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:
  1. You can only register one build per GUID (so not easy to run debug and release version simultaneously, for instance)
  2. If you want multiple versions installed, you must change the GUID
  3. You have to write the registration and unregistration functions and ensure that they are called in installers, unit tests, etc.
  4. 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.