- 追加された行はこの色です。
- 削除された行はこの色です。
#title(.NETプログラミング研究 第40号)
#navi(.NETプログラミング研究)
#contents
*.NETプログラミング研究 第40号 [#ucb8d008]
**.NET Tips [#k1b62165]
**プラグイン機能を持つアプリケーションを作成する - その2 [#u9b56728]
#column(注意){{
この記事の最新版は「[[プラグイン機能を持つアプリケーションを作成する>http://dobon.net/vb/dotnet/programing/plugin.html]]」で公開しています。
}}
(お詫び)今回はコードがかなり長くなってしまいました。ご了承ください。
前回の「プラグイン機能を持つアプリケーションを作成する - その1」ではプラグイン機能を実現させるための基本的な考え方について説明しました。簡単に復習すると、その方法とは、インターフェイスを使用するというものでした。詳細は前回のメールマガジンでご確認ください。
-[[.NETプログラミング研究 第39号>../39]]
今回はさらに実用的な例として、Windowsアプリケーションでプラグイン機能を実現する方法を考えます。ここでは具体的に、プラグインの使用できる簡単なエディタを作成します。
あくまでプラグイン機能を説明することが目的ですので、エディタは思い切り単純にし、フォームにRichTextBoxとMainMenuのみを配置することにします。プラグインからエディタのRichTextBoxコントロールにアクセスすることにより、プラグインの機能が果たせるようにします。
***インターフェイスを定義する [#m998a78d]
前回と同じように、まずプラグインのクラスが実装すべきインターフェイスを定義します。今回はプラグインのインターフェイスに加えて、プラグインを使用するホストの側が実装すべきインターフェイスも定義することにします。ホストのためのインターフェイスでは、プラグインのホストとして必要な機能をメンバとして定義し、プラグインからこのメンバを通してホストにアクセスできるようにします。
具体的には、プラグインから指定されたメッセージをホストで表示するためのメソッドと、ホストのRichTextBoxコントロールを取得するためのプロパティ、さらにホストのメインフォームを取得するためのプロパティを定義することにします。
それでは実際にこれらのインターフェイスを作成してみましょう。前号と同様、クラスライブラリとして作成するため、Visual Studio .NETではクラスライブラリのプロジェクトを作成し("Plugin"という名前で作成しています)、.NET SDKでは/target:libraryコンパイラオプションを使用します。また、アセンブリファイル名は、"Plugin.dll"とします。さらに今回はWindowsアプリケーションを扱うため、"System.Windows.Forms.dll"を参照に追加します。(参照に追加するには、Visual Studio .NETの場合は、ソリューションエクスプローラの「参照設定」を、.NET SDKの場合は、/referenceコンパイラオプションを使用します。)
コードは、次のようになります。IPluginインターフェイスがプラグインのためのインターフェイスで、IPluginHostインターフェイスがプラグインのホストのためのインターフェイスです。
#code(vbnet){{
Imports System
Imports System.Windows.Forms
Namespace Plugin
''' <summary>
''' プラグインで実装するインターフェイス
''' </summary>
Public Interface IPlugin
''' <summary>
''' プラグインの名前
''' </summary>
ReadOnly Property Name() As String
''' <summary>
''' プラグインのバージョン
''' </summary>
ReadOnly Property Version() As String
''' <summary>
''' プラグインの説明
''' </summary>
ReadOnly Property Description() As String
''' <summary>
''' プラグインのホスト
''' </summary>
Property Host() As IPluginHost
''' <summary>
''' プラグインを実行する
''' </summary>
Sub Run()
End Interface
''' <summary>
''' プラグインのホストで実装するインターフェイス
''' </summary>
Public Interface IPluginHost
''' <summary>
''' ホストのメインフォーム
''' </summary>
ReadOnly Property MainForm() As Form
''' <summary>
''' ホストのRichTextBoxコントロール
''' </summary>
ReadOnly Property RichTextBox() As RichTextBox
''' <summary>
''' ホストでメッセージを表示する
''' </summary>
''' <param name="plugin">メソッドを呼び出すプラグイン</param>
''' <param name="msg">表示するメッセージ</param>
Sub ShowMessage(ByVal plugin As IPlugin, ByVal msg As String)
End Interface
End Namespace
}}
#code(csharp){{
using System;
using System.Windows.Forms;
namespace Plugin
{
/// <summary>
/// プラグインで実装するインターフェイス
/// </summary>
public interface IPlugin
{
/// <summary>
/// プラグインの名前
/// </summary>
string Name {get;}
/// <summary>
/// プラグインのバージョン
/// </summary>
string Version {get;}
/// <summary>
/// プラグインの説明
/// </summary>
string Description {get;}
/// <summary>
/// プラグインのホスト
/// </summary>
IPluginHost Host {get; set;}
/// <summary>
/// プラグインを実行する
/// </summary>
void Run();
}
/// <summary>
/// プラグインのホストで実装するインターフェイス
/// </summary>
public interface IPluginHost
{
/// <summary>
/// ホストのメインフォーム
/// </summary>
Form MainForm {get;}
/// <summary>
/// ホストのRichTextBoxコントロール
/// </summary>
RichTextBox RichTextBox {get;}
/// <summary>
/// ホストでメッセージを表示する
/// </summary>
/// <param name="plugin">メソッドを呼び出すプラグイン</param>
/// <param name="msg">表示するメッセージ</param>
void ShowMessage(IPlugin plugin, string msg);
}
}
}}
IPluginは前回と比べ、プラグインのバージョンと説明を取得するためのプロパティが新たに追加され、さらに、Runメソッドもパラメータ、返り値がなくなりました。また、IPluginHostを設定、取得するためのプロパティも加えられています。
***プラグインを作成する [#kd83490b]
次に、IPluginインターフェイスを実装したプラグインのクラスを作成します。ここでは、RichTextBox内の文字数を表示するプラグイン(CountCharsクラス)を作成してみましょう。
プラグインも前号と同様に、クラスライブラリとして作成し、"Plugin.dll"を参照に追加します。また、"System.Windows.Forms.dll"も参照に追加してください。出力するアセンブリファイル名は、"CountChars.dll"とします。(Visual Studio .NETのVB.NETの場合は、プロジェクトのプロパティの「ルート名前空間」が空白になっているものとします。デフォルトではプロジェクト名となっていますので、変更する必要があります。)
CountCharsクラスのコードは次のようになります。
#code(vbnet){{
Imports System
Namespace CountChars
''' <summary>
''' 文字数を表示するためのプラグイン
''' </summary>
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
''' <summary>
''' RichTextBoxの文字数を表示する
''' </summary>
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
}}
#code(csharp){{
using System;
namespace CountChars
{
/// <summary>
/// 文字数を表示するためのプラグイン
/// </summary>
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;
}
}
/// <summary>
/// RichTextBoxの文字数を表示する
/// </summary>
public void Run()
{
string msg =
string.Format("文字数 : {0} 文字",
this._host.RichTextBox.Text.Length);
this._host.ShowMessage(this, msg);
}
}
}
}}
特に説明を必要とする箇所はないでしょう。Runメソッドでは、IPluginHostオブジェクトからRichTextBoxにアクセスし、文字数を取得し、IPluginHostのShowMessageメソッドで結果をホストで表示しています。
***ウィンドウを表示するプラグインの作成 [#r6228f91]
次にWindowsアプリケーションらしく、ウィンドウを表示するプラグインを作成してみましょう。ここでは、「検索」ウィンドウにより、RichTextBoxから指定された文字列を検索するプラグインを作ります(エディタとしては、プラグインで処理する機能ではありませんが)。
まず、CountCharsクラスと同様、クラスライブラリのプロジェクトを作成し(名前は、"FindString"とします)、"Plugin.dll"と"System.Windows.Forms.dll"を参照に追加します("System.Windows.Forms.dll"は今追加しなくても、「Windowsフォームの追加」でプロジェクトにフォームを追加すれば、自動的に追加されます)。
続いて、「Windowsフォームの追加」でプロジェクトにフォーム(FindForm)を追加し、「検索」ウィンドウを作成します。このフォームに配置するコントロール及び、変更するプロパティ(あるいはイベント)の一覧は次のようになります。
#pre{{
コントロール: 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を検索できるようにします。
#code(vbnet){{
'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
}}
#code(csharp){{
//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();
}
}}
次にこのフォームを表示させるプラグインクラス(FindString)を作成します。コードは、次のようになります。
#code(vbnet){{
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
}}
#code(csharp){{
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();
}
}
}
}}
RunメソッドでFindFormを表示しているだけで、特に問題はないでしょう。(表示する前にRichTextBoxの設定と、オーナーウィンドウの設定を行っています。)
***メインアプリケーションの作成 [#v0d4f190]
ようやくここまでたどり着きました。いよいよプラグインを使用するホストのアプリケーションを作成します。
ホストアプリケーションは、Windowsアプリケーションプロジェクトとして作成し(名前は、"MainApplication"とします)、"Plugin.dll"を参照に追加します。
フォームには、RichTextBoxと、メニュー、さらにメッセージを表示するためのStatusBarコントロールを配置します。変更するフォームのプロパティと、フォームに配置するコントロールとそのプロパティ(そしてイベント)の一覧を以下に示します。
#pre{{
コントロール: 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クラスは次のようなコードです。
#code(vbnet){{
Imports System
''' <summary>
''' プラグインに関する情報
''' </summary>
Public Class PluginInfo
Private _location As String
Private _className As String
''' <summary>
''' PluginInfoクラスのコンストラクタ
''' </summary>
''' <param name="path">アセンブリファイルのパス</param>
''' <param name="cls">クラスの名前</param>
Private Sub New(ByVal path As String, ByVal cls As String)
Me._location = path
Me._className = cls
End Sub
''' <summary>
''' アセンブリファイルのパス
''' </summary>
Public ReadOnly Property Location() As String
Get
Return _location
End Get
End Property
''' <summary>
''' クラスの名前
''' </summary>
Public ReadOnly Property ClassName() As String
Get
Return _className
End Get
End Property
''' <summary>
''' 有効なプラグインを探す
''' </summary>
''' <returns>有効なプラグインのPluginInfo配列</returns>
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
''' <summary>
''' プラグインクラスのインスタンスを作成する
''' </summary>
''' <returns>プラグインクラスのインスタンス</returns>
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
}}
#code(csharp){{
using System;
namespace MainApplication
{
/// <summary>
/// プラグインに関する情報
/// </summary>
public class PluginInfo
{
private string _location;
private string _className;
/// <summary>
/// PluginInfoクラスのコンストラクタ
/// </summary>
/// <param name="path">アセンブリファイルのパス</param>
/// <param name="cls">クラスの名前</param>
private PluginInfo(string path, string cls)
{
this._location = path;
this._className = cls;
}
/// <summary>
/// アセンブリファイルのパス
/// </summary>
public string Location
{
get {return _location;}
}
/// <summary>
/// クラスの名前
/// </summary>
public string ClassName
{
get {return _className;}
}
/// <summary>
/// 有効なプラグインを探す
/// </summary>
/// <returns>有効なプラグインのPluginInfo配列</returns>
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));
}
/// <summary>
/// プラグインクラスのインスタンスを作成する
/// </summary>
/// <returns>プラグインクラスのインスタンス</returns>
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;
}
}
}
}
}}
IPluginHostインターフェイスは、フォームクラスで実装します。また、プラグインの読み込みと、メニューへの表示はフォームのLoadイベントハンドラで行い、メニューを選択することにより、プラグインを実行できるようにします。
以下に変更を加えたフォームクラスの主要部分のコード(Windowsフォームデザイナが作成したコードを除く)を示します。
#code(vbnet){{
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
}}
#code(csharp){{
namespace MainApplication
{
/// <summary>
/// Form1 の概要の説明です。
/// </summary>
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);
}
}
}
}}
このメインアプリケーションを実行させるには、実行ファイルのあるフォルダに"plugins"というフォルダを作り、そこに前に作成したプラグイン"CountChars.dll"と"FindString.dll"をコピーしてください。うまくいくと、「プラグイン」メニューに「文字数取得」と「文字列の検索」が追加され、プラグインの機能を呼び出すことができるようになります。
以上でプラグイン機能を実現させる方法に関する解説はおしまいです。ここで紹介した知識を応用することにより、より複雑なプラグインも作成できるでしょう。この記事を読んで、プラグインを使ったアプリケーションを作ってみようと思われる方が一人でもいらっしゃるならばうれしいのですが。
**コメント [#x62023d5]
#comment
//これより下は編集しないでください
#pageinfo([[:Category/.NET]],2004-08-31 (火) 06:00:00,DOBON!,2010-03-21 (日) 02:40:46,DOBON!)