1

Our program needs to consume the COM server which is also made by us. The scenario is the following: the installer will copy both the program files and the COM server files into the same folder on each install.

Currently we use regsvr32 to register the COM server, but this is not very good - if we develop another unrelated program that also consumes the same COM server (likely of another version) we can run into problems - since the CLSIDs are unchanged, the server registered later will be used by both programs and the first program might malfunction.

So we need reg-free COM. We could use manifests, but I've played with them for a while and find them not very convenient for use in the nightly build. We could also rewrite the program so that instead of calling CoCreateInstance() it calls LoadLibraryEx(), then GetProcAddress() to locate DllGetClassObject() and then just retrieves the class factory and uses it.

I immediately see some drawbacks:

  • the program will have the dependency on the exact COM server filename
  • extra code will have to be written for stuff normally managed by Windows
  • the COM server will have to be in-proc and marshalling will never be used

and those drawbacks could be show stoppers generally but don't look bad at all in our specific scenario.

Are there any other drawbacks in using LoadLibraryEx()/DllGetClassObject() compared to CoCreateInstance()?

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • Isn't this what COM versioning is supposed to alleviate? If you need to modify the interface, you add a new one that inherits from the old one. If you need to modify the implementation, you add a new one (which could also inherit from the old one). So you have IID_IWhatever and IID_IWhatever2, and CLSID_Whatever and CLSID_Whatever2. Your old program would use IID_IWhatever and CLSID_Whatever whereas your new program could use IID_IWhatever2 (if the interface changes) or CLSID_Whatever2 (if the implementation changes). During the install you make sure that the newest version is installed. – Luke May 25 '10 at 14:58
  • @Luke: We do maintain binary compatibility of the interfaces, but there're implementation details - especially our internal libraries - that can cuase problems if another version with exactly the same interface is loaded from some unrelated location. Changing all interfaces and class ids every time we change internal libraries is not a good idea - lots of maintenance problems. So it's not COM fault in any way, its our fault and to resolve it we need some kind of side-by-side. – sharptooth May 26 '10 at 05:11
  • I guess I just don't know enough details about your situation to know what the problem is. If you're already XCOPY-deploying your component and now you don't even want to register it, why not just change it into a plain old DLL? In any event, I've done a little bit of this before and your concerns were the only things I ran into; aside from that, everything worked fine. – Luke May 26 '10 at 14:30
  • @Luke: Here's how we got here: we have two project configurations - one for a normal COM server for customers' use and another for our internal use. This looks simpler than having to convert the thing that initially was a COM server into a usual DLL. – sharptooth May 26 '10 at 14:45
  • If you need both COM server implementations to be available at the same time (i.e. for use by different processes) then I think you'll have to go the LoadLibrary way. – Luke May 26 '10 at 19:16

2 Answers2

1

I follow the exact procedure you describe, to implement my own lightweight version of COM. You are talking about replacing the 'activation' portion of COM. I think you list all the functionality the COM activation model provides:

  1. Out of process/apartment threading support
  2. Indirection via registry for resolving CoClass library location, allowing for newer versions, alternate implementations, etc.

Once you dynamically load the library, retrieve the class factory, and construct your object it should behave no differently than if you had created a in-process object within your apartment via COM.

joncham
  • 1,584
  • 10
  • 14
0

1. the program will have the dependency on the exact COM server filename

By using DLL Delay-load notification hooks and handling dliNotePreLoadLibrary (i.e. preempting the load), you can load from a DLL that has a different filename than recorded in the client's import table.

In fact, you can specify the actual DLL filename you wish to use in command line, or even a configuration file. (I just did that recently.) As long as you don't try to use the library before it's time.

2. extra code will have to be written for stuff normally managed by Windows

As for GetProcAddress, The delay-load helper utility provides a function for loading all imports from a single module at once.

3. the COM server will have to be in-proc and marshalling will never be used

As for marshaling - I'm not familiar with this area, but here's some ideas:

  • Need to implement your own proxy/stub code do handle inter-process-communication your own way

This means you'll need to write your own marshaling compiler, I'm afraid. You may find that other people have already done that.

Once that is done, the client will LoadLibrary the proxy, the proxy will launch the stub executable (out-of-process) to host the server, and the stub will LoadLibrary the actual server.

This is basically a complete reinvention of COM.

rwong
  • 6,062
  • 1
  • 23
  • 51