マクロから渡した関数名でリアルタイムにdllを生成する

  • 概要

    .NET Frameworkは、「System.Reflection」を利用することで、クラスやメソッド等をリアルタイムに生成するだけではなく、
    .dllや.exeへと具体的にコンパイルするメソッドまでをも提供しています。

    以下のファイルをdynamicasm.macとして保存します。

    #PY = loaddll( hidemarudir + @"\hmPy.dll" );
    
    #_ = dllfuncw(#PY, "DoString", R"IPY(
    
    my_sum_method_name = "hm_sum";
    
    )IPY"
    );
    
    
    #_ = dllfuncw(#PY, "DoString", R"IPY(
    
    from System import *
    from System.Threading import *
    from System.Reflection import *
    from System.Reflection.Emit import *
    
    try:
        my_sum_method_name = my_sum_method_name
    except:
        my_sum_method_name = "myfunc"
    
    def addMethodDynamically(typeBuilder, methodName, methodParams, returnType):
        methodBuilder = typeBuilder.DefineMethod(
                                         methodName,
                                         MethodAttributes.Public | MethodAttributes.Static,
                                         returnType,
                                         methodParams
                                         )
        ILout = methodBuilder.GetILGenerator()
        numParams = len(methodParams)
        x = 0
        while x < numParams:
            ILout.Emit(OpCodes.Ldarg_S, x)
            x += 1
        y = 0
        while y < (numParams - 1):
            ILout.Emit(OpCodes.Add)
            y += 1
        ILout.Emit(OpCodes.Ret)
    
    
    def main():
    
        domain = Thread.GetDomain()
        asmName = AssemblyName()
        asmName.Name = "DynamicAssembly"
    
        asmBuilder = domain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave)
        module = asmBuilder.DefineDynamicModule("DynamicModule", "DynamicAsm.dll")
        typeBuilder = module.DefineType("DynamicType", TypeAttributes.Public)
    
        global my_sum_method_name
        methodName = my_sum_method_name
        inputNumsList = (2, 3, 4, 5)
    
        methodParams = Array[Type]((Int32, Int32, Int32, Int32))
        inputValsList = Array[object](inputNumsList)
    
        returnType = Int32
    
        # Now, call the method building method with the parameters, passing the TypeBuilder.
        addMethodDynamically(typeBuilder, methodName, methodParams, returnType)
        myType = typeBuilder.CreateType()
        result = myType.InvokeMember(methodName,
                                BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static,
                                None, None,
                                inputValsList
                               )
        hm.debuginfo( "入力された数値の総計: %s" % result )
        hm.debuginfo( "---" )
    
        # ダイナミックにMSILを生成しています。
        asmBuilder.Save("DynamicAsm.dll")
        methodInfo = myType.GetMethod(methodName)
        hm.debuginfo( "生成したメソッド: %r;" % methodInfo )
    
    
    main()
    
    )IPY"
    );
    
    freedll( #PY );
    

    出来上がったDynamicAsm.dllをILSpyで見ると

    以下のように秀丸マクロで渡したパラメータに基づいて、.dllが出来上がっているのがわかります。