Raising events in a class library exposed to COM

2019-02-20 16:49发布

I'm trying to write a wrapper to a service, which will be used by an existing VB6 project. I've got most of the basic framework working, except for one important aspect: I can reference the wrapper in a VB6 project and subs/function calls etc. work as expected, but events do not. The events are visible in the VB6 app, but they never fire.

VB.NET Code:

Public Event Action_Response(ByVal Status as String)
Public Function TestEvent()
    RaiseEvent Action_Response("Test Done")
    Return "Done"
End Function

VB6 Code:

Dim WithEvents my_Wrapper as Wrapper_Class
Private Sub cmdTest_Click()
    Set my_Wrapper = New Wrapper_Class
    Debug.Print my_Wrapper.TestEvent() 
End Sub

Private Sub my_Wrapper_Action_Response(ByVal Status As String)
    Debug.Print Status
    Set my_Wrapper = Nothing
End Sub

So, the cmdTest button code prints 'Done' as expected, but the Action_Response event doesn't fire. Is there something else do I need to do to get the event to fire?

1条回答
小情绪 Triste *
2楼-- · 2019-02-20 17:50

Its too much to write in a comment, so I'll make it an answer....

First, identify the .net class you want to expose to COM. I'll pick a class called CORE.

Create an interface that describes the EVENTS that the CORE object will source (ie generate).

<ComVisible(True)> _
<Guid("some guid here...use guidgen, I'll call it GUID1")> _
<InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface ICoreEvents
    <System.Runtime.InteropServices.DispId(1)> _
    Sub FileLoaded(ByVal Message As String)
End Interface

Next, Create an interface for the COM exposed properties and methods of your class.

<ComVisible(True)> _
<Guid("another GUID, I'll call it guid2")> _
<InterfaceType(ComInterfaceType.InterfaceIsDual)> _
Public Interface ICore
    ReadOnly Property Property1() As Boolean
    ReadOnly Property AnotherProperty() As ISettings
    ReadOnly Property Name() As String
    ReadOnly Property Phone() As String
End Interface

Now, create your actual .net class

<ComVisible(True)> _
<ClassInterface(ClassInterfaceType.None)> _
<ComDefaultInterface(GetType(ICore))> _
<ComSourceInterfaces(GetType(ICoreEvents))> _
<Guid("a third GUID, I'll call it GUID3")> _
Public Class Core
    Implements ICore

    <System.Runtime.InteropServices.ComVisible(False)> _
    Public Delegate Sub OnFileLoaded(ByVal Message As String)
    Public Event FileLoaded As OnFileLoaded
End Class

Now, when you need to raise the FileLoaded event, just RAISEEVENT FILELOADED(Message) from within your class. .NET will forward the event out to COM because you've hooked up the COMSourceInterfaces attribute.

The attribute is shorthand for much of of this, but unfortunately doesn't give you quite the control that you need to do certain things (for instance retain version compatibility on your com interfaces).

查看更多
登录 后发表回答