none
Call a global function using C# emit RRS feed

  • Question

  • Hi Everyone,

    I'm building a dynamic assembly & module in C#. Doing this I'd like to add some "global" PInvoke calls e.g. :

     MethodBuilder freeGlobalMethod = module.DefineGlobalMethod(
    "free", 
    System.Reflection.MethodAttributes.Assembly | System.Reflection.MethodAttributes.Static, 
    typeof(void), 
    new Type[] {typeof(void*)});
    
    ...
    
    module.CreateGlobalFunctions();

    It seems I can "get" this method from the module, however, when I try to call from a type also defined the the module it an error is thrown saying that you can't call a method from a different module.

    Main question: how can I emit code from a type that calls this global fucntion ?

    Thanks, Tom

    Tuesday, July 6, 2010 11:42 AM

Answers

  • From my understanding of your question, you are creating multi-modules assembly at runtime, you defined a global method (assembly level) in one module, and you want to call the method from another module, am I right?

    If so, you may try following sample which may satisfy your requirements:

            // There are 3 modules in the assembly:

            // [0] 1. MyDynamicAsm.dll, contains only the manifest.

            // [1]  2. MyDynamicAsmmodule1.module, contains the global method.

            // [2]  3. MyDynamicAsmmodule2.module, contains type MyDynamicType, the type has a static method CallingMethod() from which the global method is invoked.

        private static void DefineGlobalMethod(ModuleBuilder myModule)

        {

            MethodBuilder mb = myModule.DefineGlobalMethod(

                                                "GlobalMethod1",

                                                MethodAttributes.Assembly | MethodAttributes.Static,

                                                null,

                                                Type.EmptyTypes);

     

            ILGenerator ILout = mb.GetILGenerator();

            ILout.Emit(OpCodes.Ldstr, "this is a global method.");

            MethodInfo mi = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });

            ILout.Emit(OpCodes.Call, mi);

            ILout.Emit(OpCodes.Ret);

     

            myModule.CreateGlobalFunctions();

        }

     

        private static void DefineMethodForCallingGlobalFunction(TypeBuilder tb)

        {

            MethodBuilder mb = tb.DefineMethod(

                                                 "CallingMethod",

                                                 MethodAttributes.Public | MethodAttributes.Static,

                                                 null,

                                                 Type.EmptyTypes);

     

            ILGenerator ILout = mb.GetILGenerator();

           

            ILout.DeclareLocal(typeof(Assembly));  // 0

            ILout.DeclareLocal(typeof(Module)); // 1

            ILout.DeclareLocal(typeof(MethodInfo)); // 2

     

            MethodInfo mi;

     

            ILout.Emit(OpCodes.Ldstr, "this is a calling method.");

            mi = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });

            ILout.Emit(OpCodes.Call, mi);

     

            // Get assembly

            mi = typeof(Assembly).GetMethod("GetExecutingAssembly");

            ILout.Emit(OpCodes.Call, mi);

            ILout.Emit(OpCodes.Stloc_0);

     

            ILout.Emit(OpCodes.Ldloc_0);

            mi = typeof(Assembly).GetMethod("GetModules", Type.EmptyTypes);

            ILout.Emit(OpCodes.Callvirt, mi);

            ILout.Emit(OpCodes.Ldc_I4_1); // get the second module.

            ILout.Emit(OpCodes.Ldelem_Ref);

            ILout.Emit(OpCodes.Stloc_1);

     

            // Get the global method

            ILout.Emit(OpCodes.Ldloc_1);

            ILout.Emit(OpCodes.Ldstr, "GlobalMethod1");

            BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic;

            ILout.Emit(OpCodes.Ldc_I4_S, (int)flags);

            ILout.Emit(OpCodes.Ldnull);

            CallingConventions cc = CallingConventions.Any;

            ILout.Emit(OpCodes.Ldc_I4_S, (int)cc);

            FieldInfo fi = typeof(Type).GetField("EmptyTypes");

            ILout.Emit(OpCodes.Ldsfld, fi);

            ILout.Emit(OpCodes.Ldnull);

            mi = typeof(Module).GetMethod("GetMethod", new Type[] { typeof(string), typeof(BindingFlags), typeof(Binder), typeof(CallingConventions), typeof(Type[]), typeof(ParameterModifier[]) });

            ILout.Emit(OpCodes.Callvirt, mi);

            ILout.Emit(OpCodes.Stloc_2);

     

            // Invoke the global method

            ILout.Emit(OpCodes.Ldloc_2);

            ILout.Emit(OpCodes.Ldnull);

            ILout.Emit(OpCodes.Ldnull);

            mi = typeof(MethodBase).GetMethod("Invoke", new Type[]{ typeof(object), typeof(object[])});

            ILout.Emit(OpCodes.Callvirt, mi);

     

            ILout.Emit(OpCodes.Pop);

     

            ILout.Emit(OpCodes.Ret);

        }

     


    Sincerely,
    Eric
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by eryang Monday, July 19, 2010 10:00 AM
    Thursday, July 8, 2010 11:11 AM
  •     public static void Main()

        {

            AppDomain myDomain = AppDomain.CurrentDomain;

            AssemblyName asmName = new AssemblyName();

            asmName.Name = "MyDynamicAsm";

     

            AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(

                                           asmName,

                                           AssemblyBuilderAccess.RunAndSave);

     

            ModuleBuilder myModule = myAsmBuilder.DefineDynamicModule("MyDynamicAsmModule1", "MyDynamicAsmmodule1.module");

            DefineGlobalMethod(myModule);

     

            ModuleBuilder myModule2 = myAsmBuilder.DefineDynamicModule("MyDynamicAsmModule2", "MyDynamicAsmmodule2.module");

     

            TypeBuilder myTypeBld = myModule2.DefineType("MyDynamicType", TypeAttributes.Public);

            DefineMethodForCallingGlobalFunction(myTypeBld);

            Type myType = myTypeBld.CreateType();

            myAsmBuilder.Save("MyDynamicAsm.dll");

     

            // Invoke the static method CallingMethod().

            Assembly assembly = Assembly.LoadFile(@"D:\MyDynamicAsm.dll");

            Type t = assembly.GetType("MyDynamicType");

            MethodInfo mi = t.GetMethod("CallingMethod");

            mi.Invoke(null, null);

           

        }


    Sincerely,
    Eric
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by eryang Monday, July 19, 2010 10:00 AM
    Thursday, July 8, 2010 11:11 AM

All replies

  •  

    Hi Tom,

    Since you use the System.Reflection.MethodAttributes.Assembly to modify the method accessibility, the generated method is only visible within its assembly, you may replace System.Reflection.MethodAttributes.Assembly by System.Reflection.MethodAttributes.Public and try again.

     

    See also:

    MethodAttributes Enumeration


    Sincerely,
    Eric
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Wednesday, July 7, 2010 7:07 AM
  • Hi Eric,

    acually I'm calling it from within the same assembly, although from a different module.  It seems the Global functions end up in a module called "<Module>" while a different module holds the generated Types. But both are in the same assembly.

     

    Tom

    Wednesday, July 7, 2010 3:41 PM
  • From my understanding of your question, you are creating multi-modules assembly at runtime, you defined a global method (assembly level) in one module, and you want to call the method from another module, am I right?

    If so, you may try following sample which may satisfy your requirements:

            // There are 3 modules in the assembly:

            // [0] 1. MyDynamicAsm.dll, contains only the manifest.

            // [1]  2. MyDynamicAsmmodule1.module, contains the global method.

            // [2]  3. MyDynamicAsmmodule2.module, contains type MyDynamicType, the type has a static method CallingMethod() from which the global method is invoked.

        private static void DefineGlobalMethod(ModuleBuilder myModule)

        {

            MethodBuilder mb = myModule.DefineGlobalMethod(

                                                "GlobalMethod1",

                                                MethodAttributes.Assembly | MethodAttributes.Static,

                                                null,

                                                Type.EmptyTypes);

     

            ILGenerator ILout = mb.GetILGenerator();

            ILout.Emit(OpCodes.Ldstr, "this is a global method.");

            MethodInfo mi = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });

            ILout.Emit(OpCodes.Call, mi);

            ILout.Emit(OpCodes.Ret);

     

            myModule.CreateGlobalFunctions();

        }

     

        private static void DefineMethodForCallingGlobalFunction(TypeBuilder tb)

        {

            MethodBuilder mb = tb.DefineMethod(

                                                 "CallingMethod",

                                                 MethodAttributes.Public | MethodAttributes.Static,

                                                 null,

                                                 Type.EmptyTypes);

     

            ILGenerator ILout = mb.GetILGenerator();

           

            ILout.DeclareLocal(typeof(Assembly));  // 0

            ILout.DeclareLocal(typeof(Module)); // 1

            ILout.DeclareLocal(typeof(MethodInfo)); // 2

     

            MethodInfo mi;

     

            ILout.Emit(OpCodes.Ldstr, "this is a calling method.");

            mi = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });

            ILout.Emit(OpCodes.Call, mi);

     

            // Get assembly

            mi = typeof(Assembly).GetMethod("GetExecutingAssembly");

            ILout.Emit(OpCodes.Call, mi);

            ILout.Emit(OpCodes.Stloc_0);

     

            ILout.Emit(OpCodes.Ldloc_0);

            mi = typeof(Assembly).GetMethod("GetModules", Type.EmptyTypes);

            ILout.Emit(OpCodes.Callvirt, mi);

            ILout.Emit(OpCodes.Ldc_I4_1); // get the second module.

            ILout.Emit(OpCodes.Ldelem_Ref);

            ILout.Emit(OpCodes.Stloc_1);

     

            // Get the global method

            ILout.Emit(OpCodes.Ldloc_1);

            ILout.Emit(OpCodes.Ldstr, "GlobalMethod1");

            BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic;

            ILout.Emit(OpCodes.Ldc_I4_S, (int)flags);

            ILout.Emit(OpCodes.Ldnull);

            CallingConventions cc = CallingConventions.Any;

            ILout.Emit(OpCodes.Ldc_I4_S, (int)cc);

            FieldInfo fi = typeof(Type).GetField("EmptyTypes");

            ILout.Emit(OpCodes.Ldsfld, fi);

            ILout.Emit(OpCodes.Ldnull);

            mi = typeof(Module).GetMethod("GetMethod", new Type[] { typeof(string), typeof(BindingFlags), typeof(Binder), typeof(CallingConventions), typeof(Type[]), typeof(ParameterModifier[]) });

            ILout.Emit(OpCodes.Callvirt, mi);

            ILout.Emit(OpCodes.Stloc_2);

     

            // Invoke the global method

            ILout.Emit(OpCodes.Ldloc_2);

            ILout.Emit(OpCodes.Ldnull);

            ILout.Emit(OpCodes.Ldnull);

            mi = typeof(MethodBase).GetMethod("Invoke", new Type[]{ typeof(object), typeof(object[])});

            ILout.Emit(OpCodes.Callvirt, mi);

     

            ILout.Emit(OpCodes.Pop);

     

            ILout.Emit(OpCodes.Ret);

        }

     


    Sincerely,
    Eric
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by eryang Monday, July 19, 2010 10:00 AM
    Thursday, July 8, 2010 11:11 AM
  •     public static void Main()

        {

            AppDomain myDomain = AppDomain.CurrentDomain;

            AssemblyName asmName = new AssemblyName();

            asmName.Name = "MyDynamicAsm";

     

            AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(

                                           asmName,

                                           AssemblyBuilderAccess.RunAndSave);

     

            ModuleBuilder myModule = myAsmBuilder.DefineDynamicModule("MyDynamicAsmModule1", "MyDynamicAsmmodule1.module");

            DefineGlobalMethod(myModule);

     

            ModuleBuilder myModule2 = myAsmBuilder.DefineDynamicModule("MyDynamicAsmModule2", "MyDynamicAsmmodule2.module");

     

            TypeBuilder myTypeBld = myModule2.DefineType("MyDynamicType", TypeAttributes.Public);

            DefineMethodForCallingGlobalFunction(myTypeBld);

            Type myType = myTypeBld.CreateType();

            myAsmBuilder.Save("MyDynamicAsm.dll");

     

            // Invoke the static method CallingMethod().

            Assembly assembly = Assembly.LoadFile(@"D:\MyDynamicAsm.dll");

            Type t = assembly.GetType("MyDynamicType");

            MethodInfo mi = t.GetMethod("CallingMethod");

            mi.Invoke(null, null);

           

        }


    Sincerely,
    Eric
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by eryang Monday, July 19, 2010 10:00 AM
    Thursday, July 8, 2010 11:11 AM
  •  

    Hi,

    I'm writing to check the issue status, please feel free to let us know if you have any concern.


    Sincerely,
    Eric
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Monday, July 12, 2010 8:59 AM