在 VB6 中通过 COM 处理在 .NET 类上公开的事件

Posted

技术标签:

【中文标题】在 VB6 中通过 COM 处理在 .NET 类上公开的事件【英文标题】:Handling events exposed on a .NET class via COM in VB6 【发布时间】:2011-02-15 12:52:33 【问题描述】:

我的测试 .NET(在编译器设置中为互操作注册的类库)代码:

Imports System.Runtime.InteropServices

<InterfaceType(ComInterfaceType.InterfaceIsIDispatch), ComVisible(True)> _
Public Interface MyEventInterface
    <DispId(1)> Event Exploded(ByVal Text As String)
    <DispId(2)> Sub PushRedButton()
End Interface


<ClassInterface(ClassInterfaceType.None)> _
Public Class EventTest
    Implements MyEventInterface

    Public Event Exploded(ByVal Text As String) Implements MyEventInterface.Exploded

    Public Sub PushRedButton() Implements MyEventInterface.PushRedButton

        RaiseEvent Exploded("Bang")

    End Sub

End Class

我的测试VB6应用程序winforms代码(引用了上面的类库):

Public ct As New ComTest1.EventTest

Private Sub Command1_Click()

    ct.add_Exploded (ExplodedHandler)

    ct.PushRedButton

    ct.remove_Exploded (ExplodedHandler)

End Sub

Private Sub ExplodedHandler(ByVal Text As String)

    MsgBox Text

End Sub

特别是我不确定如何在 VB6 中设置处理程序,我得到的编译错误是 VB6 中这一行的“Argument not optional”:

ct.add_Exploded (ExplodedHandler)

【问题讨论】:

你的 add_Exploded 声明在哪里? COM 属性创建了它。即在 VB6 中智能感知 add_ 和 remove_ 由于我相信的 Idispatch 接口而存在? 【参考方案1】:

C#

[ComVisible(true)] //Exposed
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] //Our managed interface will be IDispatch
public interface IMathEvents


    void OnOperationCompleted(string message);


[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IMathEvents))]  //Our event source is IMathEvents interface
[ComDefaultInterface(typeof(IMath))]
public class Math:IMath  /*IMath interface just declares a method named Add */

    public int Add(int x, int y)
    
        if (null != this.OnOperationCompleted)
            this.OnOperationCompleted("Operation completed, result: " + (x+y).ToString());
        return x + y;
    

    [ComVisible(false)]
    public delegate void OperationCompletedDel(string message); //No need to expose this delegate
    public event OperationCompletedDel OnOperationCompleted;


[ComVisible(true)]
public interface IMath

    int Add(int x, int y);

vb

Private WithEvents m As Math

私有子Form_Load()

Set m = New PayClient.Math

结束子

Private Sub m_OnOperationCompleted(ByVal Text As String)

MsgBox Text

结束子

私有子 Command2_Click() m.加1, 2

结束子

【讨论】:

【参考方案2】:

.NET 中的事件使用&lt;ComSourceInterfaces(GetType(接口名称))&gt; 和VB6 中的WithEvents

.NET 类库:

Imports System.Runtime.InteropServices

' This interface is to expose the events
<Guid("28C7DCE1-90EF-4a30-AF7F-4187F9FFFDEB")> _
<InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface MathsEvents
    <DispId(1)> _
    Sub Calculated(ByVal Result As Double)
End Interface

' This interface is to expose the properties and methods
<Guid("86CE5E8D-777D-4cd5-8A7D-7F58737F1DB4")> _
<InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface _Maths
    <DispId(2)> _
    Property ValueA() As Double
    <DispId(3)> _
    Property ValueB() As Double
    <DispId(4)> _
    ReadOnly Property Result() As Double
    <DispId(5)> _
    Sub Add()
End Interface

' This is the actual class
' The events are exposed by using the ComSourceInterfaces attribute
' The properties and methods are exposed using the Implements keyword
<Guid("C58721B1-15B3-4eeb-9E1E-BCDA33D38EE6")> _
<ClassInterface(ClassInterfaceType.None)> _
<ComSourceInterfaces(GetType(MathsEvents))> _
Public Class Maths
    Implements _Maths
    Public Event Calculated(ByVal Result As Double)
    Private mValueA As Double
    Private mValueB As Double
    Private mResult As Double

    Public Property ValueA() As Double Implements _Maths.ValueA
        Get
            Return mValueA
        End Get
        Set(ByVal value As Double)
            mValueA = value
        End Set
    End Property

    Public Property ValueB() As Double Implements _Maths.ValueB
        Get
            Return mValueB
        End Get
        Set(ByVal value As Double)
            mValueB = value
        End Set
    End Property

    Public ReadOnly Property Result() As Double Implements _Maths.Result
        Get
            Return mResult
        End Get

    End Property

    Public Sub New()
        mValueA = 0
        mValueB = 0
        mResult = 0
    End Sub

    Public Sub Add() Implements _Maths.Add
        mResult = mValueA + mValueB
        RaiseEvent Calculated(mResult)
    End Sub

End Class

VB6 测试应用:

Private WithEvents calc As Maths

Private Sub btnAdd_Click()

   calc.ValueA = CDbl(txtValueA.Text)
   calc.ValueB = CDbl(txtValueB.Text)
   calc.Add

End Sub

Private Sub calc_Calculated(ByVal Result As Double)
   txtResult.Text = CStr(Result)
End Sub

Private Sub Form_Load()

   Set calc = New Maths

End Sub

【讨论】:

有谁知道是否有可能只用一个接口来处理事件和属性/方法? _MathsComInterfaceType.InterfaceIsIDispatch,所以它不应该只能通过后期绑定来使用吗?在示例中用作早期绑定 - 还是我错了?

以上是关于在 VB6 中通过 COM 处理在 .NET 类上公开的事件的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中通过远程处理获取外部 IP 地址

如何在vb6中注册一个不能用作com互操作的.net DLL?

我可以将 .NET 5 COM 互操作对象与 VB6 连接起来吗?

如何在C#中通过SQL从SAP数据库读取数据

在 .NET 中通过注入将对象传递给数组

如何在 VB6 中将连接字符串评估为索引 XPath 表达式