none
Building dynamic method: a problem with Emit OpCodes RRS feed

  • Question

  • It is likely that my question has quick, easy solution. I am building a dynamic assembly "A" that inherits from an existing interface "B" which defines one method "Exec(string, Object[])". This method is implemented in "A" and used to select and execute a method "MessageBox(int, string, string,int)" in external assembly "User32.dll". The problem is with coding the OpCodes that reads "Exec" argument "Object[]" into the execution stack and invoking "MessageBox" with the write arguments' types. Below, is an outline of my code for creating OpCodes of "Exec" implementation which fails to execute with error BadImageFormatExecution (Bad class token)

    interface B { Exec(string s, Object[] args); }

    class AssBuilder{

    // create assembly, module, method , ....

    generator.Emit(OpCodes.Ldarg_2); generator.Emit(OpCodes.Ldc_I4_0, 0); generator.Emit(OpCodes.Ldelem); generator.Emit(OpCodes.Unbox_Any, typeof(int)); generator.Emit(OpCodes.Stloc_0); generator.Emit(OpCodes.Ldarg_2); generator.Emit(OpCodes.Ldc_I4_0, 1); generator.Emit(OpCodes.Ldelem); generator.Emit(OpCodes.Unbox_Any, typeof(string)); generator.Emit(OpCodes.Stloc_1); generator.Emit(OpCodes.Ldarg_2); generator.Emit(OpCodes.Ldc_I4_0, 2); generator.Emit(OpCodes.Ldelem); generator.Emit(OpCodes.Unbox_Any, typeof(string)); generator.Emit(OpCodes.Stloc_2); generator.Emit(OpCodes.Ldarg_2); generator.Emit(OpCodes.Ldc_I4_0, 3); generator.Emit(OpCodes.Ldelem); generator.Emit(OpCodes.Unbox_Any, typeof(int)); generator.Emit(OpCodes.Stloc_3); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldloc_1); generator.Emit(OpCodes.Ldloc_2); generator.Emit(OpCodes.Ldloc_3);

    generator.EmitCall( OpCodes.Call, pInvMethod, new Type[] { typeof(int), typeof(string), typeof(string), typeof(int) });

    // rest of the code

    }  // end of class

    I have successfully tested the "Exec" method by replacing the code above with

    generator.Emit(OpCodes.Ldc_I4_0, 0);
    generator.Emit(OpCodes.Ldstr, "Hello");
    generator.Emit(OpCodes.Ldstr, "Test Windows");
    generator.Emit(OpCodes.Ldc_I4_0, 0);
    What would be wrong with the previous code above?
     

     
    • Edited by DLL Exports Monday, January 7, 2013 2:46 PM
    • Moved by Lisa Zhu Wednesday, January 9, 2013 7:21 AM CLR related (From:Visual C# )
    Monday, January 7, 2013 2:10 PM

Answers

  • Two errors and two additional remarks:

    1) ldc.i4.0 doesn't take an argument. It puts 0 on the stack. You can use ldc_i4_1 to ldc_i4_8 to put values from 1 to 8, or use ldc_i4 with an argument

    2) ldelem needs an argument: the type of the value to load from the array. Here typeof(object). You can also use ldelem.ref

    3) It doesn't prevent it working, but you don't need to emit the unbox_any instruction for reference types like string

    4) Unless you need them for something else, you can get rid of the local variables

                generator.Emit(OpCodes.Ldarg_2);
                generator.Emit(OpCodes.Ldc_I4_0);
                generator.Emit(OpCodes.Ldelem_Ref);
                generator.Emit(OpCodes.Unbox_Any, typeof(int));
                generator.Emit(OpCodes.Ldarg_2);
                generator.Emit(OpCodes.Ldc_I4_1);
                generator.Emit(OpCodes.Ldelem_Ref);
                generator.Emit(OpCodes.Ldarg_2);
                generator.Emit(OpCodes.Ldc_I4_2);
                generator.Emit(OpCodes.Ldelem_Ref);
                generator.Emit(OpCodes.Ldarg_2);
                generator.Emit(OpCodes.Ldc_I4_3);
                generator.Emit(OpCodes.Ldelem_Ref);
                generator.Emit(OpCodes.Unbox_Any, typeof(int));
                generator.EmitCall(
                      OpCodes.Call,
                      pInvMethod,
                      new Type[] { typeof(int), typeof(string), typeof(string), typeof(int) });
                generator.Emit(OpCodes.Ret);


    Monday, January 7, 2013 4:56 PM

All replies

  • Two errors and two additional remarks:

    1) ldc.i4.0 doesn't take an argument. It puts 0 on the stack. You can use ldc_i4_1 to ldc_i4_8 to put values from 1 to 8, or use ldc_i4 with an argument

    2) ldelem needs an argument: the type of the value to load from the array. Here typeof(object). You can also use ldelem.ref

    3) It doesn't prevent it working, but you don't need to emit the unbox_any instruction for reference types like string

    4) Unless you need them for something else, you can get rid of the local variables

                generator.Emit(OpCodes.Ldarg_2);
                generator.Emit(OpCodes.Ldc_I4_0);
                generator.Emit(OpCodes.Ldelem_Ref);
                generator.Emit(OpCodes.Unbox_Any, typeof(int));
                generator.Emit(OpCodes.Ldarg_2);
                generator.Emit(OpCodes.Ldc_I4_1);
                generator.Emit(OpCodes.Ldelem_Ref);
                generator.Emit(OpCodes.Ldarg_2);
                generator.Emit(OpCodes.Ldc_I4_2);
                generator.Emit(OpCodes.Ldelem_Ref);
                generator.Emit(OpCodes.Ldarg_2);
                generator.Emit(OpCodes.Ldc_I4_3);
                generator.Emit(OpCodes.Ldelem_Ref);
                generator.Emit(OpCodes.Unbox_Any, typeof(int));
                generator.EmitCall(
                      OpCodes.Call,
                      pInvMethod,
                      new Type[] { typeof(int), typeof(string), typeof(string), typeof(int) });
                generator.Emit(OpCodes.Ret);


    Monday, January 7, 2013 4:56 PM
  • Hi DLL Exports,

    From your description, I ‘d like to move this post to  the most related forum.

    There are more  experts in this aspect, so you will get  better support and  may have more luck getting answers.

    Thanks for your understanding.

    Regards,


    Lisa Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, January 9, 2013 7:21 AM
  • Thanks Louis,

    Since you have accurately answered my question, would you try answer my question at this location ?

    Thanks again.

    Wednesday, January 16, 2013 7:10 AM
  • Thanks.
    Wednesday, January 16, 2013 7:54 AM