Dump Object for ComObject using dynamic?

I'm trying (with no luck) to implement "Object Dumper" for objects that I refer to in the Office Type Library.

This should be possible because the VS debug window has a “dynamic view” for System .__ ComObjects that effectively do what I want.

Any ideas?

+2
reflection c # dynamic
source share
1 answer

I also created a method to get an interface that can be used to access the object. Using:

using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; 

Your code should have an IDispatch interface:

 [Guid("00020400-0000-0000-C000-000000000046"), ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IDispatch { [PreserveSig] int GetTypeInfoCount(out int pctinfo); [PreserveSig] int GetTypeInfo( [MarshalAs(UnmanagedType.U4)] int iTInfo, [MarshalAs(UnmanagedType.U4)] int lcid, out System.Runtime.InteropServices.ComTypes.ITypeInfo ppTInfo); [PreserveSig] int GetIDsOfNames( ref Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgszNames, int cNames, int lcid, [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId); [PreserveSig] int Invoke( int dispIdMember, ref Guid riid, uint lcid, ushort wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, out object pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] puArgErr); } 

My method throws the COM object into IDispatch, gets the unmanaged type information, gets the object GUID from the non-public Marshall GetTypeInfoGuid method, and then searches for it in the current AppDomain assemblies.

 internal static Func<ITypeInfo,Guid> GetTypeInfoGuid = (Func<ITypeInfo,Guid>)Delegate.CreateDelegate(typeof(Func<ITypeInfo,Guid>), typeof(Marshal).GetMethod("GetTypeInfoGuid", BindingFlags.NonPublic | BindingFlags.Static, null, new[]{typeof(ITypeInfo)}, null), true); public static Type GetCOMObjectType(object comobject) { if(!Marshal.IsComObject(comobject)) { throw new ArgumentException("This is not COM object.", "comobject"); } IDispatch dispatch = (IDispatch)comobject; ITypeInfo info; dispatch.GetTypeInfo(0,0, out info); Guid guid = GetTypeInfoGuid(info); foreach(Assembly a in AppDomain.CurrentDomain.GetAssemblies()) { foreach(Type t in a.GetTypes()) { if(t.IsInterface && t.IsImport && t.GUID == guid) { return t; } } } return Type.GetTypeFromCLSID(guid); } 

If the corresponding type is not found, the method will return the type System .__ ComObject. However, you can get the value of the GUID property from it, so at least you get the GUID. Using:

 object controls = axWindowsMediaPlayer1.cdromCollection; Type t = GetCOMObjectType(controls); Console.WriteLine(t); Console.WriteLine(t.GUID); /*Output: WMPLib.IWMPCdromCollection ee4c8fe2-34b2-11d3-a3bf-006097c9b344 */ 

Hope this helps. Good luck. ☺

Edit: Found a simpler but slower method:

 object controls = axWindowsMediaPlayer1.cdromCollection; IDispatch dispatch = (IDispatch)controls; ITypeInfo info; dispatch.GetTypeInfo(0,0, out info); Type t = Marshal.GetTypeForITypeInfo(Marshal.GetIUnknownForObject(info)); Console.WriteLine(t); 
+3
source share

All Articles