Early Binding of a C# COM library in VBA

c#, name-collision, registry, vba, visual-studio-2012

Solution

Do avoid focusing on the ProgId. You are not actually using it, the dialogs that you made a screenshot of show the actual class names, not the ProgId.

Getting the class name renamed to "Test_Connection" is normal behavior for the type library exporter. It will do so whenever it detects a conflict with another interface or class name that has the same name. You are certainly increasing the likelihood of this happening by also having a dependency on ADODB, it also has a Connection class. A very trivial solution is to simply rename your own type.

Your code snippet cannot reproduce this problem. But of course it is incomplete, we can't see what you are really doing in the code. You'll bring in the dependency on ADODB if any of your public methods use a type from this type library. Also note that there are non-zero odds that this will happen by accident. You might have written a method that intended to use your own Connection type but the compiler resolved it to the ADODB type.

An essential tool to debug this is Oleview.exe, run it from the Visual Studio Command Prompt. First create the type library for your C# assembly with Tlbexp.exe. Then use File + View Typelib, you'll see the content of your type library expressed in the IDL syntax. You'll have little trouble recognizing the mapping of your C# types to the IDL declarations.

Pay attention to the `importlib` directives at the top of the file. They should look like this:

// TLib :     // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
importlib("mscorlib.tlb");
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");

There should only be those two. The first one imports the .NET types, defining _Object. The second one imports standard COM types, like IDispatch. If you see additional ones here then you increase the odds of a name collision.

This IDL also gives you a way to solve the problem, in case it is unsolvable, you can edit it to name the types the way you want them. Save it to a .idl file. And compile it with midl.exe /tlb to generate a type library with your preferred names. Do note that this is not something you want to have to do often.

Problem

Although this is a long question the coding and testing part should be really easy to reproduce. I have created two separate `Class Libraries` in `C#` and I think I am running into a name collision problem caused by existing registry keys from my previous projects and trials. Here are my two classes: ``` using System; using System.Runtime.InteropServices; namespace Test { [InterfaceType(ComInterfaceType.InterfaceIsDual), Guid("ED5D264B-1D80-4A5D-9C14-8297D90B7037")] public interface ITest { // body } [ClassInterface(ClassInterfaceType.None)] [Guid("8B261B92-8EC5-4CDC-A551-67DEB42137FF")] [ProgId("Test.TestClass")] public class TestClass : ITest { // body } } ``` and ``` using System; using System.Runtime.InteropServices; using ADODB; namespace Test { [InterfaceType(ComInterfaceType.InterfaceIsDual), Guid("ED5D264B-1D80-4A5D-9C14-8297D90B7037")] public interface IConnection { // body } [ClassInterface(ClassInterfaceType.None)] [Guid("8B261B92-8EC5-4CDC-A551-67DEB42137FF")] [ProgId("Test.Connection")] public class Connection : IConnection { // body } } ``` I have Exposed .Net Components to COM like this: In order to access the assemblies from Excel I have added the ADODB references to the assembly, ticked make assembly COM visible and register for com interop. Also, I've added references to each `*.tlb` file(2 files for two projects) so I can access them using an early binding and use VBA Intellisense. I have followed the same procedure on another machine and I can use early binding using the `Connection` as class. I am thinking there are some old registry keys I haven't deleted on my original machine which will not allow me to use `Connection` as the class name in VBE. I've manually scanned my registry and deleted everything I could think of related to my project. I have also deleted the project entirely and used a 3rd party software to scan registry for missing `dll`s however that didn't help:/ Removed all previously registered GUIDs and applied new ones each time I created a new Project (just in case) Created new projects using different namespaces and class names (`using ADODB;`) I haven't been able to use early binding yet like this `Test.Connection` therefore I am assuming I have a name collision problem. I am suspecting the name class `Connection` to be causing it although I am not 100% sure. The `Test.TestClass` namespace in VBA: I can declare and use instances of the `TestClass` type in two ways using early binding: ``` Dim x as Test.TestClass Dim x as TestClass ``` Now going into VBE Object Explorer F2 the `TestClass` is properly displayed in comparison to other libraries and general idea of using COMs. However, when I want to use the `Test.Connection` library I am unable to use early binding following the same pattern as `TestClass` because the generated `*.tlb` file automatically changes(renames) the `ProgId's`. So, instead I have to bind it like this ``` Dim x As Test.Test_Connection Dim x As Test_Connection ``` and the `Object Explorer` displays the names using `_` (underscores) and not `.` (dots), which is easy to explain why this happens - keep reading :) As it stands I am sure it is not the VBE environment that changes the names to avoid collisions. It is the VS' `*.tlb` generator. I went to the assembly folder and opened both `*.tlb` files in `Notepad++`. I can clearly see that the `*.tlb` for the `Test.Connection` library already includes the names with the `_`s unlike the `Test.TestClass` which has `.`s I have tried to manually edit the `*.tlb` file but as its a mixed binary file it takes some effect but also causes Excel to stop responding in some weird ways so I have to avoid this method. I think I have explained well what the problem is and where it comes from. Now my question is: Are there any attributes to use in C# code to tell the `*.tlb` generator not to override my `ProdId`s? Are there any alternative ways of manipulating `*.tlb` files? Is this issue a `name collision` and is it avoidable without changing the name of `Connection` class? I'm sorry for such long question but I have been digging and digging for almost a week now and I still cant solve this. Note: In VBA ( or VBE Object Explorer ) using IntelliSense ctrl+space it does not seem that either `Connection` or `Recordset` have been used. Since they are not already reserved in the VBE environment I recon it has to do with my library itself. As a reference to why this issue has been raised here, please see VBA equivalent to C# using or VB.NET imports creating aliases Thank you very much for your time!

Original source

Related problems