Click here to Skip to main content
15,881,248 members
Articles / Programming Languages / Visual Basic

ControlInspector - monitor Windows Forms events as they are fired (like Spy++ for .net)

Rate me:
Please Sign up or sign in to vote.
4.96/5 (86 votes)
30 Apr 2003CPOL6 min read 273.1K   8.3K   176  
ControlInspector hooks on to all events on a given control, user-control or form and shows when they are fired, along with any eventargs. It even handles custom events and custom event args using dynamically generated assemblies.
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
using System.Threading;

using System.Diagnostics;

namespace ControlInspector
{
	public class GenerateEventAssembly
	{
		Type parent = typeof(ControlEvent);
	
		Hashtable typeCollection = new Hashtable();

		AssemblyName assemblyName;
		AssemblyBuilder newAssembly;
		ModuleBuilder newModule;

		private GenerateEventAssembly() 
		{
			StartAssembly();
		}

		string filename = "james.dll";

		private void StartAssembly() 
		{
			// Create an assembly name
			assemblyName = new AssemblyName( );
			assemblyName.Name = "James";
 
			// Create a new assembly with one module.
			// Change to AssemblyBuilderAccess.RunAndSave if you want to save the
			// assembly to disk for inspection
			newAssembly =
				Thread.GetDomain( ).DefineDynamicAssembly(
				assemblyName, AssemblyBuilderAccess.Run);

			// This is the replacement to allow persisting the assembly to disk
			//newModule =
			//		newAssembly.DefineDynamicModule("James2", filename);

			newModule =
				newAssembly.DefineDynamicModule("James2");
		}

		// the private method which emits the assembly
		// using op codes
		private Type GenerateEventConsumerType(Type eventHandlerType)
		{
			string typeName = "DerivedControlEvent" + eventHandlerType.Name;

			// Define a public class in the assembly with the calculated
			// name, above
			TypeBuilder myType =
				newModule.DefineType(
				typeName, TypeAttributes.Public, parent);
 
			// Define a method on the type to call. Pass an
			// array that defines the types of the parameters,
			// the type of the return type, the name of the 
			// method, and the method attributes.
			Type[] paramTypes = new Type[2];

			paramTypes[0] = typeof(object);
			paramTypes[1] = eventHandlerType;

			Type returnType = typeof(void);

			MethodBuilder simpleMethod =
				myType.DefineMethod(
				"HandleEvent",
				MethodAttributes.Public | 
				MethodAttributes.HideBySig,
				returnType,
				paramTypes);
 
			// Get an ILGenerator. This is used
			// to emit the IL that you want.
			ILGenerator generator = 
				simpleMethod.GetILGenerator( );
 
			// Emit the IL that you'd get if you 
			// compiled the code example 
			// and then ran ILDasm on the output.
 
			generator.Emit(OpCodes.Ldarg_0);
			generator.Emit(OpCodes.Ldarg_1);
			generator.Emit(OpCodes.Ldarg_2);

			MethodInfo miGenericEventHandler;
			miGenericEventHandler = parent.GetMethod("GenericHandleEvent");
			
			generator.Emit(OpCodes.Call, miGenericEventHandler);

			// return the value
			generator.Emit(OpCodes.Ret);
 
 
			// Create the type.
			Type result = myType.CreateType( );

			//  for debugging purposes, save out the assembly. Remember to change
			//  the call that creates newAssembly above
//			newAssembly.Save(filename);

			return result;
		}
 
		static GenerateEventAssembly instance;
		public static GenerateEventAssembly Instance 
		{
			get 
			{
				if (instance == null) 
				{
					instance = new GenerateEventAssembly();
				}

				return instance;
			}
		}

		// emit the assembly, create an instance 
		// and get the interface
		public ControlEvent GetEventConsumerType(Type eventHandlerType)
		{
			Type eventConsumerType;

			if (typeCollection.Contains(eventHandlerType)) 
			{
				
				eventConsumerType = (Type) typeCollection[eventHandlerType];
			} 
			else 
			{
				eventConsumerType = GenerateEventConsumerType(eventHandlerType);

				typeCollection[eventHandlerType] = eventConsumerType;
			}

			ControlEvent ev = (ControlEvent) Activator.CreateInstance(eventConsumerType);

			return ev;
		}
 
	}

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United Kingdom United Kingdom
Director of Adastra Software Ltd, a UK based provider of point of care information systems.

Comments and Discussions