Hi all, This is the third and final example. It was adapted from "Advanced Code Injection with Mono.Cecil" posted on http://www.dotnetsharp.com/Forums/dispbbs.aspx?i=2007&j=434 (quoting http://www.wodka-fabrik.org/ilja/blog/?tag=cecil). Author is unknow but post date June 25th, 2008.
The above example is very well commented (something quite unusual and that's really a pitty and yes, I'm referring to Mono.Cecil). Again the return type of the field can be whatever you like. Again attributes are not handled. Again load and save symbols parts are commented (see the previous post "Property injection example" http://groups.google.pt/group/mono-cecil/browse_thread/thread/f2a3df3a34e68639). using System; using Mono.Cecil; using Mono.Cecil.Cil; namespace CustomFieldsInjection { public partial class Injector { public static void MethodInjection(string assemblyFilename, string typeName, string methodName) { AssemblyDefinition assembly = AssemblyFactory.GetAssembly (assemblyFilename); // Compared to Reflection, Cecil doesn`t use a AppDomain here, // which also allows us to load incomplete or CAS- prohibited assemblies. //Load the debugger symbols file // assembly.MainModule.LoadSymbols(); // Next we'd like to define our new Method. A method in Cecil consists of // the return type the signature and the body (code). //Get a TypeReference for the return Type TypeReference returnTypeReference = assembly.MainModule.Import(typeof(void)); //Define Method signature "public static void" methodName MethodDefinition methodDefinition = new MethodDefinition( methodName, MethodAttributes.Public | MethodAttributes.Static, returnTypeReference); // Now we got our method but it hasn`t got any code in it`s body. // The new method will write a message outputString to the Console. //Push string onto the stack Instruction instruction1 = methodDefinition.Body.CilWorker.Create(OpCodes.Nop); //Push string onto the stack Instruction instruction2 = methodDefinition.Body.CilWorker.Create(OpCodes.Ldstr, methodName); //Import external method reference to Console.WriteLine() MethodReference writeline = assembly.MainModule.Import( typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); // We need to generate the defined code and append it to our new method Body //Generate stack-push methodDefinition.Body.CilWorker.Append(instruction1); methodDefinition.Body.CilWorker.Append(instruction2); //Generate call to WriteLine() methodDefinition.Body.CilWorker.InsertAfter( instruction2, methodDefinition.Body.CilWorker.Create (OpCodes.Call, writeline)); //Generate return methodDefinition.Body.CilWorker.Append (methodDefinition.Body.CilWorker.Create(OpCodes.Ret)); // That done, we need to inject the generated Method into the assembly assembly.MainModule.Inject(methodDefinition, assembly.MainModule.Types[typeName]); // At last we need to modify Main to call our new Method //Get Method reference with name like methodName, MethodReference methodReference = null; //Get all the methods of typeName foreach (MethodDefinition method in assembly.MainModule.Types[typeName].Methods) { if (method.Name == methodName) { methodReference = assembly.MainModule.Import (method); break; } } //Create call to the reference Instruction callTest = methodDefinition.Body.CilWorker.Create(OpCodes.Call, methodReference); if (assembly.EntryPoint != null) { //Insert reference assembly.EntryPoint.Body.CilWorker.InsertBefore (assembly.EntryPoint.Body.Instructions[0], callTest); } //Save the debugger symbols file // assembly.MainModule.SaveSymbols(); //Save the patched assembly back to disk AssemblyFactory.SaveAssembly(assembly, assemblyFilename); } } } Have fun. Tiago Freitas Leal --~--~---------~--~----~------------~-------~--~----~ -- mono-cecil -~----------~----~----~----~------~----~------~--~---
