c++commanifestside-by-sideregfreecom

Which tags are required in the manifest for registration free COM?


TL;DR Do all registry entries produced by regsvr32 need to be present in a SxS reg-free-COM manifest and vice versa?


I'm trying to get registration free COM going for a third party component.

Reading up on the subject, I find that there are several elements mentioned, that can be put into a manifest:

From the docs, we can add the following tags to a manifest to describe a COM component:

From the other docs for HKEY_LOCAL_MACHINE\SOFTWARE\Classes we can observe that there are a few categories for the COM registry entries:

Using regsvr42 to extract the stuff the dll I'm trying to regfree yields a manifest that only contains comClass entries, no typelib or ProxyStub entries. (And I cross checked the keys written, the DLL in question, pdm.dll, MS's Process Debug Manager only writes those keys, that is, there is no type library or proxy stub info apparent in the registry.)

If the registry only contains the info that pertains to comClass does this then mean that this info will be sufficient in the SxS manifest, or may additional info be needed in the manifest?


As an aside I noticed that the registry contains a VersionIndependentProgId and a ProgId that has a version number appended at the end. The manifest only has a ProgId entry, and the docs state:

progid : Version-dependent programmatic identifier associated with the COM component. The format of a ProgID is <vendor>.<component>.<version>.

But the docs also state

The comClass element can have <progid>...</progid> elements as children, which list the version dependent progids.

and they say that the progid attribute should be the version independent one.

So, what to put here? And does it even matter when the client doesn't request a specific version?


Solution

  • The assemblyIdentity element is always required, part of the manifest plumbing. You must always provide the comClass element, it substitutes the HKLM\Software\Classes\CLSID registry key and is used to make the client's CoCreateInstance() call work. The file element names the COM server executable file.

    The rest of the keys are optional, they are needed to make marshaling work. Marshaling occurs when the client call needs to be made on a different thread. That will always happen when the server and the client are in different processes, the case for an out-of-process server or when the server runs on another machine. And it can happen when the ThreadingModel specified in the comClass element demands it. In other words, when the COM object was created on one thread but is called on another and the server is not thread-safe.

    RPC implements the marshaling but it has one job to do that it needs help with. It needs to know what the arguments for the function are, as well as the return type. So that it can properly serialize their values into a data packet that can be transmitted across a network or passed to the code in another thread that makes the call. This is the job of the proxy. The stub runs at the receiving end and deserializes the arguments to build the stack frame and makes the call. The function return value as well as any argument values passed by reference then travel back to the caller. The code that makes the call otherwise has no awareness at all that it didn't call the function directly.

    There are four basic cases:

    The latter two bullets require using HKLM\Software\Classes\Interface, it has entries for the IID for every interface. That's how COM finds out how to create the proxy and the stub for the interface. If it cannot find the key then it falls back to IMarshal. You must use the comInterfaceExternalProxyStub element to substitute the registry key. Using comInterfaceProxyStub is a special case, that's when the proxy and stub code is included with the COM server executable instead of being a separate file. An option in ATL projects for example, turned on with the "Allow merging of proxy/stub" wizard selection.

    The last bullet also requires using the typelib element, required so the built-in marshaller can find the type library it needs.

    The progId is required when the COM client uses late binding through IDispatch, the CreateObject() helper function in the client's runtime support library is boilerplate. Used in any scripting host for example.

    Having some insider knowledge of how the COM server was created certainly helps, always contact the vendor or author for advice. It can be reverse-engineered however by observing what registry keys are written when the server is registered, SysInternals' ProcMon tool is the best way to see that. Basic things to look for: