Okay, a follupup to this post. Which stemmed from the thing I had to do in this post. Which all centered around the consultants featured in this post.
Basically, I wrote an assembly in C# that would print to a special printer in our lab. This was because our consultant didn’t have a cheap way to do it directly in their app. They were supposed to consume my assembly in their app to integrate the functionality. Their app is written in VB6, which means I had to expose my c# assembly as COM consumable.
First let me say that the information out there on this is sparse and confusing. But I did it, and they were able to use it. The problem was they were early-binding the assembly so that they could use intellisense. This, in VB6, means they add the generated .tlb for the assembly to the VB project reference and then do a:
Dim cassette As MyLibrary.CassetteClass
Set cassette = New CassetteClass
(or something similar)
The problem we ran into was that, if I changed the assembly at some point and re-registered it on the machine, even though it has the same CLSID, it breaks the reference and it doesn’t function.
What needed to be done was to allow late-binding in VB6 on the assembly so that the hard-added project reference could go away and it would create the object regardless of its location or version, so long as the CLSID and ProgID were the same. That changes the VB code to:
Dim cassette As Object
Set cassette = CreateObject(ProgID)
Now previously I had seen that the way to expose a .NET assembly to be consumed as COM was to do the following:
First, attribute your class with a Guid and a ClassInterface:
[System
.Runtime
.InteropServices
.GuidAttribute
("D02C57A7-B7E0-459f-987F-289FEF1B241F")]
[System.Runtime.InteropServices.ClassInterface
(System.Runtime.InteropServices.ClassInterfaceType.AutoDual)]
Now I had seen somewhere to set the ClassInterfaceType to AutoDual to support both early and late binding. And because I didn’t forsee the problem with early binding, I sent them the VB code sample implementing the early-binding method so they could use intellisense.
The second step is to generate a strong name for the assembly. I’m assuming most people know how to do that, but if not, just Google “strong name key generation” or something.
The third step is to register the assembly with the following command (you need to load the VS.NET command window to get access to regasm)
regasm /tlb:AssemblyName.tlb AssemblyName.dll /codebase
But versioning causes problems with the early binding, so we needed to switch to late binding. I tried it running some tests. But I kept getting an error when I tried to run it:
Run-time error '-2147024894 (80070002)':
File or assembly name [], or one of it's dependencies was not found.
So the late-binding wasn’t panning out, prompting my post yesterday.
After more digging around and being completely unable to late-bind this thing, I ran across this article on CodeProject (hey, something useful on CodeProject) that didn’t get me home, but it did mention that AutoDual causes problems with versioning. Once I found that out, I switched the line to be:
[System.Runtime.InteropServices.ClassInterface
(System.Runtime.InteropServices.ClassInterfaceType.AutoDispatch)]
Which essentially exposes IDispatch only, and allows for late-binding. It doesn’t allow for early-binding, but I don’t want it to be early-bindable anyway, so no sweat off my brow. I was pretty relieved and annoyed at finding out about AutoDual, because I didn’t even think to look there. The documentation says it will allow both late and early binding, so I just assumed that it was fine and was going nuts looking elsewhere for the problem.
So…hopefully, if anyone else runs across this, this will help.
Now playing: - Ramones - I Wanna Be Sedated
Tags:
Interop