┏第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.
===============================