After a lot of searching and building various partial solutions, I figured out how to do it.
First you need to define a COM class for the object you are trying to access:
[ComImport, Guid("..."), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface ISomeCOMInterface {
Then you need to instantiate the COM object. There are several ways to do this. Since I was interested in DirectSound, I used:
[DllImport("dsound.dll", EntryPoint = "DirectSoundCreate", ...] static extern void DirectSoundCreate(IntPtr GUID, [Out, MarshalAs(UnmanagedType.Interface)] out IDirectSound directSound, IntPtr pUnkOuter); IDirectSound directSound; DirectSoundCreate(IntPtr.Zero, out directSound, IntPtr.Zero);
Since I now had my own COM object, I could use the Hans suggestion Marshal.GetComInterfaceForObject() :
IntPtr comPtr = Marshal.GetComInterfaceForObject(directSound, typeof(IDirectSound)); IntPtr vTable = Marshal.ReadIntPtr(comPtr);
As an added bonus, you can iterate through the vtable functions as follows:
int start = Marshal.GetStartComSlot(typeof(IDirectSound)); int end = Marshal.GetEndComSlot(typeof(IDirectSound)); ComMemberType mType = 0; for (int i = start; i <= end; i++) { System.Reflection.MemberInfo mi = Marshal.GetMethodInfoForComSlot(typeof(IDirectSound), i, ref mType); Console.WriteLine("Method {0} at address 0x{1:X}", mi.Name, Marshal.ReadIntPtr(vTable, i * Marshal.SizeOf(typeof(IntPtr))).ToInt64()); }
Additional reads / links:
lfalin
source share