Handling events exposed on a .NET class via COM in

2019-01-22 17:17发布

问题:

Handling events exposed on a .NET class via COM in VB6

My test .NET (class libary registered for interop in compiler settings) code:

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

My test VB6 application winforms code (which references the above class libary):

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

Specifially I'm not sure how to set up the handler in VB6 the compile error I get is "Argument not optional" on this line in the VB6:

ct.add_Exploded (ExplodedHandler)

回答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

Private Sub Form_Load()

Set m = New PayClient.Math

End Sub

Private Sub m_OnOperationCompleted(ByVal Text As String)

MsgBox Text

End Sub

Private Sub Command2_Click()
m.Add 1, 2

End Sub



回答2:

Use <ComSourceInterfaces(GetType(the interface name))> for the events in .NET and WithEvents in VB6

.NET class libary:

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 test application:

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