Link to home
Start Free TrialLog in
Avatar of Mr_Fulano
Mr_FulanoFlag for United States of America

asked on

Type.InvokeMember Method Question

Hi, I'm using the Type.InvokeMember Method in C#, within one of my applications. I need to look inside an Object and draw out all of its property names. So, to do that I'm using the invoke method. Thus, to get a property's name, I have to give the invoke member the - specific - "namedParameter" of the property I want. - Therein lies my problem!

As an example, if I wanted to get the property value within the AuthorProperty, I would use the following code below:

 eachproperty = typeDocBuiltInProps.InvokeMember("Item", BindingFlags.Default | BindingFlags.GetProperty, null, myObject, new object[] { "Author" });  <<< Thus, I would have to provide the name of the property I wanted, (i.e. "Author").

So, my question is...what if I don't know all the specific names of a properties within my Object? What would I do?  

I would like to iterate over the array containing the property names and values to get each property name within that collection. -- How could I do that?

Hence, I want to get the property names, not the values. -- I'll work on the values later.

MSDN Source code Information:  https://msdn.microsoft.com/en-us/library/de3dhzwy%28v=vs.110%29.aspx

The syntax (per MSDN) for the InvokeMember method is shown below:

public abstract object InvokeMember(
      string name,
      BindingFlags invokeAttr,
      Binder binder,
      object target,
      object[] args,
      ParameterModifier[] modifiers,
      CultureInfo culture,
      string[] namedParameters
)

Thank you for your help!
Fulano
Avatar of Fernando Soto
Fernando Soto
Flag of United States of America image

Hi Mr_Fulano;

This is how you can get the names and property values from an object.
// An object to get the info from
Employee emp = new Employee() { ID = 12345, FirstName = "John", Lastname = "Smith", Salary = 75000.00 };
// Get its type
Type empType = emp.GetType();
// Get the public properties of the object.
PropertyInfo[] properties = empType.GetProperties();
// iterate through the array of property info
foreach (var prop in properties)
{
    // Displey the public property name and its values
    Console.WriteLine("Name : {0}  =  {1}", prop.Name, prop.GetValue(emp));
}


// Test class for above code.
public class Employee
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string Lastname { get; set; }
    public double Salary { get; set; }
}

Open in new window

Avatar of Mr_Fulano

ASKER

Hello Sr. Soto, it's been quite a while since I had the pleasure and good fortune of you helping me with one of my silly questions...I've been away for a while (not doing too much coding), but I have an issue now that I need resolving, so hence another silly question. - I hope you've been well. I recall that you helped me MANY, MANY times in the VB.NET section (around 2007-2010) while I was working on a big project. Your help was quite appreciated my friend!

OK, so on to my question. - This particular question is an offspring of another question I have here on EE.

Below is a link to my other question for reference:
https://www.experts-exchange.com/questions/28736807/Reading-an-MS-Word-2010-document-docx-and-return-all-of-the-document's-Built-In-Document-Properties.html

So, the code in that question is working (partially). I've now narrowed down the problem to the fact that when the InvokeMember method try to get the properties by calling their "name", the names that are in the array are not all correct, so it throws an exception, because my code is populating the array as shown below:

Array values = Enum.GetValues(typeof(WdBuiltInProperty));

I've determined that the property list in WdBuiltInProperty and the property list in DocumentProperties are not the same. By searching every nook and cranny of the Internet for hours and hours, I was able to find the actual property names that I should be putting into the array and they all do not match what I'm doing now. The correct list is below:

Correct Property Names: (I've tested these individually and all the ones I tested worked in my code.)
Title
Subject
Author
Keywords
Comments
Template
Last Author
Revision Number
Application Name
Last Print Date
Creation Date
Last Save Time
Total Editing Time
Number of Pages
Number of Words
Number of Characters
Security
Category
Format
Manager
Company
Number of Bytes
Number of Lines
Number of Paragraphs
Number of Slides
Number of Notes
Number of Hidden Slides
Number of Multimedia Clips

As you can see from the code output I posted in the other question, the property names do not all match up. Some do and that's why the code works - partially, but when an incorrect property name is used, it crashes = hence, my problem. -- What I was trying to do with - this - question was to find a way to iterate over the DocumentProperties method and get the property list therein, so I can put that list into my array.

I thank you for your very good explanation, but I'm not sure it will help me for what I'm trying to do.

If you'd be so kind as to look at my other question, I'd be very grateful!

I'm also happy to award you the points in this one, because I really don't think its going to get a good answer.

Thank you again and stay well,
Fulano
As a followup to my post above, I was able to "hard code" the new property name list into my code as shown below:

Replace this: >>> Array values = Enum.GetValues(typeof(WdBuiltInProperty));
with this below:
            string[] values =  {"Title","Subject","Author","Keywords","Comments","Template","Last Author", "Revision Number","Application Name","Last Print Date",
                                "Creation Date","Last Save Time","Total Editing Time","Number of Pages","Number of Words","Number of Characters","Security","Category",
                                "Format","Manager","Company","Number of Bytes","Number of Lines","Number of Paragraphs","Number of Slides","Number of Notes",
                                "Number of Hidden Slides","Number of Multimedia Clips"};
 
However, I consider that cheating and although it gives me better results (I get the actual document properties within my TestDoc.docx file), its not elegant. I was hoping to do something a bit more elegant by iterating over the DocumentProperty list, pulling out the property names therein and using those to feed back into the InvokeMember method.

I tested the code above and the results are far more accurate. Yes, it does error out a few times, but only when it can't find a property value...hence, the downside of hard coding values.

Thanks for looking this over!
Dear Mr.Fulano, I have been thinking over this problem and an elegant solution for the same.
One of the solution that comes to my mind after reading various posts and thoughts on doing this is to create office word add in using VBA (in which there is no problem getting the BuiltinDocumentproperties as key/value pair which can be iterated), and then invoking this VBA code from C# so basically this VBA code shall somehow expose some kind of interface to C# to get the list of Built in Document Properties.
This is just a thought, I am going try this out, but thought of sharing it with you.
One more question I had, in your application, even assuming that we get a elegant way to get the entire map (key/value pair) of built in document properties, to access  a particular property you would still need the key (string), right? Is there no requirement to randomly access these properties from the collection? Or is it always required that you iterate over it and go through all the properties at any point in time? Hope my questions make sense.

Thanks,
Karrtik
Hi Karrtik, I'll answer your last question first. - If I'm understanding your question, you want to know if there is a requirement for how I would access the keys and values. - No. you can access any key at any time provided you have the correct key (string).

As for the VBA code, I would be open to that --- as long as I don't have to load the VBA code into the Word document. All I can do to the Word documents is read them. I can make no changes or additions to them.
That said, you're thought is interesting...so, what you're suggesting is to have a block of VBA code, that you expose to the Word document and say - run this and give me back the results. So, the question is, where would that VBA code live? Inside the C# solution? - I've never done that...I didn't even know it could be done.

Thanks,
Fulano
One more thing Karrtik, below is a complete list of the properties that we would get - IF - we were ever able to iterate over the "DocumentProperties" collection. I hard coded them into my code to test them and was able to get absolutly accurate results for all but maybe four of the properties below. So, these are actual names that I should be using. The four that failed were properties that few if any Word document has - like "Number of Hidden Slides", etc.

My problem is that I hate to hard code anything into an application. Its not elegant, its a haphazard approach, and it is a road map to future errors... but that just my opinion.  

As noted above, it took forever to find these online. They're not published very much, but these are it! I just wish we could pull them out programmatically, rather than hard coding them into the code.

Also, these work with DOC and DOCX type documents, so they're rather standard.

Property Names:
Title
Subject
Author
Keywords
Comments
Template
Last Author
Revision Number
Application Name
Last Print Date
Creation Date
Last Save Time
Total Editing Time
Number of Pages
Number of Words
Number of Characters
Security
Category
Format
Manager
Company
Number of Bytes
Number of Lines
Number of Paragraphs
Number of Slides
Number of Notes
Number of Hidden Slides
Number of Multimedia Clips

Thanks,
Fulano
Dear Mr Fulano,

So if any key can be accessed at any time, wouldn't that mean that in code you would need to know at compile time the key name? Which would mean storing the key name in memory via some mechanism?

Let me try the VBA part, if it works I shall let you know.

Thanks,
Karrtik
Hi Karrtik...NO. You wouldn't need to know the keys at all with the approach we're trying to achieve.

There are two ways of doing this...

1). You store all the keys in an Array like I did above. Simply list them all out one-by-one. (Hard coded).
2). Iterate over the DocumentProperties colleciton and ask the collection...what properties do you have for me to call. Give me all your property keys (i.e Title, Subject, Last Author...etc.).

Option 2 is the safest way to do this, because what if a version of Words doesn't contain some sort of property that we don't know about in advance? We would call the "Last Author" property as an example, but it would be called "Last Writer" (just as an example), so that call would fail and deliver a NULL to the InvokeMember method, which would abort! -- Hence my quest to get the property "names" at runtime - from the applicant itself.

Hope that answered your question.

I can't believe we can't access the DocumentProperty collection and ask it to give us all its keys. That just doesn't seem logical for some reason.

Thanks,
Fulano
Hi Fulano;

I have been researching this question and have found some approaches to the issue with not the best of results. I am hoping that you have a sample/test Word document with fictitious data in it that have most or all the properties in it that you can post to this side so that we may test with it.

Also what version of word are you working with?
Hi Fernando, 2007 and 2010 version of MS Word works with my code. I've tested both 2007 and 2010 and they both produced good results. So, if you don't have a MS Word "doc" or "docx" file, I'll be glad to upload something generic.
Good as long as the document you create has all the properties you need to extract.
I will send you a document shortly.
Hi Fernando, yes...the file I sent you underwent a test and I was able to extract all the properties as shown below:

=======================================================================================
Description Properties:
=======================================================================================
1). The property name is (Title) its value is Generic Text Data Document

=======================================================================================
2). The property name is (Subject) its value is A Tutorial Document

=======================================================================================
3). The property name is (Author) its value is William King

=======================================================================================
4). The property name is (Keywords) its value is Keyword TAG

=======================================================================================
5). The property name is (Comments) its value is This is a test MS Word 2007 document.

=======================================================================================
6). The property name is (Template) its value is Normal.dotm

=======================================================================================
7). The property name is (Last Author) its value is Sally Smith

=======================================================================================
8). The property name is (Revision Number) its value is 2

=======================================================================================
9). The property name is (Application Name) its value is Microsoft Office Word

=======================================================================================
10). The property value for (LAST PRINT DATE) could not be extracted.
=======================================================================================
11). The property name is (Creation Date) its value is 10/8/2015 12:49:00 PM

=======================================================================================
12). The property name is (Last Save Time) its value is 10/8/2015 12:58:00 PM

=======================================================================================
13). The property name is (Total Editing Time) its value is 2

=======================================================================================
14). The property name is (Number of Pages) its value is 2

=======================================================================================
15). The property name is (Number of Words) its value is 416

=======================================================================================
16). The property name is (Number of Characters) its value is 2455

=======================================================================================
17). The property name is (Security) its value is 0

=======================================================================================
18). The property name is (Category) its value is Category Field

=======================================================================================
19). The property value for (FORMAT) could not be extracted.
=======================================================================================
20). The property name is (Manager) its value is Mr. Manager

=======================================================================================
21). The property name is (Company) its value is The Any Company Co.

=======================================================================================
22). The property name is (Number of Bytes) its value is 14519

=======================================================================================
23). The property name is (Number of Lines) its value is 47

=======================================================================================
24). The property name is (Number of Paragraphs) its value is 3

=======================================================================================
25). The property value for (NUMBER OF SLIDES) could not be extracted.
=======================================================================================
26). The property value for (NUMBER OF NOTES) could not be extracted.
=======================================================================================
27). The property value for (NUMBER OF HIDDEN SLIDES) could not be extracted.
=======================================================================================
28). The property value for (NUMBER OF MULTIMEDIA CLIPS) could not be extracted.
=======================================================================================
ASKER CERTIFIED SOLUTION
Avatar of Fernando Soto
Fernando Soto
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Fernando, this is absolutely and without a doubt brilliant...!!!  WOW,  I'm sitting here in amazement at how easy you made this!!! -- Absolutely phenomenal. -- You Sir are a master world class programmer.

No doubt you will get full points for this answer, but in addition, I have another question listed here on E/E under the heading of:

"Reading an MS Word 2010 document (docx) and return all of the document's "Built-In Document Properties."

Below is a link to that question.  It deals with the same problem, (I was just trying to ask two different approaches. PLEASE go there and simply say, "See my answer to your question called "Type.InvokeMember Method Question." -- I want to award you those 500 points as well, because you answered both questions in one.

You can't imagine how grateful I am for your help!!!  THANK YOU Sir!

https://www.experts-exchange.com/questions/28736807/Reading-an-MS-Word-2010-document-docx-and-return-all-of-the-document's-Built-In-Document-Properties.html

I do have one question about your answer...how did you come up with this? What was the approach to solving the problem? I always like to learn from every exercise I do in programming and I'd love to hear how you analyzed the problem and came up with such an elegant solution. (Simply brilliant!!!)

Best Regards,
Fulano
Fulano, I have not worked with Microsoft Word much but I had recalled that with version 2007 they had changed the format of how they saved the document to the file system. The time I did work with it, it was difficult working with the technology you needed to use it. So I Started doing some internet searches to get as much info as I can find or just enough to get the job done. I had found some Microsoft documentation  on Word and OpenXML and to see if I could find some code samples that would help. I needed to see the structure of the XML files which holds the properties of the document. Did you know that the Word document is stored in XML format. Well the Word document is a Zip file with folders and files. By changing the extension of the Word document from .docx to .zip you are able to now double click on it and see and open all the files. In my reading I learned that all the properties are kept in a folder called docProps in a couple of XML documents. The two files that will be found there are app.xml and core.xml. When I opened those files I was able to verify the schema of the XML document. Then it was just a matter of opening those XML files and extracting the information by using Linq to XML.
Hi Fernando, very good approach indeed. - Yes, I did know about the XML and the ZIP structure for Office documents, but when I unzipped a Word 2010 document, I didn't find all the properties, as I expected. I expected them to be listed - some with values and some without. So, since that was not the case, I figured there must be some hidden file or inner encoded structure that wasn't apparent to me, but that did contained the keys for the values I was seeking. So, XML was't something I considered, simply because the properties weren't there (at least not all of them). I do however especially like the fact that I don't have to open and close the documents with your code, which although I was able to figure out how to do, it wasn't graceful at all.

I have some forensic software at work and will examine a Word document much more in-depth. If I find anything of significant value, I'll message it to you.

That said, I am very grateful for your help. You went WAY above and beyond the call of duty here, so I thank you tremendously.

Best Regards,
Fulano
Excellent solution. Very elegant and very well designed. - Please see my comments in my last post to you regarding the XML and the Zip files structure. -- Thank you again.
Not a problem Fulano, glad I was able to help.