none
Writing Custom Properties to Project 2013 File RRS feed

  • Question

  • Howdy,

    Stumped with Com/Interop stuff around Project 2013 and Custom Properties.  I've tried the pre-2007 way using Type.InvokeMember to get a reference to the Custom Properties.  I've used the 2007 way using a dynamic object and no matter how I do it, I get a null reference to CustomDocumentProperties.  I can see that it is a com__object in the watch window and I KNOW there are values in the Project->Custom Fields, but its always coming back as a null.  

    • using Microsoft.Office.Interop.MSProject v15.  
    • using Microsoft.Office.Core v15.  

    Probably makes sense to say that this is a .NET 4.0 WPF application that use Interop to read and write to the file.  

    If it has to do with Office.CustomDocumentProperties and Google knows about it, I've looked at those examples and attempted those code snippets.  

    Is this a known issue with Project2013 PIA's?  Why can't I get a valid reference to CustomDocumentProperties using late binding?





    • Edited by BCSATXMatt Tuesday, August 19, 2014 9:22 PM
    Monday, August 18, 2014 8:11 PM

Answers

  • Yea Haw!!! I finally figured it out :)

    use late binding to get a reference to a dynamic object for CustomDocumentProperties:

    dynamic yo = (typeof(Microsoft.Office.Interop.MSProject.Project).InvokeMember(
        "CustomDocumentProperties",
        BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,
        null,
        project,
        null));


    Then  use dynamic object to read/write props

    to Add a name/value pair:

    yo.Add("TEST4", false, MSOffice.MsoDocProperties.msoPropertyTypeString, "444", null);


    if that name exists, it will throw an exception, the update the value

    yo["TEST4"].value = "777";


    used this to confirm that the value exists.  

    string sCFv = yo["TEST4"].value;


    Might be something to do to save the file to insure these values persist, will add info about that when I figure it out.  

    Some notes:

    Typecasting to Microsoft.Office.Core.DocumentProperties in the late binding will throw an exception, don't use it.  

    Message = "Unable to cast COM object of type 'System.__ComObject' to interface type

    'Microsoft.Office.Core.DocumentProperties'. This operation failed because the

    QueryInterface call on the COM component for the interface

    with IID '{2DF8D04D-5BFA-101B-BDE5-00AA0044DE5...





    • Marked as answer by BCSATXMatt Tuesday, August 19, 2014 3:39 PM
    • Edited by BCSATXMatt Tuesday, August 19, 2014 3:41 PM
    Tuesday, August 19, 2014 3:37 PM

All replies

  • Here are the ways in which I have tried to access CustomDocumentProperties:

    First Way:

    //http://msdn.microsoft.com/en-us/library/dhxe2d75.aspx
    // This post says that it pertains to Project2013, no workie... apparently uses VSTO, which is completely undocumented in the post... 
                        Microsoft.Office.Core.DocumentProperties properties;
                        properties = (MSOffice.DocumentProperties)this.project.CustomDocumentProperties; <- Exception thrown here... because SOProperties is NULL
                        properties.Add("Project Name", false, Microsoft.Office.Core.MsoDocProperties.msoPropertyTypeString, "White Papers");


    Exception Thrown:

    Object reference not set to an instance of an object.

    Second Way: 

    //http://stackoverflow.com/questions/12690409/set-custom-document-properties-with-word-interop
    // StackOverflow.com question 
    object SOproperties = this.project.CustomDocumentProperties;
    Type propertiesType = SOproperties.GetType(); <- Exception thrown here... because SOProperties is NULL
    
    object[] documentCodeProperty = { "JXTEST1", false, MSOffice.MsoDocProperties.msoPropertyTypeString, "1111" };
    object[] documentVersionPoperty = { "JXTEST2", false, MSOffice.MsoDocProperties.msoPropertyTypeString, "2222" };
    
    propertiesType.InvokeMember("Add", BindingFlags.InvokeMethod, null, SOproperties, documentCodeProperty);
    propertiesType.InvokeMember("Add", BindingFlags.InvokeMethod, null, SOproperties, documentVersionPoperty);


    Exception Thrown:

    Object reference not set to an instance of an object.

    Third Way:

    //http://support.microsoft.com/kb/303296
    // 2003 Automation Way
    //Add a property/value pair to the CustomDocumentProperties collection.
    object oDocCustomProps = this.project.CustomDocumentProperties;
    Type typeDocCustomProps = oDocCustomProps.GetType(); <- Exception thrown here
    
    string strIndex = "TEST3";
    string strValue = "3333";
    object[] oArgs = { strIndex, false, MSOffice.MsoDocProperties.msoPropertyTypeString, strValue };
    
    typeDocCustomProps.InvokeMember("Add", BindingFlags.Default | BindingFlags.InvokeMethod, null, oDocCustomProps, oArgs);

    Exception Thrown:

    Object reference not set to an instance of an object.

    Forth Way - Via dynamic Object

    // Using Dynamic Object                    try                    {                       

    ((dynamic)this.project.CustomDocumentProperties)["TEST4"].Value = "444";                    }                    catch (Exception ex)                    {                       

    ((dynamic)this.project.CustomDocumentProperties).Add("TEST4", false, Microsoft.Office.Core.MsoDocProperties.msoPropertyTypeString, "444", Type.Missing);                       

    ((dynamic)this.project.CustomDocumentProperties)["TEST4"].Value = "444";                    }


    Exception Thrown:

    Cannot perform runtime binding on a null reference

    BTW - Adding code to these posts is a PAIN, can't copy and paste code from Visual Studio to MSDN without having to reformat it?  zoiks... 

    In each of these attempts, I am getting null back from CustomDocumentProperties.  Is this a bug the Project PIA?


    • Edited by BCSATXMatt Tuesday, August 19, 2014 2:49 PM
    Tuesday, August 19, 2014 2:33 PM
  • Yea Haw!!! I finally figured it out :)

    use late binding to get a reference to a dynamic object for CustomDocumentProperties:

    dynamic yo = (typeof(Microsoft.Office.Interop.MSProject.Project).InvokeMember(
        "CustomDocumentProperties",
        BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,
        null,
        project,
        null));


    Then  use dynamic object to read/write props

    to Add a name/value pair:

    yo.Add("TEST4", false, MSOffice.MsoDocProperties.msoPropertyTypeString, "444", null);


    if that name exists, it will throw an exception, the update the value

    yo["TEST4"].value = "777";


    used this to confirm that the value exists.  

    string sCFv = yo["TEST4"].value;


    Might be something to do to save the file to insure these values persist, will add info about that when I figure it out.  

    Some notes:

    Typecasting to Microsoft.Office.Core.DocumentProperties in the late binding will throw an exception, don't use it.  

    Message = "Unable to cast COM object of type 'System.__ComObject' to interface type

    'Microsoft.Office.Core.DocumentProperties'. This operation failed because the

    QueryInterface call on the COM component for the interface

    with IID '{2DF8D04D-5BFA-101B-BDE5-00AA0044DE5...





    • Marked as answer by BCSATXMatt Tuesday, August 19, 2014 3:39 PM
    • Edited by BCSATXMatt Tuesday, August 19, 2014 3:41 PM
    Tuesday, August 19, 2014 3:37 PM