始终使用tlbimp.exe
工具导入基本类型库会为每个coclass
创建一个接口。例如,IDL描述
interface IFoo : IUnknown
{
HRESULT DoSomething();
}
coclass Bar
{
[default] interface IFoo;
}
结果在:
- 接口CCD_ 3作为COM接口的表示
- 类CCD_ 4作为COM类的表示
- 接口
Bar
,用CoClassAttribute
进行注释
其中Bar
和IFoo
的GUID相等。MSDN在这个主题上声明:
此接口与coclass的默认接口具有相同的IID。使用此接口,客户端可以始终注册为事件接收器。
这是我在这个话题上唯一找到的东西。我知道,由于CoClassAttribute
,我可以使用该接口来创建实际类的实例。我还知道(实际上)我可以简单地使用BarClass
来创建该类的一个新实例。我不明白的是,为什么导入过程会生成Bar
接口,即使coclass
没有定义事件源,因此没有事件接收器可以连接到它
在这个例子中,是否可以删除Bar
接口1,或者是否存在我尚未考虑的其他风险?
1例如,通过分解互操作程序集
您弄错了名称,这无助于理解发生了什么。类型库中的Bar
coclass生成了一个Bar
接口和一个BarClass
类,没有"FooBar"。
这只是类型库自动生成的额外胶水,使移植代码变得更容易。对于VB6代码特别重要的是,它在COM对象模型方面有很多自由度。VB6程序使用一个coclass,就好像它是一个带有实现的真实类一样。COM中不存在这样的东西,coclass是类的不透明占位符,它是完成所有工作的接口。VB6从不支持接口的概念,因此不可能在代码中直接建模COM。
VB6编译器本身从代码中的Class关键字生成一个coclass,并生成一个携带实际方法和属性的接口。该接口是隐藏的,它与类的名称相同,但带有前导下划线。按照惯例,这会导致对象浏览器隐藏界面。因此,当用VB6编写Bar
coclass时,它将生成一个_Bar
接口。
因此,转换后的VB6程序将在任何地方使用Bar
。除非将"Bar"替换为"IFoo",否则这不会编译。合成的Bar
接口起到了拯救作用,避免了这种需要。
还有两个问题有待解决,由合成BarClass
型解决。New Bar()
不会编译,因为创建接口实例是不合法的。编译器解决了这个问题,它自动将"Bar"替换为"BarClass"。这是[CoClass]属性的实际角色,它提供了与接口关联的类的名称。事件是一个问题,它们是通过dispinterface在COM中实现的。同样是一个单独的接口,在引擎盖下有一个复杂的机制来订阅事件(IConnectionPoint等人)。合成BarClass使它们成为真正的.NET事件。