I've been doing quite a bit of googling trying to find the standard way to get an instance of a COM interface.
Microsoft provides an example of this in their article COM Interop Part 1: Client Tutorial:
// Create an instance of a COM coclass:
FilgraphManager graphManager = new FilgraphManager();
// See if it supports the IMediaControl COM interface.
// Note that this will throw a System.InvalidCastException if
// the cast fails. This is equivalent to QueryInterface for
// COM objects:
IMediaControl mc = (IMediaControl) graphManager;
// Now you call a method on a COM interface:
mc.Run();
However, it appears as though they are instantiating a COM object and casting it to a COM interface.
For the interface I am interested in, IDesktopWallpaper, there does not seem to be an implementing COM object to instantiate.
An example I found here defines some class that gets instantiated and then casts it to the interface the same way that the msdn example does:
[ComImport, Guid("C2CF3110-460E-4fc1-B9D0-8A1C0C9CC4BD")]
internal class IDesktopWallpaper
{
}
[Guid("B92B56A9-8B55-4E14-9A89-0199BBB6F93B"), //B92B56A9-8B55-4E14-9A89-0199BBB6F93B
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface DesktopWallpaperInterface
{
// declared members
}
I'm not understanding what the instantiated object is. It seems like an arbitrary object, it has a GuidAttribute which seems to indicate that it is an actual COM object.
Another example i found here System.Type and System.Runtime.InteropServices.Marshal to instantiate an object and then casts it to the interface:
IntPtr ptrRet;
SHGetMalloc(out ptrRet);
System.Type mallocType = System.Type.GetType("IMalloc");
Object obj = Marshal.GetTypedObjectForIUnknown(ptrRet,mallocType);
IMalloc pMalloc = (IMalloc)obj;
This method seems to be requesting a pointer to an existing instance of the interface. I can't find any methods like SHGetMalloc for IDesktopWallpaper in the Windows Shell documentation.
Question
So, long story short, what's the standard way to get an instance of a COM interface?
In the event that there is no one-size-fits-all solution, what are the standard ways that one can use to get an instance of a COM interface and in what circumstance is each of these ways most useful?
Edit
After downloading the Windows 10 SDK and referencing that against the Requirements section of the IDesktopWallpaper interface documentation, I have discovered that you can look up the MIDL from Shobjidl.h and use that in the GuidAttribute for your interface declaration and then look up the CLSID from Shobjidl.idl and use that in conjunction with Type.GetTypeFromCLSID(Guid) and Activator.CreateInstance(Type) to get an instance of an object that implements IDesktopWallpaper.
I also see now that the CLSID is what is used in the second method listed above for the GuidAttribute of the seemingly arbitrary object. It seems like this method allows you to mimic managed instantiation of the object by instantiating the class and then casting the instance to the COM interface.
However I am still interested to know if this is the best way to do this and what pros and cons may be associated with this method vs others.
You can get a pointer to a COM object reference by a variety of methods:
CoCreateInstanceCLSIDFromProgID→CoCreateInstanceIRunningObjectTable.GetObjectType.GetTypeFromCLSID→Activator.CreateInstanceType.GetTypeFromProgID→Activator.CreateInstancenew SomeType()whereSomeTypeis marked withComImportActivator.CreateInstanceandnew SomeType()eventually hitCoCreateInstance(if they do not get intercepted by various in-app-domain stuff). Calls toCoCreateInstancefor an out-of-process server will eventually hitIRunningObjectTablewith a class moniker (I think). The best option depends on what you are trying to do:ComImportComImportwill work, I would prefer to callCoCreateInstanceto pass the rightCLSCTX.ComImportthat would result in the server being run in-processIRunningObjectTableCLSIDFromProgIDorType.GetTypeFromProgIDRegardless of how we get a reference to an object, we start out with
IUnknown(objectin .Net), and then have to callIUnknown->QueryInterfaceto get a pointer to a particular interface. CallingQueryInterfacein .Net is effected by casting to an interface marked asComVisible(and usually annotated withGuidAttribute).In the example you named, you would end up with:
An example use of which would be:
Which produces the form: