SxS API – Installing Win32 native side by side assemblies without MSI

The SxS loader, also called “Fusion”, which I mentioned previously, is a new feature available starting with Windows XP that allows deploying multiple versions of the same DLL to a global store, “the next generation of system32”, where multiple versions of the DLL live side by side. Client applications use XML manifests to create activation contexts that specify which version is desired, avoiding a binary compatibility nightmare. You can read more about SxS here. This global store is known as “winsxs” and has a new name, “Component Servicing Infrastructure”, in Vista. For you managed developers, you can consider it as some sort of a native version of the GAC.

Until recently, the only documented way to install Win32 native SxS assemblies to the global store was by using MSI, the Windows Installer. The SxS DLL is described in a table in the MSI database and during package installation it is copied to the winsxs store. This may be a decent solution for those who already use MSI to deploy their projects, but it can be overkill for others. Even in larger projects, it is obvious that not everyone likes using MSI.

Microsoft recognized the need of .NET developers to deploy managed assemblies to the GAC without MSI and documented their previously undocumented GAC API, residing in fusion.dll, in blog entries, a knowledge base article and finally right in MSDN. This API is based around Fusion.dll’s IAssemblyCache interface.

It’s no surprise that the API for installing managed assemblies was documented first. Native SxS does not seem to be widely used (although its internal use by Microsoft has increased significantly – compare the Vista winsxs directory to XP’s and see what I mean) – which is unfortunate, since it can solve a lot of problems.

Recently, however, an API for managing native SxS DLLs in the winsxs store was documented. This API is basically identical to the GAC API in fusion.dll, but instead resides in sxs.dll, an OS component starting with Windows XP. The API is now documented in MSDN here.

While a welcome development, the documentation of this API leaves something to be desired. First of all, the API is documented for Windows Vista and Windows Server 2008, while looking at the export table of Windows XP’s sxs.dll illustrates that is definitely present in Windows XP in one form or another. When I asked about this here, the reason for this turned out to be the fact this API isn’t tested on XP and Windows Server 2003 (Hmm……)

Second of all, the SxS store’s reference counting isn’t described too much. I’d like to know the subtle meanings of the various schemes in FUSION_INSTALL_REFERENCE. I suppose up to this point, with MSI being the only name in town, FUSION_REFCOUNT_MSI_GUID was the only one actually being used.

Still, despite the downsides, the SxS API finally provides an alternative for those who would rather avoid MSI and still enjoy the benefits of isolation. I hope to see wrappers for the API becoming available online and coming to good use.

With this API, installing a SxS DLL becomes as simple as calling IAssemblyCache::InstallAssembly. Examples can be found online of using the nearly identical GAC API on managed assemblies – these can easily be used as the basis for a native SxS assembly installation routine.

Of course, the Visual C++ 2005 CRT and other runtime redistributables are native side by side assemblies themselves. MSVCR80.DLL is installed to the winsxs store and not to system32 like previous versions of the CRT. So I was hoping the availability of a documented API for SxS DLL installation would provide another supported deployment facility for the Visual C++ 2005 redistributables, in addition to the Windows Installer merge modules which of course are only suitable for an MSI installation. The second alternative of deploying all the redistributables, even those that you don’t need for your project, in the form of vcredist.exe, is even worse.

Unfortunately, when I asked a Program Manager in the Visual C++ team whether the availability of the SxS API means it is now supported as a way to deploy the runtimes, I got a negative response. The Visual C++ Team, for their reasons, prefer to keep restricting developers to the existing deployment methods, with all their problems, preventing seamless integration of runtime deployment into custom installers.

This stance is yet another motivation to use the OS CRT instead of the Visual C++ CRT when deploying projects. See my previous post describing this approach. If you like it, let Microsoft know you’d like to see this supported better.

Advertisements

The Windows SDK Team is asking for feedback

The team responsible for shipping the Windows SDK at Microsoft is asking for feedback about what developers would like to see in future releases. This is mentioned here and here. If, like me, you would like to see support for using MSVCRT.DLL with the new Visual C++ compilers included as an official feature in the Windows SDK, you should let them know. With the .NET Framework SDK now a part of the Windows SDK, I hope what’s formerly a part of the Platform SDK, for native developers, is not left behind.

Dynamically linking with MSVCRT.DLL using Visual C++ 2005

Despite rapidly approaching its tenth anniversary, Visual C++ 6.0 is still in widespread use for new software development. That much is evident from reviewing the build environments for a variety of open source projects. Some claim its continued popularity stems from old-timers preferring the older, lighter IDE over the newer ones, which also appeared to be more oriented towards the needs of the managed code developer. However, the issue of the C++ runtime and its deployment should not be overlooked.

Visual C++ 6.0 produces C++ executables and DLLs that statically link to the CRT by default in a new project. However, it has become commonplace to dynamically link against its CRT and create a dependency on MSVCRT.DLL. In 2007, this is no big deal, seeing as this runtime DLL has been deployed with every Windows release since at least Windows 98 Second Edition, and even Windows 95 installations with Internet Explorer 4 and later would have it. Software developers happily turned to dynamic linking and over time found themselves not being concerned about CRT deployment – it was already there. This provides for compact and lean binaries with no deployment woes in heterogeneous environments.

With the release of Visual C++ .NET in 2002, a new CRT DLL was born. MSVCR70.DLL was the new name in town, but this time it was nowhere to be seen – developers had to deploy this hefty DLL with their project or go a step backwards to static linking with all its problems. Microsoft cited versioning issues and compatibility (“DLL hell”, etc.) for this change in name, supposedly justifying why the bug fixes and new runtime routines weren’t incorporated into a newer revision of MSVCRT.DLL with the 7.0 compiler release.

The new CRT DLL become just the first one in a series. Visual C++ 2003’s release introduced MSVCR71.DLL and Visual C++ 2005’s release introduced MSVCR80.DLL. 2003’s runtime can only be expected to be present in Windows XP installations while the latter runtime only recently made its way into a shipping OS with the introduction of Windows Vista.

With the availability of Visual C++ .NET, Microsoft recommended and condoned deploying its CRT as a private DLL, simply a file in the directory of installed program. For developers, this only meant an unfortunate ballooning in installer size, but no additional complication. Indeed, various installations and upgrades to the system should leave the dependency intact and the application would always run with the tested DLL version, making the whole thing seemingly more ideal than being dependent on the system’s MSVCRT.DLL which could conceivably change behind your back at any moment.

However, this stance of private deployment is no longer suitable or advisable in our modern world. As we have learned all too well since 2002 and especially from Microsoft’s embarrassing tool to patch a buggy gdiplus.dll across the system, deploying high profile DLLs privately does not allow for central servicing. In such scenarios, the enterprise administrator cannot ensure patched code has been deployed to all dependent applications, even when such code is known to be binary compatible with the original DLL.

It wouldn’t be a shock if a security patch for the CRT were to be posted some day, so deploying the CRT privately is out of the question for the responsible developer.

This leaves us with performing a global installation of the CRT with one of Microsoft’s supported methods. Previously, this was just deploying the DLLs to system32 if they weren’t there, checking if there’s a newer version, etc. – not a big deal, to be sure – although this alone was enough for size and simplicity minded developers to steer clear of the new compiler and the CRT deployment mess that came with it.

Visual C++ 2005’s new CRT further complicates the deployment issues developers are faced with because it makes use of Windows XP’s new side-by-side assembly infrastructure, sometimes referred to as SxS or WinSxS. Readers unfamiliar with it can catch up here.

The most famous SxS assembly is probably version 6 of the Common Controls library, which can only be used by utilizing the SxS infrastructure and is required for enabling “Visual Styles” on common dialog buttons and other controls in Windows XP and later.

In SxS, the dependent application specifies a dependency on a specific version of a DLL using an XML manifest, which can be embedded as a resource in the binary inline, or be a separate file deployed with the binary. Assemblies that wish to become available to such isolation-aware applications can either be deployed privately to the application’s directory (I mentioned why this is a bad idea above, but apparently SxS can mitigate this scenario with its policy and deploy a security update to dependents even in this scenario) or be installed to the side-by-side assembly store, WinSxS.

WinSxS is a subdirectory of the Windows directory. Its function for native side-by-side assemblies is comparable to that of the Global Assembly Cache (GAC) of the .NET world.

So what’s the big deal? New installers would just xcopy the new CRT DLL, MSVCR80.DLL, to WinSxS and get it over with, right? Wrong. It’s more complicated than that.

Microsoft’s official position on this matter has been that there is one supported way to deploy assemblies to the WinSxS store: An .MSI file installed by the Windows Installer. However, as the popularity of this alternative installer shows, not everyone can tolerate its complexity, especially developers of the smaller variety of software.

Microsoft provides another alternative in the form of the “VCRedist” EXE which deploys the CRT and other redistributables to the SxS store that can be invoked by a custom installer. But it can only be redistributed “as-is.”

It’s unreasonable that every small project depending on the new CRT deploy a megabyte or so of DLLs and be sucked into a MSI-based deployment mode. There has to be a better way.

A question arises, what does Microsoft do? They deploy their applications to a variety of Windows environments. A look at Windbg’s dependencies showed it’s using MSVCRT.DLL rather than one of the newer CRTs. Microsoft’s new Network Monitor 3.1 also uses MSVCRT.DLL. Windows Desktop Search is also using the old, trusty CRT.

How can all these new applications be using the vintage CRT? They’re not still using the antique, unsupported Visual C++ 6.0, are they? Well, no. The answer is more complicated and can be found in the Windows Driver Kit (WDK).

What does the Windows Driver Kit, previously known as the Driver Development Kit (DDK), has to do with anything? Isn’t that what all those crazy kernel-mode developers use?

Be that as it may, the Windows Driver Kit also includes a build environment based on the Visual C++ 2005 compiler. The version there seems feature-aligned with 2005’s SP1 release. As driver developers are acutely aware, the WDK’s vintage build system is based upon SOURCES files describing projects and big common Makefile doing all the heavy lifting.

The samples included with Windbg’s SDK (debugger extension DLLs, etc.) also use this build system. Although primarily used for drivers, it can build user space projects as well. Examining the results of the build reveals an interesting fact: generated binaries are compiled with a Visual C++ 2005 SP1 style compiler, yet depend on the MSVCRT.DLL of yore.

We’ll get back to how the WDK build environment (and presumably, other, internal Microsoft build environments for products like Windows Desktop Search) pulls this stunt later. But let us first consider how one would go about doing this independently.

The CRT is just a bunch of runtime functions like strlen and printf and some boilerplate startup code that is statically linked even when using the CRT dynamically due to its very nature (i.e., DllMainCRTStartup which functions as the real DLL entry point, calls constructors for global objects and then calls the user-supplied DllMain). If we get the compiler to use a MSVCRT.LIB import library for the older Visual C++ 6.0 CRT instead of the newer import libraries that bring in the new CRT DLLs and their deployment woes, we’d be fine, right? All we have to do is pass /NODEFAULTLIB and link with an older library and we’re home free, right? Wrong. The naive attempting this simple procedure may get away with simple “Hello, World”-class applications linking and running, but when features such as Structured Exception Handling in C or C++ exceptions are introduced, the whole thing becomes real messy real fast with a bunch of unresolved external symbol errors from the linker.

The reason for this mess is that the CRT serves two distinct functions. One is containing various standard library routines like strlen and printf. The prototypes for these standard functions haven’t changed for years and binary compatibility between different CRTs is a given when it comes to those. The other function of the runtime is to support the language environment, facilitating features such as C++ exception handling with functions such as _CxxFrameHandler3. This part of the CRT is both undocumented and unavailable – it is missing from the CRT sources that have been bundled with Visual C++ releases. It is also the part that appears to have changed significantly between Visual C++ 6.0 and Visual C++ 2005, resulting in the aforementioned incompatibility.

Alan Klietz was the first, to my knowledge, to make a solution to this problem public. It is described in this posting and this one to one of the Microsoft newsgroups. Basically, the solution is the “missing link” (no pun intended) in the linker argument list for getting the old Visual C++ 6.0 runtime import library to satisfy the Visual C++ 2005 compiler. A thunk is added from the new exception handling frame handler to the older one found in the older CRT and other miscellaneous issues are addressed. (new stack allocation functions are required, the run-time checks debugging feature is usually dependent on the CRT, etc.)

This is a nice solution and was available before the WDK and its solution shipped, but unfortunately it requires a post-build step. The exception structures in the compiled binary’s “.rdata” section need to be patched from the new exception magic generated by the new compiler (0x19930522) to the old magic suitable for the 6.0 runtime (0x19930520). The resulting patched binary seems to work, but who knows what’s the meaning of this change and how subtle exception handling semantics are affected by it.

So how does the WDK pull it off? One would presume a solution in use by Microsoft wouldn’t involve a dirty trick like patching the exception handling to use the older infrastructure. Indeed, the WDK’s solution is based on another approach.

Examining the WDK’s makefile.new file reveals the trick – along with the Visual C++ 2005-based compiler, it bundles several object files – msvcrt_win2000.obj, msvcrt_winxp.obj and msvcrt_win2003.obj. There is also mention of msvcrt_winnt4.obj, but this one is nowhere to be found – not a surprise considering the WDK has no build environment for the antique NT 4.0 anymore. One of these objects files, depending on the exact build settings, is passed to the linker along with an import library for MSVCRT.DLL – and viola – the result is a binary produced with a new compiler using the ubiquitous runtime.

So what exactly is going on here? Well, the import library for MSVCRT.DLL included with the WDK is actually not one for the original MSVCRT.DLL included with Visual C++ 6.0, but rather for the latest and greatest version bundled with none other than Windows Vista. That’s right folks – while Microsoft has been preaching to the developer community to move on to the new CRTs, it has been updating the original CRT and compiling OS components and compiling their own products against it. Indeed, Vista’s MSVCRT.DLL includes the new exception handling infrastructure of Visual C++ 2005, previously only found in MSVCR80.DLL.

Unfortunately, naive use of the WDK compiler with the Vista MSVCRT import library results in binaries that attempt to import symbols only found in the Vista version of the DLL and fail miserably on older versions of Windows. This is exactly the kind of versioning mess Microsoft sought to avoid when introducing the new CRT DLL names in the first place.

The various object files included with the WDK are the solution to this issue. They included the difference between the MSVCRT.DLL shipped with a specific OS release and Vista’s. Thus, msvcrt_win2000.obj is the largest, followed by msvcrt_winxp.obj and lastly msvcrt_win2003.obj. Presumably msvcrt_winnt4.obj, available only internally in Microsoft, is even larger. Examining the object files reveals their contents: basically the exception handling code and things like implementations of new secure CRT functions (those with the _s suffix introduced in Visual C++ 2005) required by the modern CRT startup code.

So this seems pretty nice, right? We link with the import library from the WDK and the object file we require for our OS compatibility needs, potentially resulting in a Visual C++ 2005 compiled project that can work with no CRT deployment, at least from Windows 2000 onwards. We use the new exception handling code so we avoid potentially dangerous exception patching we do not understand. Not too shabby.

Unfortunately as with any not-so-documented solution there are quirks. Examination of the LIB directory of the WDK reveals the presence of an import library for the Debug CRT, the infamous MSVCRTD.DLL that provides us with the Debug CRT Heap and other productivity boosting features that have saved innumerable man hours and dollars. So we’d expect to be perfectly able to adapt the WDK build environment for the debug builds of our projects, right?

Wrong. Windows Vista does not include a debug version of its CRT. The latest public release of MSVCRTD.DLL from Microsoft is the one in Visual Studio 6’s Service Pack 6, apparently. Try using that one with a binary linked against the debug CRT import library from the WDK and watch the interesting results – a scary debug assertion failure in initialization time due to a mismatch in the type of a CRT heap block. The new CRT startup code we pull from the WDK’s import library is mismatched with the heap internals of the Visual C++ 6.0 debug CRT DLL. The new debug CRT DLL is nowhere to be found and presumably only exists internally at Microsoft. The public bundling of the debug CRT import library with the WDK is surely an oversight.

Thus developers wishing to produce compact binaries with elegant deployment are expected to give up the beloved debugging features of the debug CRT or develop and test their applications against the different Visual C++ 2005 CRT and only switch to the OS CRT when approaching deployment, risking surprises and unexpected bugs. Every developer should evaluate his priorities and determine whether it’s all worth it.

Unfortunately, since it’s the “small fish” of the developer community that consider a feature such as being to use the OS CRT to simplify heterogeneous deployment important, they have little leverage over Microsoft to convince them to make this solution more readily available or complete it by releasing a debug version of the OS CRT. The Visual C++ team will not add support for the OS CRT directly in the product (my feedback item requesting a feature to that effect was closed and tagged “won’t fix”, “by design”, etc.) while Microsoft’s in-house development teams get access to this functionality in the form of WDK-style build environments, presumably.

Those who for some reason prefer the Visual C++ 2003 compiler should be aware that the Windows Server 2003 DDK includes the Visual C++ 2003 compiler and a build environment for it that also generates binaries depending on the OS CRT, so this is all applicable to that compiler as well. However, there are less implementation differences in areas such as exception handling between Visual C++ 6.0 and Visual C++ 2003, so a hand-rolled solution is easier to come up with. Headers and import libraries from a Platform SDK release (not the newer Windows SDK) should be suitable to get such a build environment in place.

A note on x64. The Platform SDK has been featuring x64 build environments since well before the Visual C++ product finally integrated support for that platform. Presumably intending to make migration of older projects based on Visual C++ 6.0 seemless and the fact the Platform SDK release is aligned with the OS, those x64 build environments also used the OS CRT. Indeed, in x64, MSVCRT.DLL was the name of the game until Visual C++ 2005’s release resulted in the introduction of its CRT to that platform, as well. So, ironically, in the modern x64 platform the profile of the supposedly deprecated CRT is higher than on x86.

I’m hoping this solution becomes more widespread and we can see open source and other projects finally retiring the Visual C++ 6.0 of yesteryear and putting it to the rest. With the issue of runtime deployment out of the way, the advantages of the new compiler far outweigh its disadvantages.

Although I’ve been concentrating on the issue of the core CRT, all of this is applicable to other core assets in the platform such as ATL and MFC. The supposedly driver-oriented WDK has versions of ATL 3.0 and MFC 4.2 suitable for use with the modern Visual C++ 2005 compiler. Using the OS versions of these libraries in addition to the CRT has significant deployment advantages – all those extra bytes sure add up fast.

Just say no to bloatware.

How about some Windbg love?

Those of us who practice production debugging are certainly familiar with Microsoft’s Windbg. As John Robbins eloquently describes in this Bugslayer column from MSDN Magazine: “WinDBG is a hardcore debugger that handles everything from kernel mode to user-mode debugging all in a circa-1990 user interface.”

Various hosting environments are basically unsuitable for debugging with Visual Studio’s otherwise respectable Debugger. In its 2003 and 2005 releases, it has been catching up to Windbg (it can now even load dbgeng extensions like the CLR’s almighty Son of Strike) but still has its limitations and still lacks a powerful and flexible command-line interface.

With Windbg being the exclusive tool for a variety of production debugging scenarios, you’d expect Microsoft to treat it as an upper class product. Instead, its users have to put up with embarrassing bugs like this. Sure, the latest release, 6.7.5.1, is labeled as a “beta”, not minding that the previous 6.7.5.0 release was not marked as such, but is now gone off of the face of the Web. You’d figure the posted What’s New notes would at least make the decision on whether upgrading and risking new bugs like the one mentioned above would be worth it, but these contain all the changes included in 6.7.5.0 and don’t seem to document the contents of the latest beta revision. Add that to basic commands that have been a part of the debugger for ages and are referred to in any .NET debugging with Windbg tutorial (“.loadby”) still not being mentioned or fully documented in the debugger help file, debugger.chm. This help file also serves as the primary documentation for Microsoft’s debugging engine, dbgeng.dll. It’s sufficiently incomplete and problematic that the Eclipse IDE’s C++ development environment, attempting to support targeting the Windows SDK (and its bundled Visual C++ 2005-based compiler) and using DbgEng as a debugging engine, had to abandon the effort (though one can hardly blame Microsoft for under-documenting its debugging engine to prevent a competing IDE from utilizing it…).

Add to that the fact that the presumably tiny Windbg team doesn’t seem to have any presence (blogging or otherwise) on the Web. There’s no rough time table for new releases and no modern mechanism for feedback. Is this how Microsoft sees its flagship production debugging product? This wouldn’t be so bad if the Visual Studio Debugger had been brought up to par with Windbg. I hope that given Microsoft’s announced renewed commitment to the native development experience beyond Visual Studio 2008, we’ll get to see some advances in this area.

But even if we remain optimistic about production user-space debugging in future Visual C++ releases, those of us who are debugging kernel-mode code with Virtual Machines and serial cables are still left behind. Perhaps we can hope for the future Windows Driver Kit to finally integrate with Visual Studio and retire the antiquated BUILD utility and even dream of a Visual Studio Kernel Debugger… After all, it supports Windows CE Embedded Windows as a whole platform, supporting the whole Windows platform doesn’t seem like too much to ask.

Registration-free COM

As anyone who consumes COM objects or develops them is acutely aware, they require registration. Indeed, the original role of the “Registry”, in 16-bit Windows prior to the release of Windows 95, was to contain this COM registration information.

Typically, the in-process server DLL or the out-of-process EXE associated with the implementation of an object with a given CLSID are declared in a subkey with the CLSID as its name under HKEY_CLASSES_ROOT\CLSID (as a side note, HKEY_CLASSES_ROOT is a unified view of HKEY_LOCAL_MACHINE\SOFTWARE\Classes and and HKEY_CURRENT_USER\SOFTWARE\Classes, allowing for per-user class registration).

Furthermore, if your objects use any custom interfaces (they probably do), a proxy/stub factory is required for marshalling them across apartments in the same process or across processes in the same machine or in different machines in the network. The way this usually works is with a subkey named after the IID in question under HKEY_CLASSES_ROOT\Interface. In there a ProxyStubClsid32 value specifies the DLL that implements a proxy/stub factory for the interface in question. Rather than coding that yourself, you often let MIDL, the IDL compiler, generate this for you from the .idl file describing your custom interface and link the generated code to create this DLL.

Registering your CLSID implementation and the proxy/stub factories for your IIDs is desirable in most scenarios, but as software becomes more complex and the deployment scenarios more numerous, COM registration can become a source of pain and agony. Microsoft themselves recognized the migration of “DLL Hell”-style problems into the realm of COM and introduced a registration-free COM feature with the “Fusion” SxS (side by side) loader included starting with Windows XP, based on XML manifests.

Those of us who have been following the literature on COM over the years consider this development quite ironic, since COM has been “sold” as solving the world’s version issues since the era it was still being called “OLE 2.” I guess version-based ProgIDs aren’t enough.

Anyway, Fusion’s XML-based manifest solution is decent enough. You deploy a side-by-side assembly (unfortunately, Microsoft’s vendor lock-in forces you to do this with Windows Installer at the moment, an issue I’ll discuss in a future post) and describe your exported COM objects by CLSID in the XML manifest, describing the server type, ThreadingModel and so on. A facility for registering proxy/stub factories is also provided. You attach the XML manifest to your DLL either as an inline resource (a Win32 resource in text XML format – it is obvious this is the meeting point of technologies from different eras) or as an external XML file, named name.dll.manifest for a DLL called name.dll. Your client application binds to the specific version of the COM object of interest either in an XML manifest of its own (the easy way) or if you really want to spice things up, uses the not so well-known Fusion APIs, CreateActCtx and ActiveActCtx to get the client to bind to the desired implementation. Unfortunately Fusion’s API is a little “square”, requiring you to specify the manifest either as the path to a PE image (EXE/DLL) and the name of its embedded manifest resource or a .manifest file. You can’t specify a buffer containing XML describing your binding requirements or better yet specify some structure with that information. Obviously, the Fusion guys didn’t have dynamic code generation in the unmanaged code realm in mind.

You can read more about registration free COM in Junfeng Zhang’s blog. Older entries in his blog have a wealth of Fusion-related information. Two specific posts of interest are this one and this one. The rest of the stuff in the Fusion category are also a good read.

The fact the Fusion native loader is only available starting with Windows XP and the unfortunate issue of its inflexibility in specifying binding information presents a difficulty for those of us who wish to deploy isolated COM components in a heterogeneous environment. Yet this same heterogeneous environment is exactly that which presents us with the most difficult version compatibility issues, bringing us to require side by side components in the first place. A solution independent of Fusion is desired.

First we must understand the basic mechanics of COM activation. When we try to retrieve a CLSID’s class object (either directly with CoGetClassObject or indirectly with CoCreateInstance, etc.) the COM runtime (which mainly consists of ole32.dll, rpcrt4.dll and rpcss.exe) will first try to find a running instance of the class factory, before turning to the registry for activation information. It is this behavior that makes the second instantiation request for an object implemented in a .EXE local server recycle the existing class factory from the server rather than create another instance of the .EXE specified in the registry’s LocalServer32 value (note that I do not consider here the case of REGCLS_SINGLEUSE vs. REGCLS_MULTIPLEUSE, etc., but rather discuss the typical scenario). We can conclude from this behavior that registration for local servers is for activation purposes, since locating running instances is done independently of the registry (presumably with the Running Object Table).

CoRegisterClassObject is the COM runtime API running local servers use to announce the local server’s class factory is active and that activation of the server is no longer required for instantiating clients. Microsoft’s official documentation states the API is only intended for EXE servers and that DLLs should export DllGetClassObject instead. However, this appears to be an attempt to prevent confusion by novices rather than anything else. The fact is, your COM DLL can avoid a registry entry and register a class factory for in-process clients to use. Similarly, a local server could settle for calling this API and not registering itself in the registry. This of course means you give up COM’s activation facility. Trying to create objects before your class factory has “magically” come to life fails as though the class wasn’t registered. Once registration is performed, objects can be created.

At this point our strategy is hindered by the mechanics of COM’s marshaling architecture. It is not unusual for us to want our objects to be accessible beyond the confines of the apartment they were created in, and indeed, beyond their hosting process. We need to get around COM’s expectation that the proxy/stub factories for our custom interfaces be specified in the registry.

One solution is to statically link the proxy/stub factory for the custom interfaces we use into our clients and servers (this isn’t as bad as it sounds – they already have a deep intimacy with the custom interfaces seeing as they know them at the vtable and argument passing level). For an interfaces defined in name.idl, typically name_p.c is the name of MIDL’s generated proxy/stub factory. The actual implementation is in fact resident in ole32.dll, while MIDL’s output is some sort of descriptor table for that implementation to use with your specific custom interface. Usually name_p.c contains implementations of functions expected from a COM DLL, like DllGetClassObject. To prevent conflicts, we define the ENTRY_PREFIX preprocessor directive which allows us to prefix those generated functions with a name. Assuming we #define ENTRY_PREFIX PrxStb, for instance, We can call PrxStbDllGetClassObject to retrieve the class factory for the proxy/stubs for our interfaces. We now need to make the COM runtime understand this retrieved instance is the proxy/stub factory we need and that it has no business looking in the registry. CoRegisterPSClsid is just the API for the job. When a proxy/stub factory CLSID is registered using this API, the COM runtime no longer requires a ProxyStubClsid32 entry for our custom interface in the registry. Since we specify a CLSID here, we need to either write information about this CLSID to the registry or provide both the client and server side, separately, with running instances of the factory registered with CoRegisterClassObject (just like our actual object) so they’d be able to use it, creating proxies in the client side and stubs in the server side. A noteworthy (and apparently not-so-documented) fact to consider at this stage is that the CLSID for interface proxy/stub factories generated by MIDL is equal to the IID of the custom interface in question – just in case you were wondering what CLSID to create, register and map to the interface.

It is important to note that you must register an instance of the proxy/stub factory in each and every apartment you wish it to be available for object use, otherwise COM will unsuccessfully attempt to find a proxy for your proxy since it is only available elsewhere.

I’ve seen fragments of this solution discussed on the web and on various newsgroups, but its complete specification was always missing, so I hope this helps. However, there is another noteworthy solution to consider.

The second solution is only slightly different from the first one and it is unclear whether it has any advantages. It is only noteworthy because it both utilizes undocumented APIs, which seem to be barely mentioned in a web search and is implemented in a sample from Microsoft’s .NET 1.1 Framework SDK. Indeed, it appears this underground sample was scrapped from later .NET SDKs and is missing from the current Windows SDK. The “Marshaler” sample uses CreateProxyFromTypeInfo and CreateStubFromTypeInfo, exported from rpcrt4.dll, to create proxies and stubs for arbitrary interfaces specified by a given ITypeInfo* (which you can easily give it for your custom interface if you create a Type Library for it). If you have another reason to deploy a type library as a part of your isolated component, you may consider this nicer than statically linking to the MIDL-generated code.

Both of the these non-Fusion approaches have the apparent advantage of universality (although I haven’t checked whether they work on the deprecated Windows 9x family). However, keep in mind they are only useful to you if you are willing to give up on one of COM’s most notable features – activation. Without the registry, you alone are left in charge of bringing your class factories to life, making sure you create them as needed and where needed, considering threading model and other issues. Nevertheless, even in XP and later systems, these isolation approaches may be considered to have advantages over their Fusion counterpart.

If only everybody just had the CLR…