I connect to some program via COM and receive System.__ComObject. I know several methods of it, so I can do like this:
object result = obj.GetType().InvokeMember("SomeMethod", BindingFlags.InvokeMethod, null, obj, new object[] { "Some string" });
and like this
dynamic dyn = obj;
dyn.SomeMethod("Some string");
Both methods works fine. But how can I determine inner type information of com object and enumerate through all its members?
I tried this:
[ComImport, Guid("00020400-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDispatch
{
void Reserved();
[PreserveSig]
int GetTypeInfo(uint nInfo, int lcid, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(TypeToTypeInfoMarshaler))] out System.Type typeInfo);
}
...
IDispatch disp = (IDispatch)obj;
Type t;
disp.GetTypeInfo(0, 0, out t);
But the t is null at the end. Can anyone help me?
You cannot get a Type for the COM object. That would require you creating an interop library for the COM component. Which is certainly the low pain point if the COM server has a type library, just add a reference to it or run the Tlbimp.exe utility. If it is present then the type library is usually embedded inside the DLL. When you got that, both the editor and the Object Browser get a lot smarter about the method and properties available on the COM class.
Seeing the IDispatch cast work makes it quite likely that a type library is available as well. It is pretty trivial for the COM server author to create one. Another tool you can use to peek at the type library is OleView.exe, View + Typelib.
If that doesn't work then you can indeed dig stuff out of IDispatch. Your declaration looks fishy, the 3rd argument for IDispatch::GetTypeInfo is ITypeInfo, a COM interface. No need for a custom marshaller, ITypeInfo is available in the System.Runtime.InteropServices.ComTypes namespace. You can dig the IDispatch declaration out of the framework code with Reflector.
And of course, there's no substitute for decent documentation. You should be able to get some when you got a license to use this component.
You can use: http://www.nektra.com/products/deviare-api-hook-windows/
It has a complete API provided as COM objects that can be used to get information and functions of all registered COM objects and intercept them.
I've just published a CodeProject article about how to do Reflection with IDispatch-based COM objects. The article provides a small C#
DispatchUtility
helper class that's easy to include in other projects. Internally, it uses a custom declaration of IDispatch and .NET's TypeToTypeInfoMarshaler to convert IDispatch's ITypeInfo into a rich .NET Type instance.In your example, you could call
DispatchUtility.GetType(obj, true)
to get back a .NET Type instance, which you could then call GetMembers on.FWIW,
DispatchUtility
's declaration of IDispatch.GetTypeInfo is nearly identical to yours. However, when calling GetTypeInfo, it passes in LOCALE_SYSTEM_DEFAULT (2048) rather than 0 for the lcid parameter. Perhaps GetTypeInfo returned a failure HRESULT for yourdisp.GetTypeInfo(0, 0, out t)
call. Since you declared it with[PreserveSig]
, you'd need to check its result (e.g., by callingMarshal.ThrowExceptionForHR
).Here's a version of the
DispatchUtility
class with most comments removed: