6

I want to set some custom document properties of a word document I'm creating in my C# code. To do this, I followed this MSDN article and came up with this code:

using Word = Microsoft.Office.Interop.Word; // Version 12.0.0.0
word = new Word.Application();
word.Visible = false;
Word._Document doc = word.Documents.Add(ref missing, ref missing, ref missing, ref missing);
logger.Info("Setting document properties");
Core.DocumentProperties properties = (Core.DocumentProperties)doc.BuiltInDocumentProperties;
properties["Codice_documento"].Value = args[3];
properties["Versione_documento"].Value = args[4];

Unfortunately, I get this error whenever it reaches the code:

HRESULT: 0x80004002 (E_NOINTERFACE)

Why is that? I used the interfaces exactly as described my MSDN, why doesn't it work?

I'm using Interop for office 2010 and .net 3.5

Berkay Turancı
  • 3,373
  • 4
  • 32
  • 45
F.P
  • 17,421
  • 34
  • 123
  • 189
  • when it reaches *which* code? what is `args` it is not mentioned before line 3? – Zdeslav Vojkovic Oct 02 '12 at 12:53
  • The line where I cast the properties. args are string arguments passed to the program. They are definitely filled with a value, I do the check beforehand. – F.P Oct 02 '12 at 13:39
  • Filled with which value? What are the types of `args[3]` and `args[4]`? It seems that they don't implement the interface which is expected by target `DocumentProperty` – Zdeslav Vojkovic Oct 02 '12 at 13:45
  • 1
    The problem is not the arguments. The error is thrown in line 2. – F.P Oct 02 '12 at 13:48
  • But when you update the property and it is referenced in the Word document text, it does not automatically update right? I had to click it and press F9 to update it. Anyone knows of a way to do that programmatically? – Lzh Oct 30 '14 at 09:16

4 Answers4

5

You need to use CustomDocumentProperties, not BuiltInDocumentProperties. See MSDN reference on using Custom Document Properties in Word (and MSDN video here). You also need to check if the property exists and create it before trying to assign its value.

Core.DocumentProperties properties = (Core.DocumentProperties)this.Application.ActiveDocument.CustomDocumentProperties;
if (properties.Cast<DocumentProperty>().Where(c => c.Name == "DocumentID").Count() == 0)
  properties.Add("DocumentID", false, MsoDocProperties.msoPropertyTypeString, Guid.NewGuid().ToString());
var docID = properties["DocumentID"].Value.ToString();
SliverNinja - MSFT
  • 31,051
  • 11
  • 110
  • 173
  • I can't use `this.Application.ActiveDocument`, because I create the document on the fly. I have an instance of `_Document`, but even when using `CustomDocumentProperties`, the error is thrown. The application is not an addin of any sort, it's a standalone application using the interop libraries to automate word processing. – F.P Oct 02 '12 at 13:35
  • I've verified the above code works fine - you should probably share your sample code for creating the `_Document` instance. – SliverNinja - MSFT Oct 02 '12 at 13:48
  • I updated my question, although I doubt this will help. I just create an empty document. – F.P Oct 02 '12 at 13:58
  • Out of curiosity - have you recently installed or uninstalled any Office products (*12, 14, 15*)? You may try an Office install repair. Also see if the simple example above works for you (*using `this.Application`*) – SliverNinja - MSFT Oct 02 '12 at 14:43
  • I just created an empty AddIn-Project and ran your code. It works fine, the property is created and filled with a GUID. – F.P Oct 04 '12 at 11:51
  • Update: The main difference seems to be that `ActiveDocument` is of interface `Document`, whereas in my example, I have a document of the `_Document` interface – F.P Oct 04 '12 at 12:11
5

After asking the question in the MSDN forums, the answer was brought up. The problem is, that the way I tried was specific to VSTO. Due to my unknowing, I mixed up VSTO, Interop and other definitions, thus tagging this question wrong.

It now works using the following code:

logger.Info("Setting document properties");
object properties = doc.CustomDocumentProperties;
Type propertiesType = properties.GetType();

object[] documentCodeProperty = { "Codice_documento", false, Core.MsoDocProperties.msoPropertyTypeString, args[3] };
object[] documentVersionPoperty = { "Versione_documento", false, Core.MsoDocProperties.msoPropertyTypeString, args[4] };

propertiesType.InvokeMember("Add", BindingFlags.InvokeMethod, null, properties, documentCodeProperty);
propertiesType.InvokeMember("Add", BindingFlags.InvokeMethod, null, properties, documentVersionPoperty);
F.P
  • 17,421
  • 34
  • 123
  • 189
0

SliverNinja's answer above is correct. I forgot you had to .Add to the collection until I ported some old VB code. I had to set and read a bunch of doc properties, so here are a couple extension methods to read/write from either the BuiltInDocumentProperties or the CustomDocumentProperties in Word. This is NetOffice code, but you can convert it to VSTO by just changing the using statements.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NetOffice.OfficeApi;
using NetOffice.OfficeApi.Enums;
using NetOffice.WordApi;

namespace PalabraAddin {
    public static class ExtDocument {

        public static T GetCustomProperty<T>(this Document doc, string name, T defaultValue) {
            return doc.GetProperty(doc.CustomDocumentProperties, name, defaultValue);
        }

        public static T GetBuiltInProperty<T>(this Document doc, string name, T defaultValue) {
            return doc.GetProperty(doc.BuiltInDocumentProperties, name, defaultValue);
        }

        public static T SetCustomProperty<T>(this Document doc, string name, T value) {
            return doc.SetProperty(doc.CustomDocumentProperties, name, value);
        }

        public static T SetBuiltInProperty<T>(this Document doc, string name, T value) {
            return doc.SetProperty(doc.BuiltInDocumentProperties, name, value);
        }

        public static T GetProperty<T>(this Document doc, object collection, string name, T defaultValue) {
            var properties = (DocumentProperties) collection;
            foreach (var prop in properties.Where(prop => prop.Name == name))
                return (T) prop.Value;
            return defaultValue;
        }

        public static T SetProperty<T>(this Document doc, object collection, string name, T value) {
            var properties = (DocumentProperties) collection;
            foreach (var prop in properties.Where(prop => prop.Name == name)) {
                if (!((T) prop.Value).Equals(value))
                    prop.Value = value;
                return value;
            }

            MsoDocProperties propType;
            if (value is Boolean) 
                propType = MsoDocProperties.msoPropertyTypeBoolean;
            else if (value is DateTime)
                propType = MsoDocProperties.msoPropertyTypeDate;
            else if (value is double || value is Single)
                propType = MsoDocProperties.msoPropertyTypeFloat;
            else if (value is int)
                propType = MsoDocProperties.msoPropertyTypeNumber;
            else 
                propType = MsoDocProperties.msoPropertyTypeString;

            properties.Add(name, false, propType, value);
            return value;
        }
    }
}
Wade Hatler
  • 1,785
  • 20
  • 18
0

I solved it using this simple code:

foreach (var property in _WordDoc.CustomDocumentProperties)
{
   if(property.Name == target)
      property.Value = value;
}
Acubo
  • 120
  • 6