Search code examples
c#.netreflection.emit

c# system.reflection.emit ldfld


Hi i wrote the following code:

     AssemblyName assemblyName = new AssemblyName("SamAsm");
        AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        TypeBuilder typeBuilder = assemblyBuilder.DefineDynamicModule("SamAsm.exe").DefineType("SamAsmType", TypeAttributes.Public);
        MethodBuilder methodBuilder1 = typeBuilder.DefineMethod("Main", MethodAttributes.Static | MethodAttributes.Public, typeof(void), new Type[] { typeof(string) });
        ILGenerator gen = methodBuilder1.GetILGenerator();
        FieldInfo field1 = typeof(Form1).GetField("TextBox1", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

        MethodInfo method2 = typeof(Control).GetProperty("Text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).GetGetMethod();
        MethodInfo method3 = typeof(String).GetMethod(
            "op_Equality",
            BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
            null,
            new Type[]{
    typeof(String),
    typeof(String)
    },
            null
            );
        MethodInfo method4 = typeof(MessageBox).GetMethod(
            "Show",
            BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
            null,
            new Type[]{
    typeof(String)
    },
            null
            );



        LocalBuilder a = gen.DeclareLocal(typeof(Boolean));

        System.Reflection.Emit.Label label42 = gen.DefineLabel();

        gen.Emit(OpCodes.Nop);
        gen.Emit(OpCodes.Ldarg_0);
        gen.Emit(OpCodes.Ldfld, field1);
        gen.Emit(OpCodes.Callvirt, method2);
        gen.Emit(OpCodes.Ldstr, "HI");
        gen.Emit(OpCodes.Call, method3);
        gen.Emit(OpCodes.Ldc_I4_0);
        gen.Emit(OpCodes.Ceq);
        gen.Emit(OpCodes.Stloc_0);
        gen.Emit(OpCodes.Ldloc_0);
        gen.Emit(OpCodes.Brtrue_S, label42);
        gen.Emit(OpCodes.Nop);
        gen.Emit(OpCodes.Ldstr, "You cracked me");
        gen.Emit(OpCodes.Call, method4);
        gen.Emit(OpCodes.Pop);
        gen.Emit(OpCodes.Nop);
        gen.MarkLabel(label42);
        gen.Emit(OpCodes.Ret);




        typeBuilder.CreateType().GetMethod("Main").Invoke(null, new string[] { null });
        assemblyBuilder.SetEntryPoint(methodBuilder1, PEFileKinds.WindowApplication);}

When i try this, it stops me on gen.Emit(OpCodes.Ldfld,typeof(Form1).GetField("TextBox1", BindingFlags.Public | BindingFlags.NonPublic));

and tell: The value can't be null. Parameter name : con . Someone can help me?


Solution

  • It means that one of the parameters for the call is null, most likely the return value of typeof(Form1).GetField("TextBox1", BindingFlags.Public | BindingFlags.NonPublic).

    Since you already stored that value in the variable field1, you should go into Debug mode and check that it is not null.

    If the value is null, it can mean different things :

    • Is there really a field called TextBox1 in your Form1 class ? Always doubnle-check the spelling, and also character casing. Reflection methods like GetField, GetProperty... are case sensitive unless used with BindingFlags.IgnoreCase.
    • Is it accessible using the value of BindingFlags you provided (eg. is it static ?) ?

    In your case, if you look at the MSDN documentation for GetField, it explicitely states :

    The following BindingFlags filter flags can be used to define which fields to include in the search:

    You must specify either BindingFlags.Instance or BindingFlags.Static in order to get a return.

    Specify BindingFlags.Public to include public fields in the search.

    Specify BindingFlags.NonPublic to include non-public fields (that is, private, internal, and protected fields) in the search.

    Specify BindingFlags.FlattenHierarchy to include public and protected static members up the hierarchy; private static members in inherited classes are not included.

    So you should use BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance instead of BindingFlags.Public | BindingFlags.NonPublic

    Also replace

    gen.Emit(OpCodes.Ldfld,typeof(Form1).GetField("TextBox1", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance));
    

    With

    gen.Emit(OpCodes.Ldfld, field1);
    

    And use the proper flags on the line where you are assigning field1.

    UPDATE : You have the same issue with your final call to Main. You need to specify BindingFlags.Static in the following line of code, sinhce you defined your method as static using MethodAttributes earlier in your code :

    typeBuilder.CreateType().GetMethod("Main", BindingFlags.Static | BindingFlags.Public).Invoke(null, new string[] { null });
    

    Additionnally, you do not want to retrieve property accessors the way you are doing it : instead of using GetMethod with the name of the accessor (get_Text), you should use GetProperty :

        MethodInfo method2 = typeof(Control).GetProperty("Text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).GetMethod;
    

    Hope that helps.