c# How to get added events?

2019-05-09 11:01发布

问题:

I am sitting infront of my pc wondering how to get all added events. I just read some articles including A C# Bedtime Story to better understand events and I think that I got the main idea now. But still I couldn't figure out how to get the List of methods/delegates that are executed if an event is fired. Actually in my case it'd be enough if I knew if any method/delegate is assigned to a certain event. for example: I am using Gma.UserActivityMonitor (for keyboard/mouse-hooking) Now I want to know if the event HookManager.KeyUp event is not null. If it is null a delegate shout be added. In my case this one \/

HookManager.KeyUp += new KeyEventHandler(HookManager_KeyUp);

Edit

example code

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 Gma.UserActivityMonitor;

namespace EventTest 
{ 
    public partial class Form1 : Form 
    { 
        public Form1() 
        { 
            InitializeComponent();             
            HookManager.KeyUp += new KeyEventHandler(HookManager_KeyUp);
            Delegate[] a = GetEventSubscribers(button1, "Click");
            label1.Text = a[0].Method.ToString();
        } 
        void HookManager_KeyUp(object sender, KeyEventArgs e) 
        {         
            /* Do something*/     
        } 
        bool NoEventAttached() 
        { 
            return false; 
        }

        public static Delegate[] GetEventSubscribers(object target, string eventName) 
        { 
            Type t = target.GetType(); 
            var eventInfo = t.GetEvent(eventName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); 

            do 
            { 
                FieldInfo[] fia = t.GetFields(
                    BindingFlags.Static | 
                    BindingFlags.Instance | 
                    BindingFlags.NonPublic); 

                foreach (FieldInfo fi in fia) 
                { 
                    if (fi.Name == eventName) 
                    { 
                        Delegate d = fi.GetValue(target) as Delegate;                         
                        if (d != null)                         
                            return d.GetInvocationList(); 
                    } 
                    else if (fi.FieldType == typeof(EventHandlerList)) 
                    { 
                        ----> var obj = fi.GetValue(target) as EventHandlerList; 
                        var eventHandlerFieldInfo = obj.GetType().GetField("head", BindingFlags.Instance | BindingFlags.NonPublic); 
                        do 
                        { 
                            var listEntry = eventHandlerFieldInfo.GetValue(obj); 
                            var handler = listEntry.GetType().GetField("handler", BindingFlags.Instance | BindingFlags.NonPublic); 
                            if (handler != null) 
                            { 
                                var subD = handler.GetValue(listEntry) as Delegate; 
                                if (subD.GetType() != eventInfo.EventHandlerType) 
                                { 
                                    eventHandlerFieldInfo = listEntry.GetType().GetField("next", BindingFlags.Instance | BindingFlags.NonPublic); 
                                    obj = listEntry as EventHandlerList; <-----------
                                    continue; 
                                } 
                                if (subD != null) 
                                { 
                                    return subD.GetInvocationList(); 
                                } 
                            } 
                        } 
                        while (eventHandlerFieldInfo != null);                 
                    } 
                } 
                t = t.BaseType; 
            } while (t != null);          
            return new Delegate[] { }; 
        }

        private void button1_Click(object sender, EventArgs e)
        {

        }

        private void button1_MouseClick(object sender, MouseEventArgs e)
        {

        }


    } 
}

回答1:

Take note to this console application, and specifically the line calling GetInvocationList(). That method returns the list of delegates attached. Each Delegate has a Method property. Each Method property has a Name.

Delegate is Owned by You

internal class Program
{
    public event EventHandler CheckInvocationList;

    private static void Main(string[] args)
    {
        Program p = new Program();
        p.CheckInvocationList += new EventHandler(p_CheckInvocationList);
        p.Method1();

        Console.WriteLine(string.Join(" | ", p.CheckInvocationList.GetInvocationList().Select(d => d.Method.Name).ToArray()));
    }

    static void p_CheckInvocationList(object sender, EventArgs e)
    {
        throw new NotImplementedException();
    }

    public void Method1()
    {
        this.CheckInvocationList += new EventHandler(Program_CheckInvocationList);
    }

    void Program_CheckInvocationList(object sender, EventArgs e)
    {
        throw new NotImplementedException();
    }
}

Delegate is NOT Owned by You

Ok, this gets a little messy, but it gets you the answer you want. Even if the internal implementation uses an EventHandlerList (which is somewhat common), but I cannot gaurantee it would work in absolutely every scenario because there can be so many different internal representations.

However, hopefully this will work for you. As you can see in the example I'm using the BackgroundWorker class as my example class for getting the invocation list for a specific event I do not own.

using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

internal class Program
{
    private static void Main(string[] args)
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.DoWork += new DoWorkEventHandler(worker_DoWork2);
        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);

        Console.WriteLine(string.Join(" | ", GetEventSubscribers(worker, "DoWork").Select(d => d.Method.Name).ToArray()));
    }

    static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        throw new NotImplementedException();
    }

    static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        throw new NotImplementedException();
    }

    static void worker_DoWork2(object sender, DoWorkEventArgs e)
    {
        throw new NotImplementedException();
    }

    static void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        throw new System.NotImplementedException();
    }

    public static Delegate[] GetEventSubscribers(object target, string eventName)
    {
        Type t = target.GetType();
        var eventInfo = t.GetEvent(eventName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);

        do
        {
            FieldInfo[] fia = t.GetFields(
                 BindingFlags.Static |
                 BindingFlags.Instance |
                 BindingFlags.NonPublic);

            foreach (FieldInfo fi in fia)
            {
                if (fi.Name == eventName)
                {
                    Delegate d = fi.GetValue(target) as Delegate;
                    if (d != null)
                        return d.GetInvocationList();
                }
                else if (fi.FieldType == typeof(EventHandlerList))
                {
                    dynamic obj = fi.GetValue(target) as EventHandlerList;
                    var eventHandlerFieldInfo = obj.GetType().GetField("head", BindingFlags.Instance | BindingFlags.NonPublic);
                    do
                    {
                        var listEntry = eventHandlerFieldInfo.GetValue(obj);
                        var handler = listEntry.GetType().GetField("handler", BindingFlags.Instance | BindingFlags.NonPublic);
                        if (handler != null)
                        {
                            var subD = handler.GetValue(listEntry) as Delegate;
                            if (subD.GetType() != eventInfo.EventHandlerType)
                            {
                                eventHandlerFieldInfo = listEntry.GetType().GetField("next", BindingFlags.Instance | BindingFlags.NonPublic);
                                obj = listEntry;
                                continue;
                            }
                            if (subD != null)
                            {
                                return subD.GetInvocationList();
                            }
                        }
                    }
                    while (eventHandlerFieldInfo != null);
                }
            }

            t = t.BaseType;
        } while (t != null);

        return new Delegate[] { };
    }
}

Finally, though I made some pretty big modifications to the code, I have to give credit to Bob Powell for getting me started on this.



回答2:

I believe that simply comparing HookManager.KeyUp to null will give you your answer.

Other than that, though, unless things have changed since last I looked into it (quite possible) it's rather difficult to get an actual list of the delegates associated with an event. But if the value is null, that tells you that no delegates are associated with it.