The assemblyIdentity element is always required, part of the manifest plumbing. You must always provide the comClass element, it substitutes the HKLMSoftwareClassesCLSID
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 COM server doesn't support being called that way at all and must always be used from the same thread it was created on. Stop there, no need to add anything to the manifest.
The COM server implements the IMarshal interface. Automatically queried by COM when it cannot find another way to marshal the call. This is quite rare, except for a case where the COM server aggregates the free-threaded marshaller. In other words, is completely thread-safe by itself without needing any help and always runs in-process. PDM is likely to work that way. Stop there, no need to add anything to the manifest.
The COM server author started his project by writing the interface description of the server in the IDL language. Which was then compiled by MIDL. One option it has available is to auto-generate code from the IDL declarations, code that can be used to build a separate DLL that implements the proxy and the stub. IDL is sufficiently rich to describe details of the function argument types and usage to allow the marshaling to be done by this auto-generated code. Sometimes IDL attributes are not sufficient, the COM author then writes a custom marshaller. COM loads that DLL at runtime to create the proxy and stub objects automatically.
Specific to the COM Automation subset (IDispatch interface), Windows has a built-in marshaller that knows how to marshal calls that meet the subset requirements. Very common. It uses the type library to discover the function declaration.
The latter two bullets require using HKLMSoftwareClassesInterface
, 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:
If you see it write the HKLMSoftwareClassesInterface
key then you can assume that you must provide the comInterface|External|ProxyStub element
If you see it write {00020420-0000-0000-C000-000000000046} for the ProxyStubClsid32 key then you can assume it is using the standard marshaller and you must use comInterfaceExternalProxyStub element as well as the typelib element. You should then also see it write the IID's TypeLib registry key as well as the entry in the HKLMSoftwareClassesTypelib registry key. The latter gives the path of the type library. Almost always the same as the COM server, embedding the type library as a resource is very common. If it is separate (a .tlb file) then you must deploy it.
If the ProxyStubClsid32 key value is another guid then you can assume it is uses its own proxy/stub DLL. You should then also see it write the CLSID key for the proxy, its InProcServer32 key gives you the path to the DLL. If that file name matches the server's file name then you can assume that the proxy/stub code was merged and you must use the comInterfaceProxyStub element instead. If not then comInterfaceExternalProxyStub is required and you must deploy the DLL
If you see it write the ProgID in HKLMSoftwareClasses
then use the progid element, exactly as shown in the trace.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…