Reflection and COM object access
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 (
string
string Subs = Property.Substring(lnAt+1);
object Sub = Parent.GetType().InvokeMember(
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.
Other Posts you might also like
- Adding minimal OWIN Identity Authentication to an Existing ASP.NET MVC Application
- Resolving Paths To Server Relative Paths in .NET Code
- Map Physical Paths with an HttpContext.MapPath() Extension Method in ASP.NET
- Back to Basics: Rewriting a URL in ASP.NET Core
- Getting the Client IP Address in ASP.NET Core
The Voices of Reason
# re: Reflection and COM object access
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ü
# re: Reflection and COM object access
Otherwise for PowerPoint using the Office Tools is probably the easiest way to do this.
# re: Reflection and COM object access
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.