Abandoned Wig
Hi, I'm Martin.
I work on the Web Platform at Igalia.

End-run around registration-free COM

23 April 2009
With the introduction of registration-free COM, Windows now allows you to create COM objects without registering their DLLs in the registry. This means that you can include your COM DLLs with your application files and run the application without being an administrator and mucking with regsvr32. Instead you include (or embed in your executable/DLL) a manifest which specifies the location of the COM DLL relative to your application.

This "new" (it was introduced with Windows XP, I believe) approach is not flexible enough for Titanium, which doesn't know until after run-time which WebKit DLL it will be using. Writing this manifest file into the application directory and restarting or copying the DLLs into the application directory is a less than ideal solution. While the copy may work in Vista because of the wonky UAC virtualization of write permissions (that's an entirely different rant), copying an entire DLL and its dependencies at startup is expensive and defeats the purpose of DLLs.

This situation bothered me until I stumbled upon this blog post in the murky underbelly of the interblogs. It basically describes an approach using the somewhat thinly documented (perhaps intentionally) activation context API.

This Windows nightmare has a happy ending in that we were able to simply point an activation context at the WebKit DLL's manifest path. Here's what it looks like (this is originally from Gopalakrishna's blog which I linked to above):


// This is a normal CoCreateInstance -- done as if the COM DLL
// was actually registered with the system -- it will fail
IMyComponent* pObj = NULL;
HRESULT hr = CoCreateInstance(
CLSID_MyComponent,
NULL,
CLSCTX_INPROC_SERVER,
IID_IMyComponent,
(void**)&pObj);

ACTCTX actctx;
ZeroMemory(&actctx, sizeof(actctx));
actctx.cbSize = sizeof(actctx);
actctx.lpSource = "C:\Path\To\My\Manifest.manifest";
HANDLE pActCtx = CreateActCtx(&actctx);
ULONG_PTR lpCookie;

if(pActCtx != INVALID_HANDLE_VALUE)
{
if (ActivateActCtx(pActCtx, &lpCookie))
{
// CoCreateInstance should succeed now.
HRESULT hr = CoCreateInstance(
CLSID_MyComponent,
NULL,
CLSCTX_INPROC_SERVER,
IID_IMyComponent,
(void**)&pObj);
DeactivateActCtx(0, lpCookie);
}
ReleaseActCtx(pActCtx);
}