views:

53

answers:

1

Current configuration is:

  1. The main application is unmanaged.
  2. It contains DLL, containing TLB, which describes functions, exposed to COM model.
  3. To support ASMX web services, it loads .NET framework, and starts ASP.NET domain that serves web service calls.
  4. To serve web service calls, it needs data from the main application. So, we're generating Interop assembly from TLB (using tlbimp.exe), and web service assemblies use this Interop to communicate with COM objects in the main application.

Everything works ok until we've encountered problem with versions. When 2 versions of application (containing 2 versions of TLB) were installed on the same computer, both versions of TLB (for example, 2.0 and 2.1) are registered, and lower version stops to work. ProcessMonitor shows that, when trying to call web service of version 2.0 instance, it looks into registry for TLB's GUID, reads all sub-keys with version numbers, takes the last version (2.1) and starts reading its contents. After that, it reads DLL of version 2.1, and fails to make COM calls inside its own process - as far as I understand, due to problems in marshaling.

How can I make the Interop that would not require presence of TLB (at least, presence of registered TLB) to make in-process COM calls?

Thanks in advance.

+1  A: 

Well, here's the way the problem was solved.

.NET seems to load TLB to build new apartment for each ASP.NET thread (everything happens when new thread first time tries to access some COM interface). It seems to use CoMarshalInterThreadInterfaceInStream and CoGetInterfaceAndReleaseStream functions for this purpose. I'm not able to prove that, but calling these functions causes the same effect: querying system registry and loading TLB of the highest compatible version (the same major version, highest minor version). CoGetInterfaceAndReleaseStream behavior isn't affected by manifest.

So, the real problem is that our project does not follow rules Microsoft recommends for version numbering: COM interfaces having the same major version should be compatible.

The only solution found was splicing: to get address of LoadTypeLib function (OleAut32.dll), and set JMP instruction in its beginning. JMP goes to our implementation, that checks name of TLB being loaded, and if it's one of known TLBs - redirects reading to local directory.

Abelevich
Wow, what a hackish solution. Why wouldn't you just increase the major number of the typelib?
sharptooth
New builds are created several times per day (of course, not all of them are incompatible, but it's quite difficult to completely check compatibility). Major versions length is only 2 bytes, so this solution would work only for 2 years, after that we still would need something else.
Abelevich