ICanSpy

A Windows Forms Spy app! Dynamically binds to an assembly and lets you spy on which events are being raised. The .zip file includes an .exe and source.

C# (86.3 KB)
 
 
 
 
 
(0)
2,833 times
Add to favorites
3/1/2011
E-mail Twitter del.icio.us Digg Facebook
using System;
using System.IO;
using System.Text;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using System.Reflection.Emit;
using System.Windows.Forms;
using System.Runtime.Remoting;

namespace EventTestDriver
{
	public class Utils
	{
        public delegate void ReportDelegate(string eventName, object sender, System.EventArgs e);
        static public ReportDelegate FormsDelegate;
		static private RegisteredEventsSet reSet;
		static private Type eventDelegatesClass;
		static private Object eventDelegates;
        static private StreamWriter sw;

		public Utils()
		{
		}

		static private void FillEventsTreeViewFromControl(Control ctl, TreeView tvEvents)
		{
			ControlTreeNode ctn = new ControlTreeNode (ctl);
			tvEvents.Nodes.Add(ctn);

			EventInfo[] eiArray = ctl.GetType().GetEvents();

			foreach (EventInfo ei in eiArray) 
			{
				if (IsMemberBrowsable((MemberInfo) ei))
				{
					string categoryName = CategoryName(ei);
					EventCategoryTreeNode ectn = EventCategoryTreeNode(ctn, categoryName);
					if (ectn == null)
					{
						ectn = new EventCategoryTreeNode(categoryName);
						ctn.Nodes.Add(ectn);
					}
					EventTreeNode etn = new EventTreeNode(ei);
					ectn.Nodes.Add(etn);
				}
			}

			foreach (Control child in ctl.Controls)
			{
				FillEventsTreeViewFromControl(child, tvEvents);
			}
		}

		static public void FillEventsTreeViewFromForm(bool orderByControl, Form form, TreeView tvEvents)
		{
			FillEventsTreeViewFromControl(form, tvEvents);

			if (!orderByControl)
			{
				OrderEventsTreeViewByEvent(tvEvents);
			}
		}

		static public void OrderEventsTreeViewByEvent(TreeView tvEvents)
		{
			TreeView tvTmp = new TreeView();
			foreach (ControlTreeNode ctn in tvEvents.Nodes)
			{
				foreach (EventCategoryTreeNode ectn in ctn.Nodes)
				{
					EventCategoryTreeNode ectnNew = EventCategoryTreeNode(tvTmp, ectn.Text);
					if (ectnNew == null)
					{
						ectnNew = new EventCategoryTreeNode(ectn.Text);
						tvTmp.Nodes.Add(ectnNew);
					}
					foreach (EventTreeNode etn in ectn.Nodes)
					{
						EventTreeNode etnNew = EventTreeNode(ectnNew, etn.EventInfo);
						if (etnNew == null)
						{
							etnNew = new EventTreeNode(etn.EventInfo);
							ectnNew.Nodes.Add(etnNew);
						}
						ControlTreeNode ctnNew = new ControlTreeNode(ctn.Control);
						ctnNew.Checked = etn.Checked;
						etnNew.Nodes.Add(ctnNew);
					}
				}
			}
			tvEvents.Nodes.Clear();

			foreach (EventCategoryTreeNode ectn in tvTmp.Nodes)
			{
				bool allEventsChecked = true;
				foreach (EventTreeNode etn in ectn.Nodes)
				{
					bool allControlsChecked = true;
					foreach (ControlTreeNode ctn in etn.Nodes)
					{
						if (!ctn.Checked)
						{
							allControlsChecked = false;
							break;
						}
					}
					if (allControlsChecked)
					{
						etn.Checked = true;
					}
					else
					{
						allEventsChecked = false;
					}
				}
				if (allEventsChecked)
				{
					ectn.Checked = true;
				}
			}

			foreach (EventCategoryTreeNode ectn2 in tvTmp.Nodes)
			{
				tvEvents.Nodes.Add((TreeNode) ectn2.Clone());
			}
		}

		static public void OrderEventsTreeViewByControl(TreeView tvEvents)
		{
			TreeView tvTmp = new TreeView();
			foreach (EventCategoryTreeNode ectn in tvEvents.Nodes)
			{
				foreach (EventTreeNode etn in ectn.Nodes)
				{
					foreach (ControlTreeNode ctn in etn.Nodes)
					{
						ControlTreeNode ctnNew = ControlTreeNode(tvTmp, ctn.Control);
						if (ctnNew == null)
						{
							ctnNew = new ControlTreeNode(ctn.Control);
							tvTmp.Nodes.Add(ctnNew);
						}

						EventCategoryTreeNode ectnNew = EventCategoryTreeNode(ctnNew, ectn.CategoryName);
						if (ectnNew == null)
						{
							ectnNew = new EventCategoryTreeNode(ectn.CategoryName);
							ctnNew.Nodes.Add(ectnNew);
						}
						EventTreeNode etnNew = new EventTreeNode(etn.EventInfo);
						etnNew.Checked = ctn.Checked;
						ectnNew.Nodes.Add(etnNew);
					}
				}
			}
			tvEvents.Nodes.Clear();

			foreach (ControlTreeNode ctn in tvTmp.Nodes)
			{
				bool allEventCategoriesChecked = true;
				foreach (EventCategoryTreeNode ectn in ctn.Nodes)
				{
					bool allEventsChecked = true;
					foreach (EventTreeNode etn in ectn.Nodes)
					{
						if (!etn.Checked)
						{
							allEventsChecked = false;
							break;
						}
					}
					if (allEventsChecked)
					{
						ectn.Checked = true;
					}
					else
					{
						allEventCategoriesChecked = false;
					}
				}
				if (allEventCategoriesChecked)
				{
					ctn.Checked = true;
				}
			}

			foreach (ControlTreeNode ctn2 in tvTmp.Nodes)
			{
				tvEvents.Nodes.Add((TreeNode) ctn2.Clone());
			}
		}

		static private EventTreeNode EventTreeNode(EventCategoryTreeNode ectn, EventInfo ei)
		{
			foreach (EventTreeNode etn in ectn.Nodes)
			{
				if (etn.EventInfo.Name == ei.Name)
				{
					return etn;
				}
			}
			return null;
		}

		static private bool IsMemberBrowsable(MemberInfo mi)
		{
			Object[] attributes = mi.GetCustomAttributes(true);
			if(attributes.Length > 0)
			{
				for(int j = 0; j < attributes.Length; j++)
				{
					if (attributes[j] is System.ComponentModel.BrowsableAttribute)
					{
						System.ComponentModel.BrowsableAttribute browsableAttribute = (System.ComponentModel.BrowsableAttribute) attributes[j];
						return browsableAttribute.Browsable;
					}
				}
			}
			return true;			
		}

		static private string CategoryName(MemberInfo mi)
		{
			Object[] attributes = mi.GetCustomAttributes(true);
			if(attributes.Length > 0)
			{
				for(int j = 0; j < attributes.Length; j++)
				{
					if (attributes[j] is System.ComponentModel.CategoryAttribute)
					{
						System.ComponentModel.CategoryAttribute categoryAttribute = (System.ComponentModel.CategoryAttribute) attributes[j];
						return categoryAttribute.Category;
					}
				}
			}
			return "Misc.";
		}

		static private EventCategoryTreeNode EventCategoryTreeNode(ControlTreeNode ctn, string categoryName)
		{
			foreach (EventCategoryTreeNode ectn in ctn.Nodes)
			{
				if (ectn.Text == categoryName)
				{
					return ectn;
				}
			}
			return null;
		}

		static private EventCategoryTreeNode EventCategoryTreeNode(TreeView tvEvents, string categoryName)
		{
			foreach (EventCategoryTreeNode ectn in tvEvents.Nodes)
			{
				if (ectn.Text == categoryName)
				{
					return ectn;
				}
			}
			return null;
		}

		static private ControlTreeNode ControlTreeNode(TreeView tvEvents, Control ctl)
		{
			foreach (ControlTreeNode ctn in tvEvents.Nodes)
			{
				if (ctn.Control == ctl)
				{
					return ctn;
				}
			}
			return null;
		}

        static public bool EventsTreeViewHasCheckedNode(TreeView tvEvents)
        {
            foreach (TreeNode tn in tvEvents.Nodes)
            {
                if (SubTreeHasCheckedNode(tn))
                {
                    return true;
                }
            }
            return false;
        }

        static private bool SubTreeHasCheckedNode(TreeNode tn)
        {
            if (tn.Checked)
            {
                return true;
            }
            foreach (TreeNode tnChild in tn.Nodes)
            {
                if (SubTreeHasCheckedNode(tnChild))
                {
                    return true;
                }
            }
            return false;
        }


        static public void StartListening(Form formTest, 
                                          TreeView tvEvents, 
                                          bool orderedByControl)
        {
            TreeView tvTmp;
            if (orderedByControl)
            {
                tvTmp = new TreeView();
                foreach (TreeNode tn in tvEvents.Nodes)
                {
                    tvTmp.Nodes.Add((TreeNode) tn.Clone());
                }
                OrderEventsTreeViewByEvent(tvTmp);
            }
            else
            {
                tvTmp = tvEvents;
            }

            reSet = new RegisteredEventsSet();

            foreach (EventCategoryTreeNode ectn in tvTmp.Nodes)
            {
                foreach (EventTreeNode etn in ectn.Nodes)
                {
                    foreach (ControlTreeNode ctn in etn.Nodes)
                    {
                        if (ctn.Checked)
                        {
                            EventInfo ei = etn.EventInfo;
                            reSet.AddRegisteredEvent(ei.EventHandlerType, ei.Name, ctn.Control, ei);
                        }
                    }
                }
            }

            eventDelegatesClass = CreateDynamicAssembly (tvEvents, orderedByControl, reSet);

            eventDelegates = Activator.CreateInstance(eventDelegatesClass);

            FieldInfo fi = eventDelegates.GetType().GetField("ReportingDelegate");
            fi.SetValue(eventDelegates, (object) new ReportDelegate(ReportEvent)); //, BindingFlags.Default, null, Thread.CurrentThread.CurrentCulture);

            ArrayList reArray = reSet.RegisteredEvents;
            foreach (RegisteredEvent re in reArray)
            {
                MethodInfo miTmp = eventDelegates.GetType().GetMethod("AttachEvent_" + re.EventID);
                if (miTmp != null)
                {
                    ArrayList eventOwners = re.EventOwners;
                    ArrayList eventInfos = re.EventInfos;
                    Debug.Assert(eventOwners.Count == eventInfos.Count);
                    for (int index=0; index < eventOwners.Count; index++)
                    {
                        Object[] parameters = new Object[2];
                        parameters[0] = eventOwners[index];
                        parameters[1] = eventInfos[index] ;
                        miTmp.Invoke(eventDelegates, parameters);
                    }
                }
            }
        }

		static public void StopListening()
		{
			ArrayList reArray = reSet.RegisteredEvents;
			foreach (RegisteredEvent re in reArray)
			{
				MethodInfo miTmp = eventDelegates.GetType().GetMethod("DetachEvent_" + re.EventID);
				if (miTmp != null)
				{
					ArrayList eventOwners = re.EventOwners;
					ArrayList eventInfos = re.EventInfos;
					Debug.Assert(eventOwners.Count == eventInfos.Count);
					for (int index=0; index < eventOwners.Count; index++)
					{
						Object[] parameters = new Object[2];
						parameters[0] = eventOwners[index];
						parameters[1] = eventInfos[index] ;
						miTmp.Invoke(eventDelegates, parameters);
					}
				}
			}
		}

		static public Type CreateDynamicAssembly(TreeView tvEvents, 
                                                 bool orderedByControl, 
                                                 RegisteredEventsSet reSet)
        {
            AssemblyName assemblyName = new AssemblyName();
            assemblyName.Name = "EventDelegatesEmittedAssembly";

            AssemblyBuilder assembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

            ModuleBuilder module = assembly.DefineDynamicModule("EventDelegatesEmittedModule"); //, "EventDelegatesEmittedModule.mod");

            TypeBuilder delegatesClass = module.DefineType("EventDelegates", TypeAttributes.Public);

            FieldBuilder reportingDelegateField = delegatesClass.DefineField("ReportingDelegate", typeof(Delegate), FieldAttributes.Public);

            ConstructorBuilder constructor = delegatesClass.DefineConstructor(MethodAttributes.Public,
                                                                              CallingConventions.Standard, 
                                                                              new Type[0]);
            ILGenerator constructorIL = constructor.GetILGenerator();
            constructorIL.Emit(OpCodes.Ldarg_0);
            ConstructorInfo superConstructor = typeof(Object).GetConstructor(new Type[0]);
            constructorIL.Emit(OpCodes.Call, superConstructor);
            constructorIL.Emit(OpCodes.Ret);

            ArrayList reArray = reSet.RegisteredEvents;
            foreach (RegisteredEvent re in reArray)
            {
                MethodBuilder method = AddEventHandlerMethod(re, delegatesClass, reportingDelegateField);
                AddAttachOrDetachEventMethod(true, re, delegatesClass, method);
                AddAttachOrDetachEventMethod(false, re, delegatesClass, method);
            }

            return delegatesClass.CreateType();
        }

        static private void AddAttachOrDetachEventMethod(bool attach,
                                                         RegisteredEvent re, 
                                                         TypeBuilder delegatesClass, 
                                                         MethodInfo miEventHandler)
        {
            Type[] parameterTypes = new Type[2];
            parameterTypes[0] = typeof(object);
            parameterTypes[1] = typeof(EventInfo);
            MethodBuilder method = delegatesClass.DefineMethod((attach ? "AttachEvent_" : "DetachEvent_") + re.EventID, 
                                                               MethodAttributes.Public,
                                                               typeof(void),
                                                               parameterTypes);
            ILGenerator methodIL = method.GetILGenerator();
            methodIL.Emit(OpCodes.Ldarg_2);
            methodIL.Emit(OpCodes.Ldarg_1);
            methodIL.Emit(OpCodes.Ldarg_0);

            methodIL.Emit(OpCodes.Ldftn, miEventHandler);

            Type eventHandlerType = re.EventHandlerType;
            ConstructorInfo[] cisEventHandler = eventHandlerType.GetConstructors();
            methodIL.Emit(OpCodes.Newobj, cisEventHandler[0]);

            Type eventInfoType = typeof(EventInfo);
            MethodInfo miAddRemoveEventHandler = eventInfoType.GetMethod(attach ? "AddEventHandler" : "RemoveEventHandler");
            methodIL.Emit(OpCodes.Callvirt, miAddRemoveEventHandler);

            methodIL.Emit(OpCodes.Ret);
        }

        static private MethodBuilder AddEventHandlerMethod(RegisteredEvent re, 
                                                           TypeBuilder delegatesClass, 
                                                           FieldInfo fiReportingDelegate)
        {
            Type[] parameterTypes = new Type[2];
            parameterTypes[0] = typeof(System.Object);
            parameterTypes[1] = typeof(System.EventArgs);
            MethodBuilder method = delegatesClass.DefineMethod(re.EventID, 
                                                               MethodAttributes.Public,
                                                               typeof(void),
                                                               parameterTypes);
            ILGenerator methodIL = method.GetILGenerator();

            methodIL.DeclareLocal(typeof(System.Object[]));

            methodIL.Emit(OpCodes.Ldc_I4_3);
            methodIL.Emit(OpCodes.Newarr, typeof(System.Object));
            methodIL.Emit(OpCodes.Stloc_0);
            methodIL.Emit(OpCodes.Ldloc_0);
            methodIL.Emit(OpCodes.Ldc_I4_0);
            methodIL.Emit(OpCodes.Ldstr, re.EventName);
            methodIL.Emit(OpCodes.Stelem_Ref);
            methodIL.Emit(OpCodes.Ldloc_0);
            methodIL.Emit(OpCodes.Ldc_I4_1);
            methodIL.Emit(OpCodes.Ldarg_1);
            methodIL.Emit(OpCodes.Stelem_Ref);
            methodIL.Emit(OpCodes.Ldloc_0);
            methodIL.Emit(OpCodes.Ldc_I4_2);
            methodIL.Emit(OpCodes.Ldarg_2);
            methodIL.Emit(OpCodes.Stelem_Ref);
            methodIL.Emit(OpCodes.Ldarg_0);
            methodIL.Emit(OpCodes.Ldfld, fiReportingDelegate);

            MethodInfo mi1 = typeof(System.Delegate).GetMethod("get_Method");
            methodIL.Emit(OpCodes.Callvirt, mi1);

            methodIL.Emit(OpCodes.Ldnull);
            methodIL.Emit(OpCodes.Ldloc_0);

            Type[] types = new Type[2];
            types[0] = typeof(System.Object);
            types[1] = typeof(System.Object[]);
            MethodInfo mi2 = typeof(System.Reflection.MethodBase).GetMethod("Invoke", types);
            methodIL.Emit(OpCodes.Callvirt, mi2);
            methodIL.Emit(OpCodes.Pop);
            methodIL.Emit(OpCodes.Ret);

            return method;
        }
        
		static public void ReportEvent(string eventName, object sender, System.EventArgs e)
		{
            FormsDelegate(eventName, sender, e);
		}


        static public bool OpenLogFile(string logFilename, bool append)
        {
            try 
            {
                sw = new StreamWriter(logFilename, append);
                sw.AutoFlush = true;
            }
            catch(Exception e)
            {
                sw = null;
                MessageBox.Show(e.Message, "ICanSpy - Error occurred");
            }
            return (sw != null);
        }

        static public void WriteLogLine(string logLine)
        {
            if (sw != null)
            {
                sw.WriteLine(logLine);
            }
        }

        static public void WriteLogEvent(string eventName, object sender, System.EventArgs e)
        {
            if (sw != null)
            {
                Control ctl = (Control) sender;
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("N:{0} C:{1} T:{2}", eventName, ctl.Name, e.GetType().FullName);
                sw.WriteLine(sb.ToString());
            }
        }

        static public void CloseLogFile()
        {
            if (sw != null)
            {
                sw.Close();
                sw = null;
            }
        }
	}


	public class ControlTreeNode : TreeNode
	{
		private Control ctl;

		public ControlTreeNode() : base()
		{
		}

		public ControlTreeNode(Control ctl) : base()
		{
			this.ctl = ctl;
			this.Text = this.ToString();
		}

		public Control Control
		{
			get
			{
				return ctl;
			}

			set
			{
				ctl = value;
				this.Text = this.ToString();
			}
		}

		public override string ToString()
		{
			return ctl.Name + " (" + ctl.GetType().ToString() + ")";
		}

		public override object Clone()
		{
			ControlTreeNode ctn = new ControlTreeNode(this.ctl);
			ctn.Checked = this.Checked;
			foreach (EventCategoryTreeNode ectn in this.Nodes)
			{
				ctn.Nodes.Add((TreeNode) ectn.Clone());
			}
			return (object) ctn;
		}
	}

	public class EventCategoryTreeNode : TreeNode
	{
		private string categoryName;

		public EventCategoryTreeNode() : base()
		{
		}

		public EventCategoryTreeNode(string categoryName) : base()
		{
			this.categoryName = categoryName;
			this.Text = this.ToString();
		}

		public string CategoryName
		{
			get
			{
				return categoryName;
			}
			set
			{
				categoryName = value;
			}
		}

		public override string ToString()
		{
			return this.categoryName;
		}

		public override object Clone()
		{
			EventCategoryTreeNode ectn = new EventCategoryTreeNode(this.categoryName);
			ectn.Checked = this.Checked;
			foreach (EventTreeNode etn in this.Nodes)
			{
				ectn.Nodes.Add((TreeNode) etn.Clone());
			}
			return (object) ectn;
		}
	}

	public class EventTreeNode : TreeNode
	{
		private EventInfo ei;

		public EventTreeNode() : base()
		{
		}

		public EventTreeNode(EventInfo ei) : base()
		{
			this.ei = ei;
			this.Text = this.ToString();
		}

		public EventInfo EventInfo
		{
			get
			{
				return ei;
			}
			set
			{
				ei = value;
			}
		}

		public override string ToString()
		{
			return ei.Name;
		}

		public override object Clone()
		{
			EventTreeNode etn = new EventTreeNode(this.ei);
			etn.Checked = this.Checked;
			foreach (ControlTreeNode ctn in this.Nodes)
			{
				etn.Nodes.Add((TreeNode) ctn.Clone());
			}
			return (object) etn;
		}
	}

    public class RegisteredEvent
    {
        private ArrayList eventOwners;
        private ArrayList eventInfos;
        private Type eventHandlerType;
        private string eventName;
        private string eventID;

        public RegisteredEvent(Type eventHandlerType, string eventName, object eventOwner, EventInfo ei)
        {
            this.eventHandlerType = eventHandlerType;
            this.eventName = eventName;
            this.eventOwners = new ArrayList();
            this.eventOwners.Add(eventOwner);
            this.eventInfos = new ArrayList();
            this.eventInfos.Add(ei);
        }

        public string EventID
        {
            get
            {
                return eventID;
            }
            set
            {
                eventID = value;
            }
        }

        public string EventName
        {
            get
            {
                return eventName;
            }
        }

        public Type EventHandlerType
        {
            get
            {
                return eventHandlerType;
            }
        }

        public ArrayList EventOwners
        {
            get
            {
                return eventOwners;
            }
        }

        public ArrayList EventInfos
        {
            get
            {
                return eventInfos;
            }
        }

        public void AddEventOwner(object owner)
        {
            eventOwners.Add(owner);
        }

        public void AddEventInfo(EventInfo ei)
        {
            eventInfos.Add(ei);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj is RegisteredEvent)
            {
                RegisteredEvent re = (RegisteredEvent) obj;
                return this.Equals(re);
            }
            return false;
        }

        public bool Equals(RegisteredEvent re)
        {
            return this.eventHandlerType.Equals(re.eventHandlerType) &&
                   this.eventName.Equals(re.eventName);
        }

        public bool Equals(Type eventHandlerType, string eventName)
        {
            return this.eventHandlerType.Equals(eventHandlerType) &&
                   this.eventName.Equals(eventName);
        }
    }

    public class RegisteredEventsSet
    {
        private ArrayList registeredEvents;

        public RegisteredEventsSet()
        {
            registeredEvents = new ArrayList(20);
        }

        public ArrayList RegisteredEvents
        {
            get
            {
                return registeredEvents;
            }
        }

        public void AddRegisteredEvent(Type eventHandlerType, 
                                       string eventName,
                                       object eventOwner,
                                       EventInfo ei)
        {
            foreach (RegisteredEvent re in registeredEvents)
            {
                if (re.Equals(eventHandlerType, eventName))
                {
                    re.AddEventOwner(eventOwner);
                    re.AddEventInfo(ei);
                    return;
                }
            }
            RegisteredEvent newRE = new RegisteredEvent(eventHandlerType, eventName, eventOwner, ei);
            int underscoreCount = 0;
            string eventID;
            string underscoredEventHandlerTypeName = eventHandlerType.FullName.Replace(".", "_");
            do
            {
                underscoreCount++;
                eventID = underscoredEventHandlerTypeName + new string('_', underscoreCount) + eventName;
            }
            while(EventIDExists(eventID));
            newRE.EventID = eventID;
            registeredEvents.Add(newRE);
        }

        private bool EventIDExists(string eventID)
        {
            foreach (RegisteredEvent re in registeredEvents)
            {
                if (re.EventID.Equals(eventID))
                {
                    return true;
                }
            }
            return false;
        }
    }
}