matsukawar's blog

個人的な技術ブログ。テクニカルアーキテクトを目指しています。Twitter : https://twitter.com/matsukawar

DLLを動的に読み込む

たとえば、DLLをプログラム動作中に、読み込んで、内部の機能を使いたいというケースがあります。これは、遅延バインディングと言います。通常は、事前バインディングで事が済みますが、やむ終えずこのような仕組みをとらざる終えない場合もあります。

MSDNでは、事前バインディング、つまり、事前に参照設定されたDLLを使うよう推奨されてます。それは、コンパイラが効率的にコンパイルするためでもあります。
実装方法はMSDNに載ってたのパクリですが、以下に示します。

//アセンブリを読み込む
Assembly oAssembly = Assembly.LoadFrom(@"C:\SAMPLE.dll");

//オブジェクトを生成する
Object oObject = oAssembly.CreateInstance("SAMPLE.NAMESPACE.CLASSNAME");

まず、任意のDLLを読み込みます。
Assenblyオブジェクトが生成されればOKです。

次に、ネームスペース名とクラス名を指定して、アセンブリからクラスのオブジェクトの実態を作ります。型はObject型としておきます。

//オブジェクトの型を取得
Type oType = oObject.GetType();

//メソッド情報を取得
MethodInfo oMethodInfo = oType.GetMethod("FUNCTIONNAME");

//引数用パラメータ作成
object[] oParam = new object[1];
oParam[0] = "PARAM";

//デリゲート呼び出し
oMethodInfo.Invoke(oObject, oParam);

オブジェクトの実態の型を取得し、GetMethodメソッドで、メソッド名を指定して、MethodInfoオブジェクトを取得します。

もしも、引数などある場合は、object型の配列で定義しておきます。

最後に、MethodInfoオブジェクトのInvokeメソッドを呼び出し、現在のアプリケーションのバインドを、指定したアセンブリの指定したメソッドへ付け替えます。

.Net Freamwork4からは、Dynamic Language Runtime(DRL)が実装されていますので、Dynamic型が使いやすいと思います。特に、インタプリタ言語をC#プログラム中から呼び出したりする場合は、必須です。

その他に、DllImportクラスってのがあります。
以下は、user32.dllというネイティブのDLLの中の、MessageBoxクラスを動的に呼び出す方法です。

[DllImport("user32.dll")]
public static extern int MessageBox(IntPtr hWnd, string lpText, string lpCaption, uint uType);

これはすごく便利なんですが、DLLをいったんロードして、バインドすると、アプリケーションが終了するまでアンロード(開放)しないという動作になりますので、使うときは要注意です。

なぜかというと、アセンブリの中には、いったん設定した情報を開放しないstaticなメンバが存在する可能性があるためです。windowsのネイティブのDLLの中には注意しないといけないものもあります。

回避策として、DLLの呼び出し部分だけを別EXEにして、呼び出し元からキックする方法が考えられます。これだと、DllImportしたとしても、それは、別EXE内だけの話。別EXEの処理が完了すればDLLはアンロードされます。