6

我在 C# 4.0 中编写了一个 COM 可见的类库,我正在使用 VB6。事情有效,只有当我打开 VB6对象浏览器并查看暴露的成员时,我才会看到每个暴露成员的事件......但 C# 代码没有定义它们中的任何一个

这是正常的吗?难道我做错了什么?

[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IMyClass))]
public class MyClass : IMyClass
{
    public void DoSomething(string someParam)
    {
        ...
    }
}

public interface IMyClass
{
    void DoSomething(string someParam);
}

该程序集使用强名称密钥签名并设置AssemblyInfo.cs[assembly: ComVisible(true)]属性,但我不确定它与问题有什么关系。

当我查看 VB6 中的对象浏览器时,我希望看到DoSomething(string)的成员MyClass我确实看到了,但是我看到每个公开的方法都有一个匹配签名的事件,比如Event DoSomething(someParam As String)作为MyClass.

更令人费解的是(至少对我而言),属性也有一个“匹配”事件(虽然只能从小闪电图标中看出)——如果MyClass定义了这样的属性:

public string SomeProperty { get; set; }

VB6 对象浏览器会说“事件”被定义为Property SomeProperty As String,这让我大吃一惊——“属性”是如何 1) 被复制的,以及 2) 复制品如何在对象浏览器中以“事件”图标显示?这同样适用于 get-only 属性,它们具有只读的“属性/事件”对应项。

这些事件来自哪里,我该如何摆脱它们?

更新一张图片值一千字:

COM 互操作 - 虚假事件

UPDATE错误的事情ComSourceInterfaces错误地被用来代替属性的ComDefaultInterface属性。将前者换成后者给出了预期的结果:

COM 互操作 - 正确的成员

4

2 回答 2

8

通过typeof(IMyClass)作为参数传递给 ComSourceInterface 属性,您是在说 IMyClass 中的所有内容都是一个事件。

如果您不希望类的事件接口删除 ComSourceInterface 属性。

如果您确实想将 C# 类中的事件公开给 VB,请执行以下操作:

当您创建一个 COM 可见类时,您还需要创建一个只为您的类定义事件处理程序的接口。您的类应该用 COMSourceInterface 来装饰,指定您的事件处理程序接口,并且应该定义您的事件并实现事件处理程序接口。有关另一个示例,请参见如何:引发由 COM 接收器处理的事件。

[GuidAttribute("1A585C4D-3371-48dc-AF8A-AFFECC1B0967") ]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface MyEvents
{
    void ConnectedEvent(string state);
}


[ComSourceInterfaces(typeof(MyEvents))]
public class MyClass
{
    public event Action<string> ConnectedEvent;

    public MyClass() { }

    public void DoSomething(string state)
    { 
        if (ConnectedEvent != null)
            ConnectedEvent(state);
    }
}

另请参阅:Murat 的角落:暴露 COM 事件

于 2013-05-17T03:29:43.190 回答
8

您基本上会发现 COM 中的事件并没有什么特别之处。像 COM 中的任何东西一样,事件由接口支持。指定事件方法的接口的唯一特别之处是它在类型库中用 [source] 属性标记。这就是 [ComSourceInterfaces] 属性所做的一切,由 Tlbexp.exe 在生成类型库时识别。

COM 中的属性也没有什么特别之处。它们的工作方式就像在 .NET 中一样,它们是通过方法实现的。一个 getter 和一个 setter 方法。

因此,VB6 会查看您的类型库,并且对具有事件的类感到满意,因为它具有带有 [source] 属性的接口。并且很高兴该接口具有方法,它们可以拥有的所有方法,因此它假定这些方法是在引发事件时运行的方法。认识到这些方法也是属性的访问器是不够聪明的,它假定类型库作者知道他在做什么。

事件在 COM 中称为“连接点”。谷歌 IConnectionPoint 了解更多信息。如果您曾经使用自定义事件访问器创建过 WinRT 组件,那么您还会发现 COM 事件与 .NET 事件几乎没有共同之处。

Anyhoo,解决方法很简单,只在引发事件时使用 [ComSourceInterface]。

于 2013-05-17T09:47:07.030 回答