10

I'm trying to setup registration free COM, but have a slight problem in that I another COM object may be the client.

App.exe----->COM Server/Client dll(registered or not)-------->COM Server DLL (NOT Registered)

My questions is, is it possible to create a manifest for the second dll (COM Server/Client dll)? I do not have control of the executable, but if I did, this works if I create a client manifest for the executable and a server manifest for the COM server dll.

this is the manifest file for the middle dll. I tried embedding it and tried it external. Still doesn't work.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity type="win32" 
                    name="COMCliSer.dll" 
                    version="1.0.0.0" 
  />
  <dependency>
    <dependentAssembly>
      <assemblyIdentity 
                     name="COMSer.dll" 
                    version="1.0.0.0"                    
      />
    </dependentAssembly>
  </dependency>
</assembly>

On further investigation, I can get this all to work as long as the middle dll is also registration free and the exe has an application manifest. As soon as I register the middle dll, and drop the application manifest (I do not have control of what exe will use my dll), the whole thing stops working.

If the exe has no manifest, then the dll's manifest is not taken into consideration. I can prove this by setting up everything to work. Then putting a mistake in the assembly manifest. This pops up the usual message :

Unable to create process: This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.

If I then drop the application manifest, the application loads (albeit the CoCreateInstance fails because the dependencies are not taken into consideration)

Steve
  • 6,382
  • 3
  • 41
  • 66
  • Why are you calling the assembly `comser.dll`? Is the assembly manifest information merged? It is much much easier to deploy an assembly with a descriptive name e.g. "Microsoft.VC90.CRT", that contains dll's with different names: "msvcr90.dll". When dealing with dll-assemblies it becomes more difficult to debug as a single manifest now serves two purposes: to describe the contents of the assembly to consumers, AND to describe the dependencies of the dll in the assembly. – Chris Becke Oct 20 '10 at 12:41
  • The names have been changed to protect the innocent! Those are not the real names. These are native COM dlls and not .NET assemblies. – Steve Oct 20 '10 at 13:31
  • Also, what does "doesn't work" count as? Does the exe and 2nd dll load and simply fail to instantiate the 3rd, or does the exe, or 2nd dll fail to load totally? Getting things to actually fail to load is a good step as it means that the system is seeing the manifest, and logging an error to the system, or application, event log at least. If its simply failing on the call to CoCreateInstance then it probably just cant see the manifest at all. – Chris Becke Oct 20 '10 at 15:57
  • Failing on the CoCreateInstance for the second dll. – Steve Oct 22 '10 at 13:36
  • Steve, can you post your final working solution? This was a great question and I would love to see exactly how you implemented your solution. – WillowDweller Feb 01 '12 at 21:49

1 Answers1

5

Just add an assembly dependency to the server/client dll's manifest that points to the com server dll.

Remember that assembly manifests are different to 'application' manifests: An assembly manifest describes an assembly: gives it a name, and lists its dlls. An application manifest is the RT_MANIFEST embedded resource, which describes the current modules dependencies.

So, in the final analysis, you would have:

  • app.exe, with an external (app.exe.manifest) or embedded RT_MANIFEST describing a dependency on an assembly called 'acme.clientserver'
  • acme.clientserver.manifest describing an assembly, and listing 'clisrv.dll' as a registration free com dll.
  • clisrv.dll, with an external (clisrv.dll.2.manifest) or embedded RT_MANIFEST, describing a dependency on an assembly called 'acme.server'
  • acme.server.manifest, describing an assembly, listing serv.dll as a registration free com dll.
  • serv.dll - which may, or may not in turn have a manifest listing yet more dependent assemblies.

It is technically possible to call the assembly by the dll's name, and merge both the assembly and dll manifest together - the win32 loader supports this, but some settings that are valid in application manifests are not valid in assembly manifests, which can cause the resulting assembly to fail to load. It also makes it very hard to digitally sign.


WRT the exe having to have a manifest: Usually the exe's manifest sets up the processes default activation context. I'm not 100% sure how windows behaves when the exe has no manifest, but I'm pretty sure that manifests in dlls will still be processed.

Which means the problem comes down to the lack of isolation support in CoCreateInstance - for some reason - by default - CoCreateInstance only looks in the default activation context for reg free com entries.

The way to override it is to manually build your own activation context, using the Activation Context API

The basic method would be to call:

  • CreateActCtx - to create an activation context from your dlls manifest.
  • ActivateActCtx - to activate the context
  • CoCreateInstance - will now search the current activation context for reg free com entries.
  • DeactivateActCtx - to restore the default activation context.

You can add /D ISOLATION_AWARE_ENABLED to wrap most windows calls that are effected by activation contexts, for some reason CoCreateInstance is not wrapped :/

Chris Becke
  • 34,244
  • 12
  • 79
  • 148
  • i don't have the app.exe.manifest (don't need it as the middle com dll is registered). I tried adding a manifest to the middle dll, but to no avail. – Steve Oct 20 '10 at 10:34
  • Have you opened the middle dll in a resource editor (for. eg. visual studio) and seen if it has a RT_MANIFEST resource and whats in it? VS always displays RT_MANIFESTS as hex, so you need to export it to view it as text. – Chris Becke Oct 20 '10 at 10:37
  • Ok, done that. The dll has two RT_Manifests, one that I suppose was put there by the compiler (Delphi) naming the Windows Common Controls as a dependency, and the other 1, the one I added which is displayed above. – Steve Oct 20 '10 at 11:05
  • Ouch. I am chock full of advice on how to merge in manifest dependencies when using Visual C++. With delphi I can't help you :- you do need to merge your dependency information with delphi's - does delphi at least include the "mt.exe" tool from the platform SDK? MT is quite versatile, and can update embedded manifests, merging in other manifests. – Chris Becke Oct 20 '10 at 12:42
  • So you are saying my problem is that I have two dependencies. If I can merge them, I should be good to go? I'll check for mt.exe – Steve Oct 20 '10 at 13:10
  • Well, the problem is the Widows Loader is only going to process 1 RT_MANIFEST resource. You need to merge both dependencies into a single RT_MANIFEST resource. The automatically created one will have the resource id that the loader will look for. – Chris Becke Oct 20 '10 at 15:32
  • I've made some progress here, which is why I've accepted the answer. See question for additional information. – Steve Oct 25 '10 at 15:59
  • Using the activation context api directly solves all my problems. Thanks. I just need to embed the assembly manifest as a resource now, but in all honesty, even if I can't that's ok! thanks Chris! – Steve Oct 26 '10 at 14:44