Reputation: 660
I'm looking for a way to handle close event and fetch one return parameter.
I can't change the way that WinFormApp.dll
is being run.
Private Sub ShowWinFormApp() Handles Button1.Click
' launching new WinForm app from within another app
Dim InvTrack As System.Reflection.Assembly = System.Reflection.Assembly.Load(File.ReadAllBytes("\\NetworkPath\WinFormApp.dll"))
Dim oType As System.Type
Dim pControl As System.Object
Dim Params As New List(Of Object)
Params.Add(Param1)
Params.Add(Param2)
oType = InvTrack.GetType("WinFormApp.FrmMain")
pControl = Activator.CreateInstance(oType, Params)
'here i'd like to add handler to catch my event
AddHandler pControl.ImDone, AddressOf ReLaunch
'this not working, saying that Element `ImDone` is not an event of element `Object`
Application.Run(pControl)
End Sub
In WinFormApp
I tried like this:
Public Class FrmMain
Public Event ImDone As EventHandler(Of ImDoneEventArgs)
Public Sub Test() Handles Button1.Click
RaiseEvent ImDone (Me, New ImDoneEventArgs With {.RetVal = 54})
Application.Exit()
End Sub
Public Class ImDoneEventArgs
Inherits EventArgs
Public Property RetVal As Integer
End Class
End class
Upvotes: 1
Views: 74
Reputation: 32223
An example, assuming the code you have posted matches the real scenario.
You cannot use AddHandler
when the target event and the Type of its provider are unknown in the current assembly. Activator.CreateInstance()
returns an object
Type that only exposes its basic methods.
You can cast the object to its base class, the Form class. This Type is known to both assemblies. Of course, the base class doesn't expose custom events, but you can use call its ShowDialog()
method to present the Form.
You cannot call Application.Run()
directly if a message loop is already running. But you don't need to, ShowDialog()
already does that for you, in a compatible way.
To create an event handler for the custom event, you can again use Reflection to get the related EventInfo, associate an EventHandler to the method that is called when the event is raised, then call Delegate.CreateDelegate() passing the [EventInfo].EventHandlerType and the handler's method Target, to generate a compatible delegate.
Now you can add the event handler to an event of your instance of the FrmMain
object, calling [EventInfo].AddEventHandler(), passing the object that provides the event (the FrmMain
object) and the event delegate:
Dim FrmMain As Form = Nothing
Dim FrmMainEvent As EventInfo = Nothing
Dim _EventDelegate As [Delegate] = Nothing
Dim _EventHandler As EventHandler(Of EventArgs) = Sub(s, e) ReLaunch(s, e)
Dim asm As Assembly = Assembly.Load(File.ReadAllBytes("WinFormApp.dll"))
Dim formType = asm.GetType("WinFormApp.FrmMain")
If formType Is Nothing Then Throw New Exception("FrmMain Type not found")
Dim instance = Activator.CreateInstance(formType, {Param1, Param2})
If instance IsNot Nothing Then
FrmMain = DirectCast(instance, Form)
FrmMainEvent = instance.GetType().GetEvent("ImDone")
If FrmMainEvent IsNot Nothing Then
_EventDelegate = [Delegate].CreateDelegate(
FrmMainEvent.EventHandlerType, _EventHandler.Target, _EventHandler.Method
)
FrmMainEvent.AddEventHandler(instance, _EventDelegate)
End If
FrmMain.ShowDialog()
End If
As a note, you could also use an Action delegate Type, which could simplify your code a little.
When the event is raised, the specified delegate is called.
You should remove the event handler at this point, calling [EventInfo].RemoveEventHandler(), passing the instance of the object that provided the event (the FrmMain
instance you have generated) and the delegate that was associated to the event.
The EventArgs object is also a custom Type, so you can again retrieve the value of its Properties via Reflection:
I'm not sure for what purpose the code in this event handler serves. The Form is set to null (Nothing
) just because you may want to test its existence later. You may have closed it explicitly or disposed of it somewhere. Checking whether it's disposed may not give a reliable result
Public Sub ReLaunch(sender As Object, e As EventArgs)
If FrmMainEvent IsNot Nothing AndAlso _EventDelegate IsNot Nothing Then
FrmMainEvent.RemoveEventHandler(FrmMain, _EventDelegate)
End If
Debug.WriteLine(e.GetType().GetProperty("RetVal").GetValue(e))
_EventDelegate = Nothing
FrmMainEvent = Nothing
FrmMain = Nothing
End Sub
Upvotes: 1