Thursday, June 01, 2006 5:06 PM
by
loufranco
Implementing WPF BitmapEffects: Tip 2 - Don't require COM registration
If you followed
tip #1, you now have a single assembly with your managed and unmanaged code. Part of implementing the managed side of the effect is being able to provide a COM object in your implementation of
CreateUnmanagedEffect. The normal way to do that would be to use
CoCreateInstance, but that requires that you register the object. There are several disadvantages to doing this:
- You can only register one build per GUID (so not easy to run debug and release version simultaneously, for instance)
- If you want multiple versions installed, you must change the GUID
- You have to write the registration and unregistration functions and ensure that they are called in installers, unit tests, etc.
- In Vista, you need administrator rights to write to the registry
It's a big price to pay since we don't need the major benefit of
CoCreateInstance, which is to discover the host DLL and instantiate an object by name or GUID. We know exactly which DLL we want to host the COM object (the one we're in) and we don't want to load a different one. Luckily, in this simple case, it's easy to replace the
CoCreateInstance call below:
HRESULT hr = ::CoCreateInstance(
GetGUID(),
static_cast(wrapper->DangerousGetHandle().ToPointer()),
CLSCTX_INPROC_SERVER,
IID_IUnknown,
&impl);with this:
// Get our class factory DLL
IClassFactory* classFactory = NULL;
HRESULT hr = DllGetClassObject(
GetGUID(),
IID_IClassFactory,
(LPVOID*)&classFactory);
LPVOID impl = NULL;
if (SUCCEEDED(hr)) {
// Use the class factory to create the inner effect
hr = classFactory->CreateInstance(
static_cast<LPUNKNOWN>(wrapper->DangerousGetHandle().ToPointer()),
IID_IUnknown,
&impl);
classFactory->Release();
}
DllGetClassObject is the normal COM DLL entry point that
CoCreateInstance called. It looked up the DLL name in the registry, called
LoadLibrary to load it, and then called
GetProcAddress on the DLL with the procedure name
"DllGetClassObject" -- instead, since we are in the same DLL, we can just call it directly.