Как ILEmit функцию из другой DLL? - PullRequest
0 голосов
/ 16 ноября 2018

Я пытаюсь создать файл .exe, и этот файл должен вызывать функцию, которая размещена в другой DLL.Я могу правильно загрузить библиотеку DLL, и на тип и метод ссылаются правильно, но при попытке вызвать метод Main возникает исключение:

Common Language Runtime обнаружил недопустимую программу.

Я знаю, что когда я пытаюсь вызвать метод из другой DLL, это вызывает ошибку, потому что я пытаюсь запустить эту программу без этой инструкции, и не было никакого исключения выброса.Я собираюсь поместить весь код здесь (это для целей изучения).

static void Main() {
        String path=createTestMethodDLL()+"\\Testing.dll";
        AssemblyName asmName = new AssemblyName();
        asmName.Name = "HelloReflectionEmit";
        AppDomain appDom = Thread.GetDomain();
        // Create AssemblyBuilder with "RunAndSave" access
        AssemblyBuilder asmBuilder = appDom.DefineDynamicAssembly(asmName,
                                        AssemblyBuilderAccess.RunAndSave);
        // Assembly filename
        string filename = asmName.Name + ".exe";
        // Create ModuleBuilder object
        ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule(
                                                asmName.Name, filename);

        // Define "public class Hello.Emitted"
        //
        TypeBuilder typeBuilder = modBuilder.DefineType("Hello.Emitted",
                                    TypeAttributes.Public | TypeAttributes.Class);
        // Define "public static int Main(string[] args)"
        //

        MethodBuilder methBuilder = typeBuilder.DefineMethod("Main",
                                            MethodAttributes.Public |
                                            MethodAttributes.Static,
                                            typeof(int),
                                            new Type[] { typeof(string[]) });
        MethodBuilder methBuilder2 = typeBuilder.DefineMethod("test",
                                            MethodAttributes.Public |
                                            MethodAttributes.Static);

        ILGenerator ilGen = methBuilder.GetILGenerator();
        ILGenerator ilGen2 = methBuilder2.GetILGenerator();
        ilGen2.Emit(OpCodes.Ldstr, "test method!");
        ilGen2.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string[]) }));
        ilGen2.Emit(OpCodes.Ret);

        // Define a call to System.Console.WriteLine, passing "Hello World"
        var DLL=Assembly.LoadFile(path);
        Type [] ty=DLL.GetExportedTypes();
        ilGen.Emit(OpCodes.Ldstr, "Hello, World!");
        ilGen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string[]) }));
        ilGen.EmitCall(OpCodes.Call,methBuilder2,new Type[] { });

        //problem Down here//
        ilGen.EmitCall(OpCodes.Call, ty[0].GetMethod("testFunction"),new Type[] {}); 

        ilGen.Emit(OpCodes.Ldc_I4_0);
        ilGen.Emit(OpCodes.Ret);
        asmBuilder.SetEntryPoint(methBuilder, PEFileKinds.ConsoleApplication);
        // Save assembly to file
        asmBuilder.Save(filename);
        ReflectOnAssembly(asmName, asmBuilder, "Main", "Hello.Emitted");
        appDom.ExecuteAssembly(filename);
        Console.WriteLine("Finished executing {0}", asmName.Name);
        Console.ReadLine();

        LoadAssembly(filename);

    }

    private static String createTestMethodDLL() {
        AssemblyName asmName = new AssemblyName();
        asmName.Name = "Testing";
        AppDomain appDom = Thread.GetDomain();
        // Create AssemblyBuilder with "RunAndSave" access
        AssemblyBuilder asmBuilder = appDom.DefineDynamicAssembly(asmName,
                                        AssemblyBuilderAccess.RunAndSave);
        // Assembly filename
        string filename = asmName.Name + ".dll";

        // Create ModuleBuilder object
        ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule(
                                                asmName.Name, filename);

        // Define "public class Hello.Emitted"
        //
        TypeBuilder typeBuilder = modBuilder.DefineType("ConsoleApp1.Testing",
                                    TypeAttributes.Public | TypeAttributes.Class);
        // Define "public static int Main(string[] args)"
        //
        MethodBuilder methBuilder = typeBuilder.DefineMethod("testFunction",
                                            MethodAttributes.Public |
                                            MethodAttributes.Static);
        ILGenerator ilGen = methBuilder.GetILGenerator();

        ilGen.Emit(OpCodes.Ldstr, "testing!");
        ilGen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string[]) }));
        ilGen.Emit(OpCodes.Ldc_I4_0);
        ilGen.Emit(OpCodes.Ret);

        // Create type
        Type t = typeBuilder.CreateType();
        // Reflect
        //ReflectOnAssembly(asmName, asmBuilder,"testFunction", "ConsoleApp1.Testing");
        asmBuilder.SetEntryPoint(methBuilder, PEFileKinds.ConsoleApplication);
        // Save assembly to file
        asmBuilder.Save(filename);
        //LoadAssembly(filename);
        Assembly asm = Assembly.GetExecutingAssembly();
        return System.IO.Path.GetDirectoryName(asm.Location);
    }

    private static void ReflectOnAssembly(AssemblyName asmName, AssemblyBuilder asmBuilder,String methodName,String typeName) {
        Console.WriteLine("Now, use reflection on assembly {0}:", asmName.Name);
        foreach (Type type in asmBuilder.GetTypes()) {
            Console.WriteLine("Type {0}", type);
            foreach (MethodInfo mi in type.GetMethods(BindingFlags.Public
                                                      | BindingFlags.NonPublic
                                                      | BindingFlags.Instance
                                                      | BindingFlags.Static)) {
                Console.WriteLine("Method {0}", mi.ToString());
            }
            Console.WriteLine("Invoking Main:");
            MethodInfo mainMethod = asmBuilder.GetType(typeName).GetMethod(methodName);
            if (mainMethod != null)
                // First param = this, second param = method parameters
                mainMethod.Invoke(null, new object[1] { null });
        }
    }

    private static void LoadAssembly(string filename) {
        Assembly assembly = Assembly.LoadFrom(filename);
        // Get public and non public types from assembly
        Type[] types = assembly.GetTypes();
        foreach (Type t in types) {
            Console.WriteLine(t.Name);
        }
    }
...