导入的程序集中的CoClass接口究竟是为了什么



始终使用tlbimp.exe工具导入基本类型库会为每个coclass创建一个接口。例如,IDL描述

interface IFoo : IUnknown
{
HRESULT DoSomething();
}
coclass Bar
{
[default] interface IFoo;
}

结果在:

  • 接口CCD_ 3作为COM接口的表示
  • 类CCD_ 4作为COM类的表示
  • 接口Bar,用CoClassAttribute进行注释

其中BarIFoo的GUID相等。MSDN在这个主题上声明:

此接口与coclass的默认接口具有相同的IID。使用此接口,客户端可以始终注册为事件接收器。

这是我在这个话题上唯一找到的东西。我知道,由于CoClassAttribute,我可以使用该接口来创建实际类的实例。我还知道(实际上)我可以简单地使用BarClass来创建该类的一个新实例。我不明白的是,为什么导入过程会生成Bar接口,即使coclass没有定义事件源,因此没有事件接收器可以连接到它

在这个例子中,是否可以删除Bar接口1,或者是否存在我尚未考虑的其他风险?

1例如,通过分解互操作程序集

您弄错了名称,这无助于理解发生了什么。类型库中的Barcoclass生成了一个Bar接口和一个BarClass类,没有"FooBar"。

这只是类型库自动生成的额外胶水,使移植代码变得更容易。对于VB6代码特别重要的是,它在COM对象模型方面有很多自由度。VB6程序使用一个coclass,就好像它是一个带有实现的真实类一样。COM中不存在这样的东西,coclass是类的不透明占位符,它是完成所有工作的接口。VB6从不支持接口的概念,因此不可能在代码中直接建模COM。

VB6编译器本身从代码中的Class关键字生成一个coclass,并生成一个携带实际方法和属性的接口。该接口是隐藏的,它与类的名称相同,但带有前导下划线。按照惯例,这会导致对象浏览器隐藏界面。因此,当用VB6编写Barcoclass时,它将生成一个_Bar接口。

因此,转换后的VB6程序将在任何地方使用Bar。除非将"Bar"替换为"IFoo",否则这不会编译。合成的Bar接口起到了拯救作用,避免了这种需要。

还有两个问题有待解决,由合成BarClass型解决。New Bar()不会编译,因为创建接口实例是不合法的。编译器解决了这个问题,它自动将"Bar"替换为"BarClass"。这是[CoClass]属性的实际角色,它提供了与接口关联的类的名称。事件是一个问题,它们是通过dispinterface在COM中实现的。同样是一个单独的接口,在引擎盖下有一个复杂的机制来订阅事件(IConnectionPoint等人)。合成BarClass使它们成为真正的.NET事件。

最新更新