Tomer Gabel's annoying spot on the 'net RSS 2.0
# Sunday, February 26, 2006

While working on one of our projects at Monfort, we encountered a very strange problem. The project was dependant on several COM objects, one of which queries a database according to a predefined interface and returns the results in an ADO Recordset. Our project is key-signed, so we had to import the COM objects using the .NET SDK tlbimp utility; everything worked perfectly until we added the querying logic that receives the Recordset result object. The class loader would throw an exception on calling the relevant method (it was invoked dynamically) claiming that the "referenced assembly adodb.dll could not be found." To quote Monty Python: this is, of course, pure bullshit. The imported ADODB wrapper was right there in the directory. I couldn't figure out the problem in a reasonably timespan, and finally decided to ignore it altogether by using the ADODB primary interop assembly distributed with .NET 1.1. I added a reference to the ADODB PIA and everything compiled and seem to run fine.

This turns out to have been a mistake. I was absent from work for a few days getting ready for a test, and came back to find that a colleague has encountered the same problem but elsewhere; examination of the compiled executable's references (via ILDASM) revealed that it was in fact generated with two separate references to ADODB with two different public key tokens. One of the references was the PIA, which was just peachy, but the other one (in the hidden namespace ADODB_19 of all things) referenced a non-existing assembly with the same public key token we sign our other assemblies with. I concluded that there must be some sort of problem with the build process - left over dependencies that weren't compiled properly or something of the sort. Cleaning up the build directory and rebuilding did not alleviate the issue. In desperation I tried to manually edit the project files but couldn't find anything.

I then decided that one of the COM object wrappers we created using tlbimp was, for some reason, referencing a non-existing version of the ADODB wrapper; I went through the wrapper assemblies one by one and managed to find the offending library. Turns out that tlbimp does not, by default, look for primary interop assemblies and opts to import ADODB every single time (singing the new wrapper assembly accordingly). When I deleted what I thought was a redundant ADODB wrapper assembly, I in fact deleted a version of the wrapper that was referenced by one the imported COM wrappers. So now all I had to do was add a /reference: directive to the tlbimp call in our build script and voilla - everything works!

Only it doesn't. Another COM object which references ADODB was still generated with the mangled assembly reference (i.e. it still referenced the wrapper with our own public key). I retried all sorts of tricks and couldn't figure out why it was generated that way; I eventually tried to re-import it manually with a /strictref directive, which resulted in the following error message:

C:\Temp>tlbimp SomeComServer.exe /keyfile:PublicKey.snk /reference:"%PROGRAMFILES%\Microsoft.NET\Primary Interop Assemblies\ADODB.dll" /strictref
Microsoft (R) .NET Framework Type Library to Assembly Converter 1.1.4322.573
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.

TlbImp error: System.ApplicationException - Type library 'ADODB' is not in the list of references

A fit of confused rage and an hour later I sat at the computer again to try to figure things out; finally (as usual) it was just a matter of asking Google the right question:

The problem was that MyCOMLib.dll was compiled against ADO 2.5 and the PIA released by MS is registered only for ADO 2.7. I don't have access to the COM component to recompile it for ADO 2.7, so I had to get a PIA for ADO 2.5.

Further research into this turned out a little detail most .NET developers are probably unaware of:

Issue 7: You experience problems working with components that expect ADO 2.8 interfaces

The ADODB PIA that is included with Visual Studio 2005 is the same component that was included with Visual Studio .NET 2003 and was built by using the Microsoft .NET Framework 1.1. The ADODB PIA was built to interact with ADO 2.7 interfaces and has not been updated to work with ADO 2.8 interfaces.

Therefore, attempts to use the ADODB PIA together with components that expose ADO 2.8 interfaces will fail. This scenario is not supported with the ADODB PIA.

Oh, great job, Microsoft! You spent so much time on the interop issues with .NET (of which, by the way, there is an impressively small number), came up with the concepts for Primary Interop Assemblies, Publisher Policy Files and everything else that went into .NET in order to prevent DLL hell, you tout Primary Interop Assemblies as a way for component publishers to guarantee that their components are usable under .NET, and finally you go on to release a PIA for one of the most widely used COM objects in Windows which only supports one version!

So there you are, I hope this might save someone the frustration of having to figure all of this out on their own.

As a footnote, ILDASM is one of the worst tools I've ever used. I can't believe how Microsoft managed to wrap a useful debugging tool with one of the most frustrating and least usable UIs I've ever encountered. Don't know what I'm talking about? Try double-clicking on a node (method, manifest, whatever). You can't run a search through the text; worse still, you can't even Ctrl+A, Ctrl+C then paste into notepad! Only now, days after I needed it, did it occur to me to rightclick and "select all". I suppose it's OK if you don't follow the classic usability patterns and guidelines in a small and esoteric development tool, but please try and exercise a bit of common sense...

Sunday, February 26, 2006 10:47:04 PM (Jerusalem Standard Time, UTC+02:00)  #    -
Send mail to the author(s) Be afraid.
<August 2022>
All Content © 2022, Tomer Gabel
Based on the Business theme for dasBlog created by Christoph De Baene (delarou)