┏第40号━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃         .NETプログラミング研究         ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ──<メニュー>─────────────────────── ■.NET Tips ・プラグイン機能を持つアプリケーションを作成する - その2 ─────────────────────────────── ─────────────────────────────── ■.NET Tips ─────────────────────────────── ●プラグイン機能を持つアプリケーションを作成する - その2 (お詫び)今回はコードがかなり長くなってしまいました。ご了承く ださい。 前回の「プラグイン機能を持つアプリケーションを作成する - その 1」ではプラグイン機能を実現させるための基本的な考え方について 説明しました。簡単に復習すると、その方法とは、インターフェイス を使用するというものでした。詳細は前回のメールマガジンでご確認 ください。 [URL].NETプログラミング研究 第39号 http://backno.mag2.com/reader/BackBody?id=200408160600000000104516000 今回はさらに実用的な例として、Windowsアプリケーションでプラグ イン機能を実現する方法を考えます。ここでは具体的に、プラグイン の使用できる簡単なエディタを作成します。 あくまでプラグイン機能を説明することが目的ですので、エディタは 思い切り単純にし、フォームにRichTextBoxとMainMenuのみを配置す ることにします。プラグインからエディタのRichTextBoxコントロー ルにアクセスすることにより、プラグインの機能が果たせるようにし ます。 ★インターフェイスを定義する 前回と同じように、まずプラグインのクラスが実装すべきインターフ ェイスを定義します。今回はプラグインのインターフェイスに加えて、 プラグインを使用するホストの側が実装すべきインターフェイスも定 義することにします。ホストのためのインターフェイスでは、プラグ インのホストとして必要な機能をメンバとして定義し、プラグインか らこのメンバを通してホストにアクセスできるようにします。 具体的には、プラグインから指定されたメッセージをホストで表示す るためのメソッドと、ホストのRichTextBoxコントロールを取得する ためのプロパティ、さらにホストのメインフォームを取得するための プロパティを定義することにします。 それでは実際にこれらのインターフェイスを作成してみましょう。前 号と同様、クラスライブラリとして作成するため、Visual Studio .NETではクラスライブラリのプロジェクトを作成し("Plugin"という 名前で作成しています)、.NET SDKでは/target:libraryコンパイラ オプションを使用します。また、アセンブリファイル名は、"Plugin. dll"とします。さらに今回はWindowsアプリケーションを扱うため、 "System.Windows.Forms.dll"を参照に追加します。(参照に追加する には、Visual Studio .NETの場合は、ソリューションエクスプローラ の「参照設定」を、.NET SDKの場合は、/referenceコンパイラオプシ ョンを使用します。) コードは、次のようになります。IPluginインターフェイスがプラグ インのためのインターフェイスで、IPluginHostインターフェイスが プラグインのホストのためのインターフェイスです。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Imports System Imports System.Windows.Forms Namespace Plugin ''' ''' プラグインで実装するインターフェイス ''' Public Interface IPlugin ''' ''' プラグインの名前 ''' ReadOnly Property Name() As String ''' ''' プラグインのバージョン ''' ReadOnly Property Version() As String ''' ''' プラグインの説明 ''' ReadOnly Property Description() As String ''' ''' プラグインのホスト ''' Property Host() As IPluginHost ''' ''' プラグインを実行する ''' Sub Run() End Interface ''' ''' プラグインのホストで実装するインターフェイス ''' Public Interface IPluginHost ''' ''' ホストのメインフォーム ''' ReadOnly Property MainForm() As Form ''' ''' ホストのRichTextBoxコントロール ''' ReadOnly Property RichTextBox() As RichTextBox ''' ''' ホストでメッセージを表示する ''' ''' メソッドを呼び出すプラグイン ''' 表示するメッセージ Sub ShowMessage(ByVal plugin As IPlugin, ByVal msg As String) End Interface End Namespace ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ using System; using System.Windows.Forms; namespace Plugin { /// /// プラグインで実装するインターフェイス /// public interface IPlugin { /// /// プラグインの名前 /// string Name {get;} /// /// プラグインのバージョン /// string Version {get;} /// /// プラグインの説明 /// string Description {get;} /// /// プラグインのホスト /// IPluginHost Host {get; set;} /// /// プラグインを実行する /// void Run(); } /// /// プラグインのホストで実装するインターフェイス /// public interface IPluginHost { /// /// ホストのメインフォーム /// Form MainForm {get;} /// /// ホストのRichTextBoxコントロール /// RichTextBox RichTextBox {get;} /// /// ホストでメッセージを表示する /// /// メソッドを呼び出すプラグイン /// 表示するメッセージ void ShowMessage(IPlugin plugin, string msg); } } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ IPluginは前回と比べ、プラグインのバージョンと説明を取得するた めのプロパティが新たに追加され、さらに、Runメソッドもパラメー タ、返り値がなくなりました。また、IPluginHostを設定、取得する ためのプロパティも加えられています。 ★プラグインを作成する 次に、IPluginインターフェイスを実装したプラグインのクラスを作 成します。ここでは、RichTextBox内の文字数を表示するプラグイン (CountCharsクラス)を作成してみましょう。 プラグインも前号と同様に、クラスライブラリとして作成し、 "Plugin.dll"を参照に追加します。また、"System.Windows.Forms. dll"も参照に追加してください。出力するアセンブリファイル名は、 "CountChars.dll"とします。(Visual Studio .NETのVB.NETの場合は、 プロジェクトのプロパティの「ルート名前空間」が空白になっている ものとします。デフォルトではプロジェクト名となっていますので、 変更する必要があります。) CountCharsクラスのコードは次のようになります。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Imports System Namespace CountChars ''' ''' 文字数を表示するためのプラグイン ''' Public Class CountChars Implements Plugin.IPlugin Private _host As Plugin.IPluginHost 'IPluginのメンバ Public ReadOnly Property Name() As String _ Implements Plugin.IPlugin.Name Get Return "文字数取得" End Get End Property Public ReadOnly Property Version() As String _ Implements Plugin.IPlugin.Version Get '自分自身のAssemblyを取得し、バージョンを返す Dim asm As System.Reflection.Assembly = _ System.Reflection.Assembly.GetExecutingAssembly() Dim ver As System.Version = asm.GetName().Version Return ver.ToString() End Get End Property Public ReadOnly Property Description() As String _ Implements Plugin.IPlugin.Description Get Return "エディタで編集中の文章の文字数を表示します。" End Get End Property Public Property Host() As Plugin.IPluginHost _ Implements Plugin.IPlugin.Host Get Return Me._host End Get Set(ByVal Value As Plugin.IPluginHost) Me._host = Value End Set End Property ''' ''' RichTextBoxの文字数を表示する ''' Public Sub Run() Implements Plugin.IPlugin.Run Dim msg As String = String.Format("文字数 : {0} 文字", _ Me._host.RichTextBox.Text.Length) Me._host.ShowMessage(Me, msg) End Sub End Class End Namespace ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ using System; namespace CountChars { /// /// 文字数を表示するためのプラグイン /// public class CountChars : Plugin.IPlugin { private Plugin.IPluginHost _host; //IPluginのメンバ public string Name { get { return "文字数取得"; } } public string Version { get { //自分自身のAssemblyを取得し、バージョンを返す System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); System.Version ver = asm.GetName().Version; return ver.ToString(); } } public string Description { get { return "エディタで編集中の文章の文字数を表示します。"; } } public Plugin.IPluginHost Host { get { return this._host; } set { this._host = value; } } /// /// RichTextBoxの文字数を表示する /// public void Run() { string msg = string.Format("文字数 : {0} 文字", this._host.RichTextBox.Text.Length); this._host.ShowMessage(this, msg); } } } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ 特に説明を必要とする箇所はないでしょう。Runメソッドでは、 IPluginHostオブジェクトからRichTextBoxにアクセスし、文字数を取 得し、IPluginHostのShowMessageメソッドで結果をホストで表示して います。 ★ウィンドウを表示するプラグインの作成 次にWindowsアプリケーションらしく、ウィンドウを表示するプラグ インを作成してみましょう。ここでは、「検索」ウィンドウにより、 RichTextBoxから指定された文字列を検索するプラグインを作ります (エディタとしては、プラグインで処理する機能ではありませんが)。 まず、CountCharsクラスと同様、クラスライブラリのプロジェクトを 作成し(名前は、"FindString"とします)、"Plugin.dll"と"System. Windows.Forms.dll"を参照に追加します("System.Windows.Forms. dll"は今追加しなくても、「Windowsフォームの追加」でプロジェク トにフォームを追加すれば、自動的に追加されます)。 続いて、「Windowsフォームの追加」でプロジェクトにフォーム( FindForm)を追加し、「検索」ウィンドウを作成します。このフォー ムに配置するコントロール及び、変更するプロパティ(あるいはイベ ント)の一覧は次のようになります。 コントロール: Form Name: FindForm Text: 検索 AcceptButton: findButton CancelButton: closeButton FormBorderStyle: FixedToolWindow ShowInTaskbar: false コントロール: TextBox Name: findString Text: "" コントロール: Button Name: findButton Text: 次を検索 DialogResult: OK Clickイベント: findButton_Click コントロール: Button Name: closeButton Text: 閉じる DialogResult: Cancel Clickイベント: closeButton_Click コントロール: CheckBox Name: wholeWord Text: 単語単位で検索する コントロール: CheckBox Name: matchCase Text: 大文字小文字を区別する コントロール: CheckBox Name: reverse Text: 上へ検索する さらに、FindFormクラスに次のコードを追加し、指定された RichTextBoxを検索できるようにします。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ 'Imports System.Windows.Forms 'がコードの先頭に書かれているものとする '検索するRichTextBox Friend RichTextBox As RichTextBox Private Sub findButton_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles findButton.Click '検索オプションを決定する Dim finds As RichTextBoxFinds = RichTextBoxFinds.None If Me.wholeWord.Checked Then finds = finds Or RichTextBoxFinds.WholeWord End If If Me.matchCase.Checked Then finds = finds Or RichTextBoxFinds.MatchCase End If If Me.reverse.Checked Then finds = finds Or RichTextBoxFinds.Reverse End If '検索範囲を決定する Dim startPos, endPos As Integer If Not Me.reverse.Checked Then startPos = Me.RichTextBox.SelectionStart + _ Me.RichTextBox.SelectionLength endPos = -1 If startPos >= Me.RichTextBox.TextLength Then MessageBox.Show("検索が完了しました。", "検索") Return End If Else startPos = 0 endPos = Me.RichTextBox.SelectionStart If endPos <= 0 Then MessageBox.Show("検索が完了しました。", "検索") Return End If End If '検索する If Me.RichTextBox.Find( _ findString.Text, startPos, endPos, finds) < 0 Then MessageBox.Show("検索が完了しました。", "検索") Else Me.RichTextBox.Focus() End If End Sub Private Sub closeButton_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles closeButton.Click Me.Close() End Sub ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ //using System.Windows.Forms; //がコードの先頭に書かれているものとする //検索するRichTextBox internal RichTextBox RichTextBox; //「次を検索」がクリックされた時 private void findButton_Click( object sender, System.EventArgs e) { //検索オプションを決定する RichTextBoxFinds finds = RichTextBoxFinds.None; if (this.wholeWord.Checked) finds |= RichTextBoxFinds.WholeWord; if (this.matchCase.Checked) finds |= RichTextBoxFinds.MatchCase; if (this.reverse.Checked) finds |= RichTextBoxFinds.Reverse; //検索範囲を決定する int startPos, endPos; if (!this.reverse.Checked) { startPos = this.RichTextBox.SelectionStart + this.RichTextBox.SelectionLength; endPos = -1; if (startPos >= this.RichTextBox.TextLength) { MessageBox.Show("検索が完了しました。", "検索"); return; } } else { startPos = 0; endPos = this.RichTextBox.SelectionStart; if (endPos <= 0) { MessageBox.Show("検索が完了しました。", "検索"); return; } } //検索する if (this.RichTextBox.Find( findString.Text, startPos, endPos, finds) < 0) MessageBox.Show("検索が完了しました。", "検索"); else this.RichTextBox.Focus(); } //「閉じる」がクリックされた時 private void closeButton_Click( object sender, System.EventArgs e) { this.Close(); } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ 次にこのフォームを表示させるプラグインクラス(FindString)を作 成します。コードは、次のようになります。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Imports System Imports System.Windows.Forms Namespace FindString Public Class FindString Implements Plugin.IPlugin Private _host As Plugin.IPluginHost Private _mainForm As FindForm 'IPluginのメンバ Public ReadOnly Property Name() As String _ Implements Plugin.IPlugin.Name Get Return "文字列の検索" End Get End Property Public ReadOnly Property Description() As String _ Implements Plugin.IPlugin.Description Get Return "編集中の文章から指定された文字列を検索します。" End Get End Property Public Property Host() As Plugin.IPluginHost _ Implements Plugin.IPlugin.Host Get Return _host End Get Set(ByVal Value As Plugin.IPluginHost) _host = Value End Set End Property Public ReadOnly Property Version() As String _ Implements Plugin.IPlugin.Version Get '自分自身のAssemblyを取得し、バージョンを返す Dim asm As System.Reflection.Assembly = _ System.Reflection.Assembly.GetExecutingAssembly() Dim ver As System.Version = asm.GetName().Version Return ver.ToString() End Get End Property Public Sub Run() Implements Plugin.IPlugin.Run 'フォームが表示されていれば、アクティブにして終了 If Not (Me._mainForm Is Nothing) AndAlso _ Not Me._mainForm.IsDisposed Then Me._mainForm.Activate() Return End If '検索ウィンドウを作成し、表示する Me._mainForm = New FindForm Me._mainForm.RichTextBox = Me._host.RichTextBox Me._mainForm.Owner = Me._host.MainForm Me._mainForm.Show() End Sub End Class End Namespace ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ using System; using System.Windows.Forms; namespace FindString { public class FindString : Plugin.IPlugin { private Plugin.IPluginHost _host; private FindForm _mainForm; //IPluginのメンバ public string Name { get { return "文字列の検索"; } } public string Description { get { return "編集中の文章から指定された文字列を検索します。"; } } public Plugin.IPluginHost Host { get { return _host; } set { _host = value; } } public string Version { get { //自分自身のAssemblyを取得し、バージョンを返す System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); System.Version ver = asm.GetName().Version; return ver.ToString(); } } public void Run() { //フォームが表示されていれば、アクティブにして終了 if (this._mainForm != null && !this._mainForm.IsDisposed) { this._mainForm.Activate(); return; } //検索ウィンドウを作成し、表示する this._mainForm = new FindForm(); this._mainForm.RichTextBox = this._host.RichTextBox; this._mainForm.Owner = this._host.MainForm; this._mainForm.Show(); } } } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ RunメソッドでFindFormを表示しているだけで、特に問題はないでし ょう。(表示する前にRichTextBoxの設定と、オーナーウィンドウの 設定を行っています。) ★メインアプリケーションの作成 ようやくここまでたどり着きました。いよいよプラグインを使用する ホストのアプリケーションを作成します。 ホストアプリケーションは、Windowsアプリケーションプロジェクト として作成し(名前は、"MainApplication"とします)、"Plugin.dll "を参照に追加します。 フォームには、RichTextBoxと、メニュー、さらにメッセージを表示 するためのStatusBarコントロールを配置します。変更するフォーム のプロパティと、フォームに配置するコントロールとそのプロパティ (そしてイベント)の一覧を以下に示します。 コントロール: Form Name: Form1 Menu: mainMenu Loadイベント: Form1_Load コントロール: RichTextBox Name: mainRichTextBox Dock: Fill コントロール: StatusBar Name: mainStatusbar コントロール: MainMenu Name: mainMenu コントロール: MenuItem Name: menuPlugins Text: プラグイン(&P) コントロール: MenuItem Name: menuHelp Text: ヘルプ(&H) コントロール: MenuItem Name: menuAbout Text: バージョン情報(&A)... Clickイベント: menuAbout_Click 次に前号で作成したPluginInfoクラスをプロジェクトに追加します。 ただし、CreateInstanceメソッドでIPluginHostオブジェクトを IPluginHost.Hostプロパティに設定するように変更しています。 PluginInfoクラスは次のようなコードです。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Imports System ''' ''' プラグインに関する情報 ''' Public Class PluginInfo Private _location As String Private _className As String ''' ''' PluginInfoクラスのコンストラクタ ''' ''' アセンブリファイルのパス ''' クラスの名前 Private Sub New(ByVal path As String, ByVal cls As String) Me._location = path Me._className = cls End Sub ''' ''' アセンブリファイルのパス ''' Public ReadOnly Property Location() As String Get Return _location End Get End Property ''' ''' クラスの名前 ''' Public ReadOnly Property ClassName() As String Get Return _className End Get End Property ''' ''' 有効なプラグインを探す ''' ''' 有効なプラグインのPluginInfo配列 Public Shared Function FindPlugins() As PluginInfo() Dim plugins As New System.Collections.ArrayList 'IPlugin型の名前 Dim ipluginName As String = _ GetType(Plugin.IPlugin).FullName 'プラグインフォルダ Dim folder As String = _ System.IO.Path.GetDirectoryName( _ System.Reflection.Assembly. _ GetExecutingAssembly().Location) folder += "\plugins" If Not System.IO.Directory.Exists(folder) Then Throw New ApplicationException( _ "プラグインフォルダ""" + folder + _ """が見つかりませんでした。") End If '.dllファイルを探す Dim dlls As String() = _ System.IO.Directory.GetFiles(folder, "*.dll") Dim dll As String For Each dll In dlls Try 'アセンブリとして読み込む Dim asm As System.Reflection.Assembly = _ System.Reflection.Assembly.LoadFrom(dll) Dim t As Type For Each t In asm.GetTypes() 'アセンブリ内のすべての型について、 'プラグインとして有効か調べる If t.IsClass And t.IsPublic And _ Not t.IsAbstract And _ Not (t.GetInterface(ipluginName) Is Nothing _ ) Then 'PluginInfoをコレクションに追加する plugins.Add(New PluginInfo(dll, t.FullName)) End If Next t Catch End Try Next dll 'コレクションを配列にして返す Return CType(plugins.ToArray( _ GetType(PluginInfo)), PluginInfo()) End Function 'FindPlugins ''' ''' プラグインクラスのインスタンスを作成する ''' ''' プラグインクラスのインスタンス Public Function CreateInstance( _ ByVal host As Plugin.IPluginHost) As Plugin.IPlugin Try 'アセンブリを読み込む Dim asm As System.Reflection.Assembly = _ System.Reflection.Assembly.LoadFrom(Me.Location) 'クラス名からインスタンスを作成する Dim plugin As Plugin.IPlugin = _ CType(asm.CreateInstance(Me.ClassName), _ Plugin.IPlugin) 'IPluginHostの設定 plugin.Host = host Return plugin Catch End Try End Function End Class ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ using System; namespace MainApplication { /// /// プラグインに関する情報 /// public class PluginInfo { private string _location; private string _className; /// /// PluginInfoクラスのコンストラクタ /// /// アセンブリファイルのパス /// クラスの名前 private PluginInfo(string path, string cls) { this._location = path; this._className = cls; } /// /// アセンブリファイルのパス /// public string Location { get {return _location;} } /// /// クラスの名前 /// public string ClassName { get {return _className;} } /// /// 有効なプラグインを探す /// /// 有効なプラグインのPluginInfo配列 public static PluginInfo[] FindPlugins() { System.Collections.ArrayList plugins = new System.Collections.ArrayList(); //IPlugin型の名前 string ipluginName = typeof(Plugin.IPlugin).FullName; //プラグインフォルダ string folder = System.IO.Path.GetDirectoryName( System.Reflection.Assembly .GetExecutingAssembly().Location); folder += "\\plugins"; if (!System.IO.Directory.Exists(folder)) throw new ApplicationException( "プラグインフォルダ\"" + folder + "\"が見つかりませんでした。"); //.dllファイルを探す string[] dlls = System.IO.Directory.GetFiles(folder, "*.dll"); foreach (string dll in dlls) { try { //アセンブリとして読み込む System.Reflection.Assembly asm = System.Reflection.Assembly.LoadFrom(dll); foreach (Type t in asm.GetTypes()) { //アセンブリ内のすべての型について、 //プラグインとして有効か調べる if (t.IsClass && t.IsPublic && !t.IsAbstract && t.GetInterface(ipluginName) != null) { //PluginInfoをコレクションに追加する plugins.Add( new PluginInfo(dll, t.FullName)); } } } catch { } } //コレクションを配列にして返す return (PluginInfo[]) plugins.ToArray(typeof(PluginInfo)); } /// /// プラグインクラスのインスタンスを作成する /// /// プラグインクラスのインスタンス public Plugin.IPlugin CreateInstance(Plugin.IPluginHost host) { try { //アセンブリを読み込む System.Reflection.Assembly asm = System.Reflection.Assembly.LoadFrom(this.Location); //クラス名からインスタンスを作成する Plugin.IPlugin plugin = (Plugin.IPlugin) asm.CreateInstance(this.ClassName); //IPluginHostの設定 plugin.Host = host; return plugin; } catch { return null; } } } } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ IPluginHostインターフェイスは、フォームクラスで実装します。ま た、プラグインの読み込みと、メニューへの表示はフォームのLoadイ ベントハンドラで行い、メニューを選択することにより、プラグイン を実行できるようにします。 以下に変更を加えたフォームクラスの主要部分のコード(Windowsフ ォームデザイナが作成したコードを除く)を示します。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Public Class Form1 Inherits System.Windows.Forms.Form Implements Plugin.IPluginHost '(省略) 'IPluginの配列 Dim plugins() As Plugin.IPlugin 'IPluginHostの実装 Public ReadOnly Property MainForm() As Form _ Implements Plugin.IPluginHost.MainForm Get Return Me End Get End Property Public ReadOnly Property RichTextBox() As RichTextBox _ Implements Plugin.IPluginHost.RichTextBox Get Return mainRichTextBox End Get End Property Public Sub ShowMessage(ByVal plugin As Plugin.IPlugin, _ ByVal msg As String) _ Implements Plugin.IPluginHost.ShowMessage 'ステータスバーに表示する mainStatusbar.Text = msg End Sub 'メインフォームのLoadイベントハンドラ Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load 'インストールされているプラグインを探す Dim pis As PluginInfo() = PluginInfo.FindPlugins() 'プラグインのインスタンスを取得する Me.plugins = New Plugin.IPlugin(pis.Length - 1) {} Dim i As Integer For i = 0 To (Me.plugins.Length) - 1 Me.plugins(i) = pis(i).CreateInstance(Me) Next i 'プラグインを実行するメニューを追加する Dim plugin As Plugin.IPlugin For Each plugin In Me.plugins Dim mi As New MenuItem(plugin.Name, _ AddressOf menuPlugin_Click) Me.menuPlugins.MenuItems.Add(mi) Next plugin End Sub 'プラグインのメニューがクリックされた時 Private Sub menuPlugin_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles menuPlugins.Click Dim mi As MenuItem = CType(sender, MenuItem) 'クリックされたプラグインを探す '(同じ名前のプラグインが複数あると困ったことに...) Dim plugin As Plugin.IPlugin For Each plugin In Me.plugins If mi.Text = plugin.Name Then 'クリックされたプラグインを実行する plugin.Run() Return End If Next plugin End Sub 'プラグインのバージョンを表示する Private Sub menuAbout_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles menuAbout.Click Dim msg As String = "インストールされているプラグイン" + vbLf _ + "(名前 : 説明 : バージョン)" + vbLf + vbLf Dim plugin As Plugin.IPlugin For Each plugin In Me.plugins msg += String.Format("{0} : {1} : {2}" + vbLf, _ plugin.Name, plugin.Description, plugin.Version) Next plugin MessageBox.Show(msg) End Sub End Class ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ namespace MainApplication { /// /// Form1 の概要の説明です。 /// public class Form1 : System.Windows.Forms.Form, Plugin.IPluginHost { //(省略) //IPluginの配列 Plugin.IPlugin[] plugins; //IPluginHostの実装 public Form MainForm { get { return (Form) this; } } public RichTextBox RichTextBox { get { return mainRichTextBox; } } public void ShowMessage(Plugin.IPlugin plugin, string msg) { //ステータスバーに表示する mainStatusbar.Text = msg; } //メインフォームのLoadイベントハンドラ private void Form1_Load(object sender, System.EventArgs e) { //インストールされているプラグインを探す PluginInfo[] pis = PluginInfo.FindPlugins(); //プラグインのインスタンスを取得する this.plugins = new Plugin.IPlugin[pis.Length]; for (int i = 0; i < this.plugins.Length; i++) this.plugins[i] = pis[i].CreateInstance(this); //プラグインを実行するメニューを追加する foreach (Plugin.IPlugin plugin in this.plugins) { MenuItem mi = new MenuItem(plugin.Name, new EventHandler(menuPlugin_Click)); this.menuPlugins.MenuItems.Add(mi); } } //プラグインのメニューがクリックされた時 private void menuPlugin_Click( object sender, System.EventArgs e) { MenuItem mi = (MenuItem) sender; //クリックされたプラグインを探す //(同じ名前のプラグインが複数あると困ったことに...) foreach (Plugin.IPlugin plugin in this.plugins) { if (mi.Text == plugin.Name) { //クリックされたプラグインを実行する plugin.Run(); return; } } } //プラグインのバージョンを表示する private void menuAbout_Click( object sender, System.EventArgs e) { string msg = "インストールされているプラグイン\n" + "(名前 : 説明 : バージョン)\n\n"; foreach (Plugin.IPlugin plugin in this.plugins) { msg += string.Format("{0} : {1} : {2}\n", plugin.Name, plugin.Description, plugin.Version); } MessageBox.Show(msg); } } } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ このメインアプリケーションを実行させるには、実行ファイルのある フォルダに"plugins"というフォルダを作り、そこに前に作成したプ ラグイン"CountChars.dll"と"FindString.dll"をコピーしてください。 うまくいくと、「プラグイン」メニューに「文字数取得」と「文字列 の検索」が追加され、プラグインの機能を呼び出すことができるよう になります。 以上でプラグイン機能を実現させる方法に関する解説はおしまいです。 ここで紹介した知識を応用することにより、より複雑なプラグインも 作成できるでしょう。この記事を読んで、プラグインを使ったアプリ ケーションを作ってみようと思われる方が一人でもいらっしゃるなら ばうれしいのですが。 =============================== ■このマガジンの購読、購読中止、バックナンバー、説明に関しては  次のページをご覧ください。  http://www.mag2.com/m/0000104516.htm ■発行人・編集人:どぼん!  (Microsoft MVP for Visual Basic, Oct 2003-Oct 2004)  http://dobon.net  dobon_info@yahoo.co.jp ■ご質問等はメールではなく、掲示板へお願いいたします。  http://dobon.net/vb/bbs.html ■上記メールアドレスへのメールは確実に読まれる保障はありません  (スパム、ウィルス対策です)。メールは下記URLのフォームメール  から送信してください。  http://dobon.net/mail.html Copyright (c) 2003 - 2004 DOBON! All rights reserved. ===============================