Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Reflection and COM object access


:P
On this page:

 

I ran into an interesting problem today. I posted code for a handful of very useful Reflection helper routines I use to dynamically access properties/fields and call methods on .Net objects. This has been working great in many situations where you’re dealing with dynamically created objects and objects accessed indirectly through remoting or other remote mechanism when no interfaces are available.

 

While working on my Help Builder Add in for VS.Net I ran into a fairly serious problem with this code – the issue is that code using the MemberInfo structures that are trying to read the property and method signatures dynamically are failing. For example the following code to GetProperty:

 

public const BindingFlags MemberAccess =

      BindingFlags.Public | BindingFlags.NonPublic |

      BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase;

 

 

 

public static object GetProperty(object Object,string Property)

{

      PropertyInfo pi = Object.GetType().GetProperty(Property,

                         wwUtils.MemberAccess | BindingFlags.GetProperty);

      return pi.GetValue(Object,null);

 

}

 

failed with a dynamically create EXE COM server:

 

private bool LoadHelpBuilder(ref object HelpBuilder)

{

      if (HelpBuilder == null)

      {

            Type loT = Type.GetTypeFromProgID("wwHelp.wwHelp");

            HelpBuilder =  Activator.CreateInstance(loT);

      }

 

      try

      {

            object nHtmlFormat = wwUtils.GetProperty(HelpBuilder,"nhtmlformat");

      }

      catch(Exception ex)

      {

            // *** Nope try reloading

            HelpBuilder = null;

            return LoadHelpBuilder(ref HelpBuilder);

      }

 

      return true;

}

 

In this example, GetProperty() fails with Invalid Object reference – which I presume means that the object contains no matching signature as far as Reflection is concerned.

 

However, it turns out that using InvokeMember() like this work in the GetProperty method:

 

public static object GetProperty(object Object,string Property)

{

     

      return Object.GetType().InvokeMember(Property,

       wwUtils.MemberAccess | BindingFlags.GetProperty,null,

      Object,null);

}

 

Although it works my question is what is InvokeMember doing that GetProperty() is not. I tried playing around with the various MemberInfo flags to see if that would possibly get it to work, but couldn’t. Anybody know what InvokeMembers is doing differently?

 

I seem to recall a discussion a while back that InvokeMember – being such a jack of all trades method – is slower than the direct MemberInfo access which is why I originally switched to using the MemberInfo structures and their Get and Set methods to set these values.

 

Because of this issue I decided to backfit my utility routines including the nested ones at least for now. Here’s an example of the nested version of GetPropertyEx() which allows to get properties using ‘.’ syntax (like Invoice object with a property of "Customer.Address.Street").

 

public static object GetPropertyEx(object Parent, string Property)

{

      MemberInfo Member = null;

 

      Type Type = Parent.GetType();

 

      int lnAt = Property.IndexOf(".");

      if ( lnAt < 0)

      {

            if (Property == "this" || Property == "me")

                  return Parent;

 

            // *** Get the member

            return Parent.GetType().InvokeMember(Property,

      wwUtils.MemberAccess | BindingFlags.GetProperty | BindingFlags.GetField,

null, Parent,null);

      }

 

      // *** Walk the . syntax - split into current object (Main) and parsed objects (Subs)

      string Main = Property.Substring(0,lnAt);

      string Subs = Property.Substring(lnAt+1);

 

      object Sub = Parent.GetType().InvokeMember(Main,

       wwUtils.MemberAccess | BindingFlags.GetProperty | BindingFlags.GetField,null,

       Parent,null);

                  }

 

      // *** Recurse further into the sub-properties (Subs)

      return wwUtils.GetPropertyEx(Sub,Subs);

}

 

For this situation using InvokeMember may actually be more convenient anyway as you can use GetProperty and GetField as the flag in one go.

 

For now at least if you want to be sure, InvokeMember seems like a more consistent solution.


The Voices of Reason


 

Mark Jackson
July 08, 2004

# re: Reflection and COM object access

Having dug around in the Rotor BCL and assuming .Net 1.1 still works the same:

InvokeMember has two criteria for locating the member to invoke.

1. The number of parameters in the method declaration equals the number of arguments provided to the invocation.
2. The type of each argument can be converted by the binder to the type of the parameter.

If it can't do it first time, it tries again with the parameters in a different order.

GetProperty quickly ends up in a code module called comclass.h (c++ I guess) which is the unmanaged base for all classes in the CLR where a match is performed on the abstract of the property signature.

The consequence is that GetProperty insists on getting it exactly right, and will be a marshalling nightmare.

InvokeMethod will be slower as it uses more managed code, but with properties, as long as you have the name correct it will find it and at worst you will get a type cast failure.



Rick Strahl's Web Log
June 24, 2007

# .Net Reflection and Performance - Rick Strahl's Web Log

Reflection often gets a bad rap for being slow. True it's much slower than direct access, but it's important to look at performance in the proper perspective. For many operations Reflection and 'evaluative' access to properties, fields and methods provides flexibility that wouldn't otherwise be there and the speed hit you take, especially in non-iterative situations is only minmal.

Elmue
September 02, 2008

# re: Reflection and COM object access

Hello

Thanks, your article helped me a lot.
I still have a problem.
I'm trying to set properties of a PowePoint Table Cell.

In C# this looks like:
Cell.Borders[PpBorderType.ppBorderTop].DashStyle = MsoLineDashStyle.msoLineDash;

But I want to be able to set ANY property of ANY ComObject 100% dynamically using information from a XML file.
Is there any why to find out WHICH enumeration type uses the Borders[] collection ?

It would be great if the was something like

Type GetEnumerationType(Type i_ComObject)
{
...
}

so that calling
GetEnumerationType(typeof(Borders))
would return
PpBorderType

There MUST be any way because Visual Studio complains if I put any invalid enumeration type like:

Cell.Borders[MsoTextOrientation.msoTextOrientationHorizontal]...

So this information exists in the typelib.
But how di I get it ?

Any idea ?
Thanks
Elmü

Rick Strahl
September 02, 2008

# re: Reflection and COM object access

COM collections usually have an item() or items() collection you can call. Check the type library for the format.

Otherwise for PowerPoint using the Office Tools is probably the easiest way to do this.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024