.NET FrameworkのクラスライブラリのSystem.Reflection.Emit名前空間のクラスを使用すると、アプリケーションの実行時に、実行ファイルを生成することができます。
しかし、あのあたりはヘルプが役に立たない上、動的に実行ファイルを生成するサンプルは、ネット上にほとんど転がっていません。 近いものはMSの英語サイトにサンプルがおいてありましたが。
ってことで、今回は動的にHelloWorldな実行ファイルを出力するサンプルを書いておきます。

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

namespace DynamicEXETest
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain tAppDomain = Thread.GetDomain();

            // アセンブリの名前を生成
            AssemblyName tAssemblyName = new AssemblyName();
            tAssemblyName.Name = "TestDynamicAssembly";

            // 動的アセンブリを定義して、そのビルダーを得る
            AssemblyBuilder tAssembly = tAppDomain.DefineDynamicAssembly(tAssemblyName, AssemblyBuilderAccess.Save);

            // アセンブリ内にモジュールを定義
            ModuleBuilder tModule;
            tModule = tAssembly.DefineDynamicModule("TestDynamicModule", "TestDynamicModule.mod");

            // モジュール内にクラスを定義
            TypeBuilder tDynamicClass = tModule.DefineType("TestClassDynamic", TypeAttributes.Public);

            // エントリーポイントのメソッドを定義
            MethodBuilder tMainMethod = tDynamicClass.DefineMethod("Main", MethodAttributes.Private | MethodAttributes.Static, null, new Type[] { typeof(string[]) });

            // ILコードを書く
            ILGenerator tILGenerator = tMainMethod.GetILGenerator();
            { // メソッド本体

                // 文字列"Hello World"をスタックに乗せる
                tILGenerator.Emit(OpCodes.Ldstr, "Hello World");

                // Console.Writelineを呼び出す。
                tILGenerator.EmitCall(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), new Type[] { typeof(string) });

                // Console.ReadLineを呼び出す。
                tILGenerator.EmitCall(OpCodes.Call, typeof(Console).GetMethod("ReadLine"), null);

                // スタックからReadLineで読み込んだ値を削除
                tILGenerator.Emit(OpCodes.Pop);

                // メソッド終了
                tILGenerator.Emit(OpCodes.Ret);
            }

            // これまでの情報から型を生成
            tDynamicClass.CreateType();

            // アセンブリのエントリーポイントを設定
            tAssembly.SetEntryPoint(tMainMethod);

            // ファイルに書き出す。
            tAssembly.Save("testAssembly.exe", PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
        }
    }
}

このコードを実行してできた”testAssembly.exeをReflectorを使って逆アセンブルすると、以下のようなコードが見れます。

private static void Main(string[])
{
    Console.WriteLine("Hello World");
    Console.ReadLine();
}
カテゴリー: 技術情報

1件のコメント

来栖川ブログ » 計算機を作ってみる(さいご) · 2009-03-09 22:50

[…] 前回動的に実行ファイルを作るサンプルを書いたので、ついでに、前に作った計算機を、実行ファイルを吐き出すように改造してみた。 Visual Studio2005のプロジェクト -> calc_compiler.zip ISyntacticNodeのEvalをILGeneratorが渡ってくるように書き換え。 PLAIN TEXT C#: […]

現在コメントは受け付けていません。