*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
C# にて、DLLの機能を動的に読み込む方法
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
「C# にて、DLLを取り扱う方法」における一連の説明(知恵ノート)において、ここでは、「C# にて、DLLの機能を動的に読み込む方法」について説明します。
総合の目次
本ページを含めた関連事項の総合目次です。
http://note.chiebukuro.yahoo.co.jp/detail/nooooooo
(注意: 総合目次は、まだ作っていません。関連するサンプルが幾つか増えたら、総合目次を作る予定です)
関連サンプル
現時点では、まだ作っていません(知恵ノートと言う形では)。
なお、通常のDLL呼び出しを関連サンプルにする予定です。
知恵ノート作成は、未着手なので、取りあえず「Q and A」のほうを参照して下さい。
下記の「自分で作るクラスライブラリ」と書かれた以降を参照して下さい。
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1020326470
注意事項: .NET のバージョン
本サンプルで使用している dynamic と言う型は、.NET Framework 4 から搭載された型です。
よって、それよりも前のバージョンを利用されている方は、本サンプルの機能の利用は無理です。
はじめに
通常では、DLLをインポートする側(利用する側)のプログラムをビルドする時に、利用するDLLが有る必要があります。
もしもない場合は、利用するDLL がないことを示すエラーが発生します。
すなわち、これは、プログラムの構成(DLL の機能の構成)はビルド時に決定していると言うことです。当たり前な話しですが。
これに対して、ここで紹介します手法では、ビルド時ではなく、動的に(実行時に)プログラムの構成(DLL の機能の構成)を決められます。
すなわち、ビルド時ではなく、実行時にDLL の機能が読み込まれる仕組みになっています。
よって、DLLをインポートする側(利用する側)のプログラムをビルドする時に、利用するDLLがなくてもエラーになりません。
つまり、DLL がないと言うエラーは、ビルドエラーではなく、実行時エラーとして発生します。
それでは、ここで紹介します手法の場合、どのようなプログラミングで活用するのでしょうか。
例えば、DLL を頻繁に入れ替える必要がある場合に、ここでの手法を使ったほうが良いと言えます。
なお、このように動的にプログラム(DLL)を読み込むことをプラグインと言います。
関連サンプルと比べた特徴
関連サンプルでは、インポート側(利用する側)のプログラムをビルドする際に、DLLの構成が決定している必要があります。
これに対して、今回のサンプルでは、動的に(実行時に)にDLLの機能が読み込まれます。
<関連サンプル>
プログラムの構成(DLL の機能の構成)は、ビルド時に決定する。
呼び出し元のプログラム(DLLを利用する側のプログラム)をビルドする時に、利用するDLLがないとエラーになる。
DLL 内のメソッドの使い方が間違っていた場合(文法的な間違いの場合)は、基本的にビルド時にエラーが出る。
<今回のサンプル>
プログラムの構成(DLL の機能の構成)は、実行時に決定することが可能である(実行時のユーザーの要求や、ユーザーの操作等に応じて、プログラム構成を取り決められる。すなわち、柔軟な処理が行ないたい場合に本方法が良い) ---> プラグイン
実行時に、呼び出し元のプログラム(DLLを利用する側のプログラム)に、DLLの機能が読み込まれる。よって、呼び出し元のプログラム(DLLを利用する側のプログラム)をビルドする時に、利用するDLLがなくてもエラーにならない。ただし、実行時にDLL が無い場合は、エラーになる(実行時エラー)。
DLL 内のメソッドの使い方が間違っていた場合(文法的な間違いの場合)は、実行時にエラーが出る場合が多い。
サンプルコード
ここで取り上げるサンプルは、なるべく複雑にならない範囲で、DLLの読み込みを確かめられるものとします。
本サンプルの仕様概要
以下では、エクスポート側(機能を公開する側)のプログラム、すなわち、DLL その物を、「エクスポート側プログラム」、又は、そのまま「DLL」と呼ぶことにします。
これに対して、インポート側(DLLを呼び出して利用する側)のプログラムのことを「インポート側プログラム」と呼ぶことにします。
<エクスポート側プログラムの仕様>
エクスポート側プログラムは、なるべく単純なプログラムとします。
具体的な仕様は、「こんにちは」と言う文字列をデーターとして持つクラスとします。
<インポート側プログラムの仕様>
DLL が持つデーター(「こんにちは」と言う文字列)を取得して、それをラベルに表示します。
<DLL のファイル名と、その保存場所>
本サンプルでは、DLL のファイル名を
C:\PluginExportPG.dll
とします。
すなわち、ビルド後(完成後)のDLL である PluginExportPG.dll は、Cドライブの直下に移動(又はコピー)して下さい。なお、別のファイル名、又は別の保存場所にしたい場合は、インポート側プログラム(DLLを利用する側のプログラム)の該当箇所のコードを書き替えて下さい。
<DLL 内のクラス名の仕様>
DLL 内のエクスポート(機能の外部公開)しているクラスのクラス名は、ネームスペース(名前空間)を含めて、
PluginExportPG.TestClass
とします。
よって、別のクラス名にした場合は、サンプルコードの該当箇所を書き替えて下さい(特に、DLL 作成時のプロジェクト名を、指示の名前と異なるものにしている場合、ネームスペースの名前が変更されています。よって、その点を注意して下さい)。
エクスポート側プログラム(DLL)におけるフォームデザイン等の前準備
コードを記述する前に、フォームのデザイン作成などの、以下の前準備を行なって下さい。
<プロジェクトの作成>
本サンプルの確認用に、新規にプロジェクトを作成して下さい。
プロジェクトの種類は、「クラスライブラリ」です。
なお、下記のサンプルでは、PluginExportPG と言うプロジェクト名にしました。
<イベントプロシージャの作成>
今回のサンプルでは、イベントプロシージャの作成は、行ないません。
(よって、ここでの作業は、特にありません)
インポート側プログラムにおけるフォームデザイン等の前準備
コードを記述する前に、フォームのデザイン作成などの、以下の前準備を行なって下さい。
<プロジェクトの作成>
本サンプルの確認用に、新規にプロジェクトを作成して下さい。
プロジェクトの種類は、「Windowsフォームアプリケーション」です。
なお、下記のサンプルでは、PluginImportPG と言うプロジェクト名にしました。
<フォームのデザイン>
デザイン画面で、ラベル(label)を1個貼り付けて下さい。
<イベントプロシージャの作成>
デザイン画面のフォーム(無地の部分)をダブルクリックして、Form1_Load() メソッド を作って下さい。
エクスポート側プログラム(DLL)におけるソースコード
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PluginExportPG
{
public class TestClass
{
//============
// メンバー変数
public string MessageData;
//============
// コンストラクタ
public TestClass()
{
// データー格納用のメンバー変数を初期化設定
MessageData = "こんにちは";
}
//============
// データー取得用メソッド
// 戻り値: 取得データー
public string GetMessageData()
{
return MessageData;
}
//============
// データー設定用メソッド
// 第1引数: 設定データー
public void SetMessageData(string Message_Data)
{
MessageData = Message_Data;
}
}
}
インポート側プログラムにおけるソースコード
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace PluginImportPG
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// DLL を指定して、動的にアセンブリをロードする。
System.Reflection.Assembly assem = System.Reflection.Assembly.LoadFrom("C:\\PluginExportPG.dll");
// 指定のアセンブリから、指定クラスのType オブジェクトを取得。
Type AssType = assem.GetType("PluginExportPG.TestClass");
// 指定した型(Type オブジェクト)のインスタンスを生成。
dynamic obj = Activator.CreateInstance(AssType);
// DLL 内にあるメソッドを実行
label1.Text = obj.GetMessageData();
}
}
}
コードの解説
<エクスポート側プログラム>
DLL(エクスポート側プログラム)の作成方法は、一般のクラスライブラリの作成(関連サンプル)と同じです。
<インポート側プログラム>
インポート側プログラム(DLL を利用する側)については、DLL をインポートするための手続きが必要です。
まず、System.Reflection.Assembly.LoadFrom()メソッドで、指定のDLL を(動的に)読み込みます。
次に、先程読み込んだもの(アセンブリと言う)の中から、利用したいクラスを探し出します。
そのクラスの探し出しは、System.Reflection.Assembly.GetType()メソッドの引数に、該当のクラス名を指定することによって、探し出します。
なお、探し出したクラスは、Type オブジェクトと言う形で、取得します。
このType オブジェクトは、名前の通り、型(「型」の英語は、「Type」)の情報を格納することが可能なオブジェクトです。
次に、Activator.CreateInstance()メソッドにおいて、その引数に、先程取得したType オブジェクトを指定して実行すれば、目的のクラスオブジェクトを生成することが可能です。
あとは、そのクラスオブジェクトを使って、普通に、該当クラスのメンバー(メソッドや変数)を使用して下さい。-
実行前の注意事項
「本サンプの仕様概要」でも述べましたように、ビルド後(完成後)のDLL は、所定の場所に置いて下さい(上記のサンプルコードのままならば、Cドライブの直下)。
実行結果
プログラムを実行すると、「こんにちは」と言う文字が表示されます。
さいごに
プラグイン以外の目的では、.NET Framework 4 から搭載された「動的言語ランタイム (DLR)」と言う機能を活用する場合に、本サンプルの手法の活用が有効的です。