PInvoke and COM objects


I’ve occasionally found the need to mix COM interop and PInvoke.  For certain scenarios it’s just easier to code up a PInvoke declaration and function.  It’s perfectly legal to include COM objects in these scenarios provided the appropriate Marshal attributes are added to the signature.

The easiest way to accomplish scenario is to have the native signature only expose IUnknown instances.  On the managed side use an object declaration annotated with MarshalAs(UnmanagedType.IUnknown).  Example:

[DllImport("SomeDll.dll")]
[return: MarshalAs(UnmanagedType.IUnknown)]
public static extern object GetSomeComObject();

One item to remember though is how to managed the ref counting in this scenario.  In any case where a COM object is considered to be coming out of the PInvoke signature, the CLR will assume that it has an obligation to call IUnknown::Release() at some point in the future.  The corresponding native code must take this into account and appropriately AddRef() the object. 

This includes any scenario, as displayed above, where the COM object is the actual return value of the function [1].

 

[1] Got bit by this last week.


Comments (4)

  1. int19h says:

    Actually, it’s also an easy way to interop with your own C++ backend in an "object-oriented" fashion in a cross-platform way. Mono also supports marshalling COM objects, even on Unix – of course, Unix doesn’t have all the COM infrastructure, but g++ has vtable layout guaranteed to be COM-compatible, and, so long as you have AddRef/Release/QueryInterface in proper slots in your vtable, Mono will happily construct RCW/CCW for such objects and marshal calls.

    So, you write a shared library in C++, with plain global factory functions returning objects as entry points, and use the trick you describe to access them via P/Invoke and let COM interop kick in. Writing a makefile to have the library cross-compile with VC on Windows and g++ on Unix is trivial.

  2. jaredpar says:

    @Int19h

    I truthfully know nothing about COM interop on Mono.  In fact didn’t think it existed.  Can you point me to some documentation on it?  I’m very curious.