尽管这是一个很长的问题,编码和测试部分应该很容易重现。
我在Class Libraries
中创建了两个单独的C#
,并且我认为我遇到了由我以前的项目和试验中存在的注册表项引起的名称冲突问题。
这是我的两门课:
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
}
}
和
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
}
}
我有过这样的经历:
为了从excel访问程序集,我添加了对程序集的adodb引用,勾选make assembly com visible并注册com interop。此外,我还添加了对每个
*.tlb
文件的引用(两个项目有两个文件),这样我就可以使用Exposed .Net Components to COM访问它们并使用vbaearly binding。我在另一台机器上遵循了相同的过程,并且可以使用
Connection
as类使用早期绑定。我想有一些旧的注册表项我没有删除在我的原始机器上,这将不允许我使用
Connection
作为类名在vbe中。我已经手动扫描了我的注册表,删除了所有我能想到的与我的项目相关的东西。我还删除了整个项目,并使用第三方软件扫描注册表中缺少的
dll
s,但没有帮助:/删除所有以前注册的guid,并在每次创建新项目时应用新的guid(以防万一)
使用不同的名称空间和类名(
using ADODB;
)创建了新项目,我还不能像这样使用早期绑定,因此我假设我有一个Intellisense问题。我怀疑是name类Test.Connection
引起的,尽管我不能百分之百确定。vba中的
Connection
命名空间:我可以使用早期绑定以两种方式声明和使用
Test.TestClass
类型的实例:Dim x as Test.TestClass
Dim x as TestClass
现在进入vbe对象资源管理器f2,与其他库和使用coms的一般思想相比,
TestClass
正确显示。但是,当我想使用
TestClass
库时,我无法使用与Test.Connection
模式相同的早期绑定,因为生成的TestClass
文件会自动更改(重命名)*.tlb
。所以,我只好这样绑起来Dim x As Test.Test_Connection
Dim x As Test_Connection
ProgId's
使用Object Explorer
(下划线)而不是_
(圆点)显示名称,这很容易解释为什么会发生这种情况-继续阅读:)从目前的情况来看,我确信不是vbe环境更改名称以避免冲突。它是vs'
.
发生器。我转到assembly文件夹,打开
*.tlb
中的两个*.tlb
文件。我可以清楚地看到,Notepad++
库的*.tlb
已经包含了带有Test.Connection
s的名称,而不像_
具有Test.TestClass
s的名称我试图手动编辑
.
文件,但由于它是一个混合二进制文件,因此会产生一些效果,但也会导致excel以某些奇怪的方式停止响应,因此我必须避免使用这种方法。我想我已经很好地解释了问题是什么,从何而来。现在我的问题是:在C代码中是否有任何属性可以用来告诉
*.tlb
生成器不要重写我的*.tlb
s?有没有其他处理ProdId
文件的方法?这个问题是一个*.tlb
问题吗?在不更改name collision
类的名称的情况下,它是可以避免的吗?我很抱歉问了这么长时间,但我已经挖了差不多一个星期了,仍然无法解决这个问题。
注意:在使用intellisense ctrl+space的vba(或vbe对象资源管理器)中,似乎没有使用
Connection
或Connection
。由于它们还没有在vbe环境中被保留,我发现这与我的库本身有关。请参阅name collision
非常感谢你的时间!
最佳答案
不要把注意力集中在progid上。您实际上并没有使用它,您制作的屏幕截图中的对话框显示的是实际的类名,而不是progid。
将类名重命名为“test_connection”是类型库导出器的正常行为。每当它检测到与另一个具有相同名称的接口或类名发生冲突时,它就会这样做。当然,您还依赖于adodb,它也有一个连接类,从而增加了发生这种情况的可能性。一个非常简单的解决方案是简单地重命名您自己的类型。
您的代码段无法重现此问题。但它当然是不完整的,我们看不到你在代码中真正做了什么。如果您的任何公共方法使用此类型库中的类型,您将引入对adodb的依赖。还要注意的是,发生这种情况的几率不是零。您可能已经编写了一个方法来使用您自己的连接类型,但是编译器将其解析为ADODB类型。
要调试此文件,一个必不可少的工具是oleview.exe,请在visual studio命令提示符下运行它。首先使用tlbexp.exe创建C程序集的类型库。然后使用file+view类型库,您将看到用idl语法表示的类型库内容。您将很容易识别c类型到idl声明的映射。
注意文件顶部的importlib
指令。它们应该是这样的:
// TLib : // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
importlib("mscorlib.tlb");
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
应该只有这两个。第一个导入.NET类型,定义对象。第二个导入标准的com类型,比如idispatch。如果你在这里看到其他的,那么你就增加了名字冲突的几率。
这个idl还为您提供了一种解决问题的方法,如果问题无法解决,您可以对其进行编辑,以您想要的方式命名类型。保存到.idl文件。并使用midl.exe/tlb编译它,以生成具有首选名称的类型库。请注意,这不是你想经常做的事情。