This project is read-only.

How to add code into method?

Topics: Metadata Model, PE reader, PE Writer, Source Model
Apr 30, 2011 at 6:34 PM

Hi guys!

I'm trying insert an source code into method body. I do it like so: 

 

IMetadataHost host = new PeReader.DefaultHost();
IModule module = host.LoadUnitFrom("ModelAssembly.dll") as IModule;
IMethodDefinition method = /*I select necessary method here*/ 
              
ILGenerator ilGenerator = new ILGenerator(host, method);
ilGenerator.Emit(OperationCode.Ldstr, "hello");               
ilGenerator.Emit(OperationCode.Call, "System.Void System.Console.WriteLine(System.String)");               
ilGenerator.Emit(OperationCode.Ret);

Stream peStream = File.Create("ModelAssembly_new.dll");
PeWriter.WritePeToStream(module, host, peStream);           
peStream.Close();

I expect to see new lines of code into top of body. But, when i open ModelAssembly_new.dll into IL DASM, i see old version of method body. Thus, source code didn't add to assembly. How i do it correctly? I hope, anyone will show correct example here. Thank for help!

 

Apr 30, 2011 at 7:01 PM

The object model that you get from LoadUnitFrom is immutable. The ILGenerator instance is not going to change that object model, it will merely generate a new il stream. The ILMutator sample application shows how you can go about making a mutable copy of the object model and changing the il.

Depending on your application, you may find it easier to use the Code Model from the companion project (cciast.codeplex.com).

May 1, 2011 at 9:48 PM
Edited May 1, 2011 at 9:48 PM

Thank you vary match! I find solution and i give it below. I hope, it will help someone. Following source code have been written on the basis of ILMutator simple application.  

IMetadataHost host = new PeReader.DefaultHost();
IModule module = host.LoadUnitFrom("ModelAssembly.dll") as IModule; // Load original module

module = new MetadataDeepCopier(host).Copy(module); // Make a editable copy
ILMutator mutator = new ILMutator(host); // Create class, which will add some source code in any method
module = mutator.Visit(module); // Create new modified assembly

Stream s = File.Create(outputPath);           
PeWriter.WritePeToStream(module, host, s);           
s.Close();

public class ILMutator : MutatingVisitor    
{       
        public ILMutator(IMetadataHost host) 
            : base(host, false) { }

        public override MethodBody Mutate(MethodBody methodBody)       
        {           
            // Create Console.WriteLise(String) method reference
            Microsoft.Cci.NamespaceTypeReference SystemDotConsoleType =
              new Microsoft.Cci.NamespaceTypeReference(host,
                host.PlatformType.SystemString.ContainingUnitNamespace,
                host.NameTable.GetNameFor("Console"),
                0, false, false, PrimitiveTypeCode.NotPrimitive);

            IMethodReference consoleDotWriteLine = new Microsoft.Cci.MethodReference(
              host, SystemDotConsoleType, CallingConvention.Default,
              host.PlatformType.SystemVoid, host.NameTable.GetNameFor("WriteLine"),
              0, host.PlatformType.SystemString);

            // Create IL Generator
            ILGenerator generator = new ILGenerator(this.host, methodBody.MethodDefinition);

            // Generate output into console the name of current method
            generator.Emit(OperationCode.Ldstr, methodBody.MethodDefinition.Name.Value);           
            generator.Emit(OperationCode.Call, consoleDotWriteLine);
            generator.AdjustBranchSizesToBestFit();       

            // Apply changes to new body
            methodBody.Operations.InsertRange(0, new List<IOperation>(generator.GetOperations()));
            methodBody.OperationExceptionInformation.AddRange(new List<IOperationExceptionInformation>(generator.GetOperationExceptionInformation()));
            return methodBody;     
        }   
}