Home > Enterprise >  How to capture arguments returned by dll events (events are subscribed using Reflection)?
How to capture arguments returned by dll events (events are subscribed using Reflection)?

Time:01-11

I have a winform application(WindowsFormsApplication2) that loads a dll using appdomain. In the winform, I have suscribed to 'TestEvent' implemented in ClassLibrary.dll. If the TestEvent returns an argument,how can I capture the returned argument in the event handler HandleEvent implemented in winform?

This is the winform application codes.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Diagnostics;
using ClassLibrary1;
using static System.Net.Mime.MediaTypeNames;

namespace WindowsFormsApplication2
{
  
    [Serializable]
    public partial class Form1 : Form
    {
        void HandleEvent(object sender, EventArgs e)
        {
            Debug.WriteLine("HandleEvent called");
        }
        string DLL = @"..\ConsoleApplication1\ClassLibrary1\bin\Debug\ClassLibrary1.dll";

        public Form1()
        {
            InitializeComponent();
            Loader.Call( DLL, "ClassLibrary1.Class1", "RaiseEvent", HandleEvent, DateTime.Now.ToShortDateString());

        }

        private void button1_Click(object sender, EventArgs e)
        {
            Application.Restart();
            Application.Run(new Form1());
            this.Close();
        }
     
    }

    public class Loader : MarshalByRefObject
    {
        AppDomain ad = AppDomain.CreateDomain("Test");
        object CallInternal(string dll, string typename, string method, EventHandler handler, object[] parameters)
        {
            Assembly a = Assembly.LoadFile(dll);
            object o = a.CreateInstance(typename);
            Type t = o.GetType();

            // Subscribe to the event
            EventInfo eventInfo = t.GetEvent("TestEvent");
            eventInfo.AddEventHandler(o, handler);

            MethodInfo m = t.GetMethod(method);
            return m.Invoke(o, parameters);
        }

        public static object Call( string dll, string typename, string method, EventHandler handler, params object[] parameters)
        {
            Loader ld = (Loader)ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(Loader).FullName);
            object result = ld.CallInternal(dll, typename, method, handler, parameters);
            AppDomain.Unload(ad);
            return result;
        }
    }
}

This is the ClassLibrary1.dll codes

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClassLibrary1
{
    [Serializable]
    public class Class1
    {
        public event EventHandler TestEvent;

        public int RaiseEvent(string msg)
        {
            try
            {
                TestEvent(this, EventArgs.Empty);
            }
            catch (Exception ex)
            {
                Console.WriteLine("the exception is: "   ex.ToString());
                if (ex.InnerException != null)
                {
                    Console.WriteLine("the inner exception is: "   ex.InnerException.Message.ToString());
                }
            }
            return 2;
        }

    }
}

CodePudding user response:

You can use something like this:

        void HandleEvent(object sender, EventArgs e)
        {
            Debug.WriteLine("HandleEvent called");
        }

        string DLL = @"..\ConsoleApplication1\ClassLibrary1\bin\Debug\ClassLibrary1.dll";    
        //You can can create new appDomain: var dom = AppDomain.CreateDomain("domain name");//If you really need it!
        var dom = AppDomain.CurrentDomain;
        var assembly = dom.Load(DLL);

        var type = assembly.GetTypes().FirstOrDefault(p => p.FullName == "ClassLibrary1.Class1");
        var inst = Activator.CreateInstance(type);
        var eventInfo = type.GetEvent("event name");
        var handleEventMethod = GetType().GetMethod("HandleEvent");
        Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, type, handleEventMethod);
        eventInfo.AddEventHandler(inst, handler);
        
        var method = type.GetMethod("RaiseEvent");
        var resultData = (int)method.Invoke(inst, new object[]{"Expecting argument of your method"});

How do I use reflection to call a generic method?

Invoke a method of anonymous class

Subscribe to an event with Reflection

Invoke static methods

CodePudding user response:

As I understand it, your want your HandleEvent method to be able to consume or produce some custom value that we'll call Argument. In this case, the outcome can be achieved by inheriting EventArgs for a custom event.

public class Class1
{
    public event ValueReceivedEventHandler TestEvent;

    public int RaiseEvent(string msg)
    {
        try
        {
            TestEvent(this, EventArgs.Empty);
        }
        catch (Exception ex)
        {
            Console.WriteLine("the exception is: "   ex.ToString());
            if (ex.InnerException != null)
            {
                Console.WriteLine("the inner exception is: "   ex.InnerException.Message.ToString());
            }
        }
        return 2;
    }
}

Custom event class

public delegate void ValueReceivedEventHandler(Object sender, ValueReceivedEventArgs e);
public class ValueReceivedEventArgs : EventArgs
{
    public object Argument { get; set; }
}

Then you can handle event in one of these ways:

void HandleEvent(object sender, EventArgs e)
{
     if(e is ValueReceivedEventArgs ePlus)
     {
          Debug.WriteLine(ePlus.Argument.ToString());
     }
}


void HandleEvent(object sender, ValueReceivedEventArgs e)
{
    Debug.WriteLine(e.Argument.ToString());
}

Please leave me a comment if this is way off from what you're trying to achieve.

  • Related