views:

71

answers:

1

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)

+2  A: 

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
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
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
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
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
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
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
I've made some progress here, which is why I've accepted the answer. See question for additional information.
Steve
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