Kumar
Kumar

Reputation: 11329

Reflection on COM Interop objects

Trying to create a mapper for an Microsoft Office object to POCO's and found this

// doesn't work
// returns an empty array where o is a RCW on an office object
foreach(var pi in  o.GetType().GetProperties() ) 
    tgt.SetValue(rc, pi.GetValue(o, null));

so have to resort to this

foreach(var field in tgt.GetFields() ){
    var pv = o.InvokeMember(field.Name, System.Reflection.BindingFlags.GetProperty, null, o, null);
    i.SetValue(rc, pv);
}

which works for now but wondering why the RCW.GetProperties() doesn't work here?

Upvotes: 10

Views: 7857

Answers (3)

Jamil Geor
Jamil Geor

Reputation: 337

It is because the COM object is late bound. The runtime does not know what methods/properties will be available on a COM object until they are accessed/invoked.

Here are some good articles on the subject:

http://support.microsoft.com/default.aspx?scid=kb;en-us;Q302902

http://www.codeproject.com/Articles/10838/How-To-Get-Properties-and-Methods-in-Late-Binding

Upvotes: 4

phoog
phoog

Reputation: 43046

The other two answers as of this writing are correct, but they miss an important opportunity to explain how the late binding of a COM object looks in terms of the .NET type system. When you call GetType on the COM object, the return value is the __ComObject internal type, not the COM interface type that you normally work with when writing interop code. You can see this in the debugger, or with some code like Console.WriteLine(o.GetType().Name);.

The __ComObject type has no properties; that's why you get an empty array when you call o.GetType().GetProperties(). (At least some things in life make sense!)

If you decompile the InvokeMember method, you'll find that it has special handling for COM objects, delegating the call to an internal native method. For "regular" .NET objects, the method uses "regular" .NET reflection, retrieving the appropriate MemberInfo for the requested member, and invoking it.

You can use .NET reflection on the interface type. For example, if you know that the object is an Excel Worksheet, you can use typeof(Worksheet).GetProperties(), and use the resulting PropertyInfo instances with your object. If you don't know the type of the object at compile time, however, you need to call GetType(), as in your example code. In that case, you're stuck with using InvokeMember.

Upvotes: 21

Showtime
Showtime

Reputation: 266

You need to specify them by name using Type.InvokeMember(propertyName, BindingFlags.GetProperty, binder, target, args) because there's no way of knowing what properties a lately-bound object will have at compile-time. Instead, you need to perform that lookup at runtime, usually via string comparison.

RCW.GetProperties() would only work if you could determine the properties and their locations at compile-time.

Upvotes: 2

Related Questions