VBA中C#COM库的早期绑定 [英] Early Binding of a C# COM library in VBA

查看:135
本文介绍了VBA中C#COM库的早期绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尽管这是一个很长的问题,但是编码和测试部分应该真的很容易复制。



我在 C#中创建了两个单独的 Class Libraries ,我想我是由于以前的项目和试验中的现有注册表项引起的名称冲突问题。



这是我的两堂课:

 使用系统; 
使用System.Runtime.InteropServices;

命名空间测试
{

[InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid( ED5D264B-1D80-4A5D-9C14-8297D90B7037)]
公共接口ITest
{
// body
}

[ClassInterface(ClassInterfaceType.None)]
[Guid( 8B261B92- 8EC5-4CDC-A551-67DEB42137FF)]
[ProgId( Test.TestClass)]
公共类TestClass:ITest
{
// body
}
}

 使用系统; 
使用System.Runtime.InteropServices;
使用ADODB;

命名空间测试
{

[InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid( ED5D264B-1D80-4A5D-9C14-8297D90B7037)]
公共接口IConnection
{
// body
}

[ClassInterface(ClassInterfaceType.None)]
[Guid( 8B261B92- 8EC5-4CDC-A551-67DEB42137FF)]
[ProgId( Test.Connection)]
公共类连接:IConnection
{
// body
}
}

我有

非常感谢您的宝贵时间!

解决方案

请避免专注于ProgId。



将您重命名为 Test_Connection的类名的操作是在屏幕快照中显示的实际类名,而不是ProgId。类型库导出程序的正常行为。每当它检测到与另一个具有相同名称的接口或类名称发生冲突时,它将这样做。当然,您也依赖于ADODB,这肯定会增加发生这种情况的可能性,它还具有Connection类。一个非常简单的解决方案是简单地重命名您自己的类型。



您的代码段无法重现此问题。但是,当然这是不完整的,我们无法在代码中看到您真正在做什么。如果您有任何公共方法使用此类型库中的类型,则将引入对ADODB的依赖性。还要注意,这是偶然发生的非零几率。您可能已经编写了一种打算使用自己的Connection类型的方法,但是编译器将其解析为ADODB类型。



Oleview.exe是调试该问题的必要工具,从Visual Studio命令提示符运行它。首先使用Tlbexp.exe为C#程序集创建类型库。然后使用File + View Typelib,您将看到以IDL语法表示的类型库的内容。识别C#类型到IDL声明的映射将很容易。



请注意 importlib 指令位于文件顶部。它们应该看起来像这样:

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

应该只有 这两个。第一个导入.NET类型,定义_Object。第二种导入标准的COM类型,例如IDispatch。如果您在此处看到其他问题,则可能增加名称冲突的可能性。



此IDL还为您提供了解决问题的方法,以防万一它无法解决,可以对其进行编辑,以根据需要命名类型。将其保存到.idl文件。并使用midl.exe / tlb进行编译,以生成具有您首选名称的类型库。请注意,这不是您经常要做的事情。


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 dlls 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 ProdIds?
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!

解决方案

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.

这篇关于VBA中C#COM库的早期绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆