DynamicMethod - Common language runtime detected an invalid program

1.7k views Asked by At

So I try to call a method from an extern DLL via a dynamicmethod using the ilgenerator.

delegate void Write(string text);
static void Main(string[] args)
{
    byte[] bytes = File.ReadAllBytes(@"externmethod.dll");
    var assembly = Assembly.Load(bytes);
    var method = assembly.GetTypes()[0].GetMethod("Write");
    var dynamicMethod = new DynamicMethod("Write", typeof(void), new Type[] { typeof(string) });
    var ilGenerator = dynamicMethod.GetILGenerator();
    ilGenerator.EmitCall(OpCodes.Call, method, null);
    var delegateVoid = dynamicMethod.CreateDelegate(typeof(Write)) as Write;
    delegateVoid("test");
    Console.ReadLine();
}

And the DLL code:

using System;
class program
{
    public static void Write(string text)
    {
        Console.WriteLine(text);
    }
}

But I'm getting this strange error:

An unhandled exception of type 'System.InvalidProgramException' occurred in test.exe
Additional information: Common Language Runtime detected an invalid program.

And I don't have any clue what im doing wrong??

1

There are 1 answers

4
Dudi Keleti On

Your delegate delegate void Write(string text); accepting string as parameter so you need to do this before emitting call:

ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ldstr, "this is test");

And you must return in the end of the method so you need to do that:

ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ret);

Complete code:

var method = assembly.GetTypes()[0].GetMethod("Write");
var dynamicMethod = new DynamicMethod("Write", typeof(void), new Type[] { typeof(string) });
var ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ldstr, "this is test");
ilGenerator.Emit(System.Reflection.Emit.OpCodes.Call, method);
ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ret);
var delegateVoid = dynamicMethod.CreateDelegate(typeof(Write)) as Write;
delegateVoid("test");

Update: I noticed that you want to send parameter to method so instead of

ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ldstr, "this is test");

Write this

ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);

Then what you send here delegateVoid("test"); will print out.

And about the access limitation, if you can't make Program class public, you can define your DynamicMethod like this to get access:

var dynamicMethod = new DynamicMethod("Write", typeof(void), new[] { typeof(string) }, assembly.GetTypes()[0]);