.net – Handling VB.NET events in VB6 code


I have some VB6 code that instantiates a class which handles events that are being raised from a VB.NET component. The VB6 is pretty straightforward:

private m_eventHandler as new Collection


public sub InitSomething()
  dim handler as EventHandler

  set handler = new EventHandler
  m_eventHandler.Add handler

end sub 

Note that the event handler object has to live beyond the scope of the init method (which is why it is being stored in a Collection). Note also that m_engine.Start indicates the point in the program where the VB.NET component would start raising events.

The actual event handler (as requested):

Private WithEvents m_SomeClass As SomeClass
Private m_object as Object

Private Sub m_SomeClass_SomeEvent(obj As Variant)
    Set obj = m_object
End Sub

Note that m_object is initialized when an instance of EventHandler is created.

The VB.NET code which raises the event is even simpler:

Public ReadOnly Property SomeProp() As Object
        Dim obj As Object
        obj = Nothing
        RaiseEvent SomeEvent(obj)
        SomeProp = obj
    End Get
End Property

My problem is that when I debug the VB6 program, the first time InitSomething gets called, the event will not be handled (the VB6 event handler is never entered). Subsequent calls to InitSomething does work.

Everything works as I would have expected when I run the program outside the debugger. At this point, I'm not even sure if this is something I should be worried about.

It may or may not be relevant but the VB.NET was converted from a VB6 using the Visual Studio code conversion tool (and subsequently manually cleaned up).

Best Solution

I've found that if you are writing .Net Components for Consumption in VB6 (or any other COM environment) the utilisation of Interfaces is absolutely criticial.

The COM templates that comes out of the box with VStudio leave a lot to be desired especially when you are trying to get Events to work.

Here's what I've used.

Imports System.Runtime.InteropServices
Imports System.ComponentModel

<InterfaceType(ComInterfaceType.InterfaceIsDual), Guid(ClientAction.InterfaceId)> Public Interface IClientAction
        <DispId(1), Description("Make the system raise the event")> sub SendMessage(ByVal theMessage As String)
    End Interface

    <InterfaceType(ComInterfaceType.InterfaceIsIDispatch), Guid(ClientAction.EventsId)> Public Interface IClientActionEvents
        <DispId(1)> Sub TestEvent(ByVal sender As Object, ByVal e As PacketArrivedEventArgs)
    End Interface

    <ComSourceInterfaces(GetType(IClientActionEvents)), Guid(ClientAction.ClassId), ClassInterface(ClassInterfaceType.None)> _
    Public Class ClientAction
        Implements IClientAction

        Public Delegate Sub TestEventDelegate(ByVal sender As Object, ByVal e As PacketArrivedEventArgs)

        Public Event TestEvent As TestEventDelegate

    public sub New()
        //Init etc
    end sub

    public sub SendMessage(theMessage as string) implements IClientAction.SendMessage
    end sub 

        Protected Sub onSendMessage(message as string)
            If mRaiseEvents Then
                RaiseEvent TestEvent(Me, New PacketArrivedEventArgs(theMessage))
            End If
        End Sub

    end Class

I've been able to get COM and .Net consumers of the Assembly/Component to work properly with events and be able to debug in and out of the component.

Hope this helps.

Related Question