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:
CoCreateInstance
CLSIDFromProgID
→CoCreateInstance
IRunningObjectTable.GetObject
Type.GetTypeFromCLSID
→Activator.CreateInstance
Type.GetTypeFromProgID
→Activator.CreateInstance
new SomeType()
whereSomeType
is marked withComImport
Activator.CreateInstance
andnew SomeType()
eventually hitCoCreateInstance
(if they do not get intercepted by various in-app-domain stuff). Calls toCoCreateInstance
for an out-of-process server will eventually hitIRunningObjectTable
with a class moniker (I think). The best option depends on what you are trying to do:ComImport
ComImport
will work, I would prefer to callCoCreateInstance
to pass the rightCLSCTX
.ComImport
that would result in the server being run in-processIRunningObjectTable
CLSIDFromProgID
orType.GetTypeFromProgID
Regardless of how we get a reference to an object, we start out with
IUnknown
(object
in .Net), and then have to callIUnknown->QueryInterface
to get a pointer to a particular interface. CallingQueryInterface
in .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: