lundi 24 octobre 2016

vb.net dll reflection event

I'm trying to pass a user defined event argument class from a dll to my main program. Both have the event argument class defined, but when I try to bind the event delegate to the method it won't bind because its signature is not compatible. I've stripped the code down to the main problem.

The code in the dll raises an event called ValueChange with a ValueEventArgs as argument:

Public Class Main
  Public Event ValueChange(ByVal sender As System.Object, ByVal e As ValueEventArgs)
  Private _Value As Integer

  Public Sub Up()
    _Value += 1
    RaiseEvent ValueChange(Me, New ValueEventArgs(_Value))
  End Sub
End Class

Public Class ValueEventArgs
  Inherits System.EventArgs
  Public Property Value As Integer

  Public Sub New(ByVal Value As Integer)
    Me.Value = Value
  End Sub
End Class

The Main program loads the dll and binds the event delegate to the method ShowValue:

Imports System.Reflection

Public Class Main
  Private DriverAssembly As [Assembly]
  Private DriverClass As Type
  Private DriverClassInstance As Object

  Private Sub ButtonLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonLoad.Click
    DriverAssembly = [Assembly].Load("reflection_event, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
    DriverClass = DriverAssembly.GetType("ReflectionEventDll.Main")
    DriverClassInstance = Activator.CreateInstance(DriverClass)

    ' get the handler method
    Dim Method As MethodInfo = Me.GetType.GetMethod("ShowValue")

    ' get the event and create a delegate
    Dim ValueChangeEvent As EventInfo = DriverClass.GetEvent("ValueChange")
    Dim Handler As [Delegate] = [Delegate].CreateDelegate(ValueChangeEvent.EventHandlerType, Me, Method) ' Fails
    ' Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.

    ' add the event handler
    ValueChangeEvent.AddEventHandler(DriverClassInstance, Handler)
  End Sub

  Private Sub ButtonUp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonUp.Click
    DriverClass.GetMethod("Up").Invoke(DriverClassInstance, Nothing) ' invoke the method on the driver class instance
  End Sub

  Public Sub ShowValue(ByVal sender As Object, ByVal e As ValueEventArgs)
    MessageBox.Show(e.Value.ToString())
  End Sub
End Class

Public Class ValueEventArgs
  Inherits System.EventArgs
  Public Property Value As Integer

  Public Sub New(ByVal Value As Integer)
    Me.Value = Value
  End Sub
End Class

If I remove the creation of the delegate and the AddEventHandler everything works without a problem, without the event of course.

Funny thing, if I change the arguments of ShowValue method in the main program everything suddenly works, including the event.

Public Sub ShowValue(ByVal sender As Object, ByVal e As EventArgs)
  ' works, but the Value is lost
End Sub

It gets better, because it's not completely lost. If I put a breakpoint on the Sub I can see e is containing a property called Value.
A DirectCast also fails, but writing the EventArgs to a Object seems to work.

  Public Sub ShowValue(ByVal sender As Object, ByVal e As EventArgs)
    Dim Obj As Object = e
    MessageBox.Show(Obj.Value.ToString())
  End Sub

It works, but I don't think this is the right way. How can I use a user defined event argument class when handling an event from a dll?





Aucun commentaire:

Enregistrer un commentaire