技術をかじる猫

適当に気になった技術や言語、思ったこと考えた事など。

ManagedDll を動的に読み込むあれこれ

流派は2つ。
Assembly 使って、動的にリンクする方法
http://athomejp.com/goldfish/vcs/assemblycall.asp

AppDomain 使って、動的にロードする方法
http://d.hatena.ne.jp/akiramei/20071111/1194786373

前者のほうが簡易だけど、後者はアンロードできるそうな。
デカいDLLなら迷わず後者だな。

見たい人だけサンプル

Assembly クラスによるロード

Assembly クラスで DLL を決め打ちで読み込み、ロードしてくる方法。インスタンスはActivatorで無理やり生成する。
インターフェース用意しとくと、アクセスが容易。
もし、インターフェースを用意しないのであれば、Type.GetMethod や、Type.GetProperty でMethodInfo とか PropertyInfo 経由でごにょごにょしなきゃいけない。

public interface IHello
{
    string getDllMessage();
}

で、これを継承してクラス(DLL)作成

namespace Hello
{
    public class SampleHello : DinamicDLLLoad.IHello
    {
        public string getDllMessage()
        {
            return "Mr,Azalea";
        }
    }
}

そして、これを動的に読み込むコード

static void Main(string[] args)
{
    while (true)
    {
        System.Threading.Thread.Sleep(500);
        if (System.IO.File.Exists("Hello.dll"))
            break;
        Console.WriteLine("Cannot find Hello.dll");
    }

    try
    {
        /* DLL を指定して読み込む */
        Assembly assembly = Assembly.LoadFrom("Hello.dll");
        Module module = assembly.GetModule("Hello.dll");
        Type type = module.GetType("Hello.SampleHello");

        /* インスタンスを作成する */
        IHello hello = Activator.CreateInstance(type) as IHello;

        Console.WriteLine("Hello " + hello.getDllMessage());
    }
    catch (Exception)
    { }
    Console.WriteLine("Push any key to exit;");
    Console.ReadLine();
}

AppDomain 使って読み込む

こっちの実装だと、アンロードが可能になる。
扱い的には子プロセス(みたいなもの)を立てて、ソコからさらに動的にクラスインスタンスを持ってくる。
だから、プロセス(Domain)が死ねば、dll も開放されるというワケ。

static void Main(string[] args)
{
    while (true)
    {
        System.Threading.Thread.Sleep(500);
        if (System.IO.File.Exists("Hello.dll"))
            break;
        Console.WriteLine("Cannot find Hello.dll");
    }

    AppDomainSetup setup = new AppDomainSetup();
    setup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
    
    /* シャドウコピーで dll を使うので、途中削除OK */
    setup.ShadowCopyFiles = "true";

    AppDomain mainDomain = AppDomain.CreateDomain("SampleCode", null, setup);
    IHello hello = mainDomain.CreateInstanceAndUnwrap("Hello", "Hello.SampleHello") as IHello;

    Console.WriteLine("Push any key to exit;");
    Console.ReadLine();
}