How can I read custom document properties with C#?

I ant to get the custom document properties of office documents (word, excel, powerpoint) using C#. I'm building a windows desktop application. On one of the forms, I'd like to let the user select a document then click a button that will then bring back for display the custom document properties for that document. Is their a way to read these properties with C#? I am using Visual Studio 2017.
dodgerfanAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Chinmay PatelChief Technical NinjaCommented:
Hi dodgerfan,

You can use VSTO - Visual Studio Tools for Office. Refer to: https://docs.microsoft.com/en-us/visualstudio/vsto/how-to-create-and-modify-custom-document-properties

private string ReadDocumentProperty(string propertyName)
{
    Office.DocumentProperties properties;
    properties = (Office.DocumentProperties)this.CustomDocumentProperties;

    foreach (Office.DocumentProperty prop in properties)
    {
        if (prop.Name == propertyName)
        {
            return prop.Value.ToString();
        }
    }
    return null;
}

Open in new window


Regards,
Chinmay.
0
dodgerfanAuthor Commented:
I apologize for my late response. I got pulled into something else for a time. The link you provide is one fo the things I've been trying to utilize. I also found this one: https://nishantrana.me/2008/07/18/setting-built-in-and-custom-document-properties-using-c/
I used that one to get an app running that lets me update the builtin properties and add custom properties. What I have not yet figured out is how to update a custom property. Any idea how to do that? Thanks.
0
Chinmay PatelChief Technical NinjaCommented:
Refer to the link I shared earlier :) It shows both how to create and modify the properties.

Sample Code:
void TestProperties()
{
    Microsoft.Office.Core.DocumentProperties properties;
    properties = (Office.DocumentProperties)this.CustomDocumentProperties;

    if (ReadDocumentProperty("Project Name") != null)
    {
        properties["Project Name"].Delete();
    }

    properties.Add("Project Name", false,
        Microsoft.Office.Core.MsoDocProperties.msoPropertyTypeString,
        "White Papers");
}

private string ReadDocumentProperty(string propertyName)
{
    Office.DocumentProperties properties;
    properties = (Office.DocumentProperties)this.CustomDocumentProperties;

    foreach (Office.DocumentProperty prop in properties)
    {
        if (prop.Name == propertyName)
        {
            return prop.Value.ToString();
        }
    }
    return null;
}

Open in new window

0
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

dodgerfanAuthor Commented:
I've been working with that code you posted from the link. I want to update an existing Custom Property. So would it look something like this? I'm also getting an error on the this.CustomDocumentProperties. Does not contain a definition is the message I see. Not sure what's causing that. Thank again.

private string ReadDocumentProperty(string propertyName)
{
    Microsoft.Office.Core.Office.DocumentProperties properties;
    properties = (Microsoft.Office.Core.DocumentProperties)this.CustomDocumentProperties;  // error on this line

    foreach (Microsoft.Office.Core.DocumentProperty prop in properties)
    {
        if (prop.Name == "MyCustomPropertyName")
        {
            update the custom property? not sure of the line of code here
        }
    }
    return null;
}

Open in new window

0
Chinmay PatelChief Technical NinjaCommented:
Which property name you are using? Does the document contain that property? Did you try to debug your code?
0
dodgerfanAuthor Commented:
I am using a word document, and I added a custom property called ExpireDate with a  value of today's date. The document has the property and a value. I am trying to update it to a different value. The code you pointed me to plus some other sites I have found have helped. I can update Builtin properties, and I can add new custom properties. But so far no success on updating a custom property.
0
Chinmay PatelChief Technical NinjaCommented:
The technique is delete the existing one and recreate. Did you see the code I posted. It first deletes the existing one and then recreates a new one with new value.
0
dodgerfanAuthor Commented:
Well, no. I did not notice that at all. I was so focused on finding an Update I failed to notice the delete then recreate part. Sorry about that.
My code looks almost exactly like what you posted above, with just the custom property name changed to ExpireDate. I am still getting the error on this.CustomDocumentProperties; in both pieces of code. Is it related to what document I want to use it on. In this case I just wanted to hard code a file name in, like this:
object filename = @"C:\SampleWord.docx";  But at some point I want to make it a variable that changes.
0
Chinmay PatelChief Technical NinjaCommented:
Hi dodgerfan,

Please do post your entire code and let me have a look at it. Let's close this, it's been dragging for a while. :)

Regards,
Chinmay.
0
dodgerfanAuthor Commented:
I will post what I have first thing in the morning, Thanks.
0
dodgerfanAuthor Commented:
This is what I have at the moment.
using System;
using System.IO;
using System.Windows.Forms;
using Microsoft.Office.Core;
using Microsoft.Office.Interop;
using Microsoft.Office.interop.Word;
using Microsoft.Office.Tools;

private void btnUpdateCustom_Click(object sender, EventArgs e)
{
    object filename = @C:\MyFiles\SampleWord.docx";

    Microsoft.Office.Core.DocumentProperties properties;
    properties = (Microsoft.Office.Core.DocumentProperties)this.CustomDocumentProperties;

    if (ReadDocumentProperty("My Text") != null)
    {
        properties["My Text"].Delete();
    }

    properties.Add("My Text", false, Microsoft.Office.Core.MsoDocProperties.msoPropertyTypeString,
        "New Text");
}

private string ReadDocumentProperty(string propertyName)
{
    Office.DocumentProperties properties;
    properties = (Office.DocumentProperties)this.CustomDocumentProperties;

    foreach (Office.DocumentProperty prop in properties)
    {
        if (prop.Name == propertyName)
        {
            return prop.Value.ToString();
        }
    }
    return null;
}

Open in new window

On the line that has this.CustomDocumentProperties in both sections, I get an error: ViewFiles does not contain a definition for CustomDocumentPorperties and no extension method CustomDocumentProperties accepting a first argument of type ViewFiles could be found. Are you missing an assembly reference? ViewFiles is the name of the windows form. I'm also not clear on how to tell it what file to use, which I have in there.
0
Chinmay PatelChief Technical NinjaCommented:
Just one question before I get into this, have you installed VSTO add-in on your system or not?
0
dodgerfanAuthor Commented:
I thought I did, but now I can;t verify it. How can I check to make sure? And what version? I am using Visual Studio 2017 on a Windows 8 machine. I need it to work with office documents like this, correct? Is there another way? Sorry about this. And thanks again.
0
Chinmay PatelChief Technical NinjaCommented:
I am sorry I was not aware that you are using VS2017. For, VS2017 these add-ins are built-in. You don't have to install anything.

And another solid revelation, I am really sorry for wasting your time but VSTO is not the right fit here. I missed that we are not in an add-in but an independent App.

So please follow this code to list all the properties.

using Microsoft.Office.Interop;
using Microsoft.Office.Interop.Word;

Document doc = null;
            Microsoft.Office.Interop.Word.Application app = new Microsoft.Office.Interop.Word.Application();
            try
            {
                doc = app.Documents.Open(@"c:\temp\doc1.docx");
                dynamic properties = doc.CustomDocumentProperties;
                Console.WriteLine("Name\t\tValue");
                foreach (var item in properties)
                {
                    Console.WriteLine(item.Name + "\t\t" + item.Value + "\t\t");
                }
            }
            catch (Exception exception)
            {
// Handle Errors as per your requirements
            }
            finally
            {
                doc.Close();
                doc = null;
                app = null;
            }

Open in new window


So once you have this, you can use the code you were referring to earlier to add/modify the properties.

Regards,
Chinmay.
0
dodgerfanAuthor Commented:
Thanks, an no need to apologize. I'm learning, if slowly, so you are not wasting my time.
I have taken your code and put it in my form. I used a listbox instead of console.writeline. The line I changed looks like this now:
lstCustomProperties.Items.Add(item.Name + "\t\t" + item.Value + "\t\t");

Open in new window

I put it in the click event of the button. When I click it, it returns all of the custom properties, names and values. In order to change one, you're saying I can now use the code I referred to earlier? I'm still getting an error on the
properties = (Microsoft.Office.Core.DocumentProperties)this.CustomDocumentProperties;

Open in new window

sections.
0
Chinmay PatelChief Technical NinjaCommented:
0
dodgerfanAuthor Commented:
I'm trying to use that code now. This section:
object oDocCustomProps = adoc.CustomDocumentProperties;

Type typeDocCustomProps = oDocCustomProps.GetType();

// setting the ProposalSentDate custom date property with current date time

string strIndex1 = “ProposalSentDate”;

string strValue1 = DateTime.Now.ToShortDateString();

object[] oArg = { strIndex1, false, Microsoft.Office.Core.MsoDocProperties.msoPropertyTypeDate, strValue1 };

typeDocCustomProps.InvokeMember(“Add”,

BindingFlags.Default |

BindingFlags.InvokeMethod, null,

oDocCustomProps,oArg);

Open in new window

lets me add new custom properties to the document. But I have not been able to update one. As you said, I need to delete the property then put it back in with the new value. But I do not see how to remove it first. I tried "Delete" as part of invokeMember, but that threw an error.  Also, when I run the code to add a property, it opens the form and inserts it, then I have to save it then exit it. Can I do this in code? I've tried making it not visible and trying to save the document after insert, then closing word altogether. But that does not work.
0
Chinmay PatelChief Technical NinjaCommented:
Read that article carefully it has shown how to set the property.
0
dodgerfanAuthor Commented:
I got this code to work:
public void DeleteCustom()
{
	object missing = System.Reflection.Missing.Value;
 	object filename = @C:\MyFiles\SampleWord.docx";

	ApplicationClass WordApp = new ApplicationClass();
	Document adoc = WordApp.Documents.Open(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
	
object oDocCustomProps = object oDocCustomProps = adoc.CustomDocumentProperties;
	Type typeDocCustomProps = oDocCustomProps.GetType();
 
	string strIndex = "PropertyName";
	try
	{
		object oKBProp = typeDocCustomProps.InvokeMember("Item",
															 BindingFlags.Default |
															 BindingFlags.GetProperty,
															 null, oDocCustomProps,
															 new object[] { strIndex });
		Type typeKBProp = oKBProp.GetType();
		typeKBProp.InvokeMember("Delete", BindingFlags.Default | BindingFlags.InvokeMethod, null, oKBProp, null);
	}
	catch { }
	WordApp.Visible=true;
	adoc.Save();
}

Open in new window

The problem is that the word has to open. If I take out WordApp.Visible=true; it does not work. And the save does not always work properly. I would like to keep word closed and make the change (delete or add). Is that possible? Thanks again.
0
Chinmay PatelChief Technical NinjaCommented:
I do not think that word has to open. I have not tried it myself on delete part yet. I could keep word hidden - you can see in my code that I have not made it visible - and it still gave the desired results. Also you can just use app.Documents.Open(filename), no need to provide those optional attributes. Also no need to use ref keyword as well. I will give it a try tomorrow and let you know.
0
dodgerfanAuthor Commented:
I made the change you mentioned on the optional attributes. It looks like this now:
public void DeleteCustom()
{
 	object filename = @C:\MyFiles\SampleWord.docx";

	ApplicationClass WordApp = new ApplicationClass();
	Document adoc = WordApp.Documents.Open(fileName);
	
	object oDocCustomProps = object oDocCustomProps = adoc.CustomDocumentProperties;
	Type typeDocCustomProps = oDocCustomProps.GetType();
 
	string strIndex = "PropertyName";
	try
	{
		object oKBProp = typeDocCustomProps.InvokeMember("Item", BindingFlags.Default | BindingFlags.GetProperty, null, oDocCustomProps, new object[] { strIndex });
		Type typeKBProp = oKBProp.GetType();
		typeKBProp.InvokeMember("Delete", BindingFlags.Default | BindingFlags.InvokeMethod, null, oKBProp, null);
	}
	catch { }
	WordApp.Visible=true;
	adoc.Save();
}

Open in new window

If I close the app then open then open the word document and check for the just deleted custom property, it is removed. But when i close word it asks if I want to save changes. If I do not, then the custom property I just deleted goes back in. Opening the document to save changes is not what I want to do. I hope this makes sense. I can remove the WordApp.Visible = true line and I get the same behavior, so it does not appear it has to open. But I need it to save the changes. The adoc.Save() line does not appear to work.
0
Chinmay PatelChief Technical NinjaCommented:
Hi Dodgerfan,

A question - Apart from modifying the properties is there anything else that you have to do with this App?

Regards,
Chinmay.
0
dodgerfanAuthor Commented:
Chinmay,
I've been trying to get one thing at a time for the most part, but eventually a uer will open the app, and browse to select a document. I've been focused on Word right now (that's 95% of the documents), but it will eventually be Excel and Powerpoint, too. Once the document is selected, then a list will display all of the Custom Properties (you got that part earlier). I need the user to then be able to select a custom property from the list and either delete it or update it. They will also be able to add a new one. And all of this without actually opening the document. I've been working on trying to get it to work without opening Word, but so far I'm hitting the wall. Thanks again.
0
Chinmay PatelChief Technical NinjaCommented:
It is already done but using a different technique. I was wondering if you are OK to wait a bit more then I can write a complete article on this. If you are in a hurry I'll post it in couple of minutes.
0
dodgerfanAuthor Commented:
No problem, I can wait for a bit more.
0
Chinmay PatelChief Technical NinjaCommented:
And which version of Microsoft Office it should target? Are you planning to process any older versions (.Doc, .ppt, .xls) etc?
0
dodgerfanAuthor Commented:
Office 2010 is the focus right now. Moving to newer versions down the line could happen (long time out). And it is possible to have to deal with older versions, but it's not a lot.
0
dodgerfanAuthor Commented:
One other thing I thought of. If any of the processing takes a some time, show a progress bar of some type then a message when the process is complete.
0
Chinmay PatelChief Technical NinjaCommented:
:D I am not going to do that. I am going to provide you a library you call to the library it doe the processing in a split second, if you think it is taking time, you will provide a progressbar. But I do request you to hold off till you see it in action. Also, one question, do you need to process BuiltIn Document properties as well? or just custom ones?
0
dodgerfanAuthor Commented:
Thanks, sounds good. While not as important, processing the builtin properties would be useful too.
0
Chinmay PatelChief Technical NinjaCommented:
How about once you see my code, build your own. I promise you it will be easy and straightforward. That way you will learn something new as well.
0
dodgerfanAuthor Commented:
Sounds great. There's really no point if I don't learn to work this myself.
0
Chinmay PatelChief Technical NinjaCommented:
Hi dodgerfan,

Please refer to this article for the working helper class to help you modify the custom document properties.

https://www.experts-exchange.com/articles/33048/A-helper-class-to-perform-CRUD-on-Microsoft-Office-documents-Custom-Properties-without-headache.html

Please test it throughly and adapt to your exact requirements.

Regards,
Chinmay.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
dodgerfanAuthor Commented:
I was able to get the code in and take a look. I cut and pasted the helper class into a class I created in my solution. But when I try to change the namespace to the namespace I have from OblakConsulting, I get an error on here:
Properties customProperties = customProps.Properties;
if (customProperties != null)
{
CustomDocumentProperty property = GetProperty(customProperties, propertyName);

Open in new window

It does not like Properties or customProperties. When I change the namespace to OblakConsulting, it clears up. Any idea how to change the namespace without getting the errors?
0
Chinmay PatelChief Technical NinjaCommented:
Hi dodgerfan,

It should not give you an error as long as you make changes in code wherever you are referencing this class. I think you have not corrected the namespace after changing OblakConsulting. Which version of Visual Studio you are using? It generally gives hints for trivial issues like this and just by pressing CTRL + SPACE or CTRL + . you should be able to fix these errors.

Regards,
Chinmay.
0
dodgerfanAuthor Commented:
I'm not able to fix it so far. The error I get when I highlight the red line is 'Properties' is a namespace' but is being used like a type. The suggestions from intellisense have not worked. If I make the namespace OblakConstulting, then the error clears up.
0
Chinmay PatelChief Technical NinjaCommented:
1.Just double check if OpenXML SDK is installed for your project.
2. Have you included proper Using statements?
3. Share your entire project.
0
Chinmay PatelChief Technical NinjaCommented:
I mean all the code files you are using.
0
dodgerfanAuthor Commented:
It looks like OpenXML is not installed properly. Then why would it compile if the namespace is not changed? Anyway, I cannot post the entire project. It exists on a different network, with no way fro me to pull off a copy. The code I do post I retype, which is why have typos, too. I had to download the OPenXML nuget package from the Nuget site then moved had it moved over. When I try to install it, I get the error: Unable to resolve the dependency System.IO.Packaging'. Sources(s) used: 'Package Source'. Microsoft Visual Studio Offline Packages.' Sorry about this. If you have an idea about what I have wrong, please let me know. But I will try to resolve this.
0
Chinmay PatelChief Technical NinjaCommented:
Hi dodgerfan,

You don't have to post everything just the failing files. Also if OpenXML is not installed properly I don't think it will compile at all.
How did you try to install the nuget package?

Another thing that hit me, you might have conflicting namespace, could you please post the name spaces you have included? I generally remove unused namespaces.

Also change : Properties customProperties = customProps.Properties; to this:
                DocumentFormat.OpenXml.CustomProperties.Properties customProperties = customProps.Properties;

Open in new window


PS: I understand security and restrictions BUT I absolutely loathe, security by obscurity.

Regards,
Chinmay.
0
dodgerfanAuthor Commented:
Once I changed that line of code you pointed out, it all compiled and I have n o errors. OpenXML is installed properly, too. Thank you!
0
Chinmay PatelChief Technical NinjaCommented:
Finally a WIN :D... I actually lost my cool :P for a couple of minutes when I read about that namespace thing. Namespaces generally don't interfere I think there are some other Properties your code was running into. Glad this one got closed finally.
0
dodgerfanAuthor Commented:
Yes, thank you again. I will close this one out.
0
dodgerfanAuthor Commented:
Extraordinarily helpful.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Office

From novice to tech pro — start learning today.