• 検索結果がありません。

プラグイン

N/A
N/A
Protected

Academic year: 2021

シェア "プラグイン"

Copied!
26
0
0

読み込み中.... (全文を見る)

全文

(1)

■ プラグイン詳細・1 ■

Adobe Photoshop や Becky! Internet Mail 等のアプリケーションでは、プラグイン(又は、アドイン、 エクステンション等)と呼ばれるプログラムをインストールする事に依り、機能を追加する事が出来る 様に成って居る。此処では、此の様なプラグイン機能を持ったアプリケーションの作り方を考えて観る 事にする。 其れは、インターフェイスを使用すると謂う方法で有る。詰り、プラグインと仕て必要と成る機能をプ ロパティやメソッド(更に、イベントやインデクサ)と仕て持つインターフェイスを予め用意して置き、 此のインターフェイスを実装したクラスと仕てプラグインを作成するので有る。 ■ インターフェイスの作成 理屈は扨て置き、実際にプラグインを作成して観る事にする。 此処で作成するプラグインは、プラグインの名前を返す機能と、渡された文字列を処理して、結果を文 字列と仕て返す機能を有する物とし、夫々の機能の為にName プロパティと Run メソッドを持つイン ターフェイスを作る。 Visual Studio では、クラスライブラリのプロジェクトを作成し、下記の様なコードを書き、ビルドす る。.NET SDK の場合は、/target:library コンパイラオプションに依り、コードライブラリを作成する。 猶、此処で作成されたアセンブリファイル名は、Plugin.dll で有るとする。

※ Visual Studio の Visual Basic の場合は、プロジェクトのプロパティの「ルート名前空間」が空白に 成って居る物とする(デフォルトでは、プロジェクト名と成って居るので、プロジェクトのプロパ

ティでルート名前空間の欄を消去する)。

Visual Basic Imports System

Namespace Plugin

Public Interface IPlugin

ReadOnly Property Name( ) As String

Function Run( ByVal Str As String ) As String End Interface End Namespace C# using System; namespace Plugin {

public interface IPlugin {

string Name { get; } string Run( string str ); }

}

(2)

■ プラグインの作成

次に、此のインターフェイスを基に、プラグインを作る。プラグインもクラスライブラリと仕て作成す

る。プラグインは今作成したIPlugin インターフェイスを実装する必要が有るので、Plugin.dll を参照

に追加する。具体的には、Visual Studio の場合は、ソリューションエクスプローラの「参照設定」に Plugin.dll を追加する。.NET SDK の場合は、/reference コンパイラオプションを使用する。

此処では、渡された文字列の文字数を返すプラグインを作成する事にする。IPlugin インターフェイス

を実装した下記の様な CountChars クラスを作成する。此のクラスライブラリは、CountChars.dll と

謂う名前のアセンブリファイルと仕てビルドする物とする。 Visual Basic Public Class CountChars

Implements Plugin.IPlugin

' プラグインの名前を返すプロパティ

Public ReadOnly Property Name( ) As String _ Implements Plugin.IPlugin.Name Get Return "文字数取得" End Get End Property ' 文字数を文字列で返すメソッド

Public Function Run( ByVal Str As String ) As String _ Implements Plugin.IPlugin.Run Return Str.Length.ToString( ) End Function End Class C# using System; namespace CountChars {

public class CountChars : Plugin.IPlugin {

public string Name { get { return "文字数取得"; } }

public string Run( string str ) {

return str.Length.ToString( ); }

} }

(3)

■ プラグインを使うアプリケーションの作成 残るはプラグインを使用するメインアプリケーションの作成で有る。メインアプリケーションでは、イ ンストールされて居る有効なプラグインを何の様に探すか、然して、プラグインクラスのインスタンス を何の様に作成するかと謂う事が問題と成る。 先ず、インストールされて居るプラグインを探す方法に付いてで有る。プラグインは、必ず dll と謂う 拡張子を持ち、指定されたフォルダに置かれて居なければ成らないと謂う約束に仕て置く(此処では、 メインアプリケーションがインストールされて居るフォルダに有るplugins フォルダにプラグインを置 く物とする)。此れに依り、メインアプリケーションは、プラグインフォルダに有るdll の拡張子を持つ ファイル而巳を調べれば良い事に成る。更に、アセンブリにIPlugin インターフェイスを実装したクラ スが有るか調べるには、リフレクションを使用する。 亦、プラグインクラスのインスタンスを作成するには、Activator.CreateInstance メソッド等を使用す れば良い(下記のサンプルでは、Assembly.CreateInstance メソッドを使用して居る)。 其れでは、実際に作成して観る事にする。此処では、メインアプリは、コンソールアプリケーションと 仕て作成する事にする。亦、Plugin.dll を参照に追加する。 先ずは、プラグインを扱うクラス(PluginInfo)を作成する。此のクラスは、プラグインのアセンブリ ファイルのパスとクラス名を返すプロパティ(夫々Location と ClassName)と、有効なプラグインを 探すメソッド(FindPlugins)、IPlugin のインスタンスを作成するメソッド(CreateInstance)を有す る。此のクラスのコードを以下に示す。 Visual Basic Public Class PluginInfo

Private LocationValue As String Private ClassNameValue As String

' PluginInfo クラスのコンストラクタ

Private Sub New( ByVal path As String, ByVal cls As String ) Me.LocationValue = path

Me.ClassNameValue = cls End Sub

' アセンブリファイルのパス

Public ReadOnly Property Location( ) As String Get Return LocationValue End Get End Property ' クラスの名前

Public ReadOnly Property ClassName( ) As String Get Return ClassNameValue End Get End Property ' 有効なプラグインの探索するメソッド

Public Shared Function FindPlugins( ) As PluginInfo( ) Dim Plugins As New System.Collections.ArrayList

(4)

' IPlugin 型の名前

Dim PluginName As String = GetType( Plugin.IPlugin ).FullName

' プラグインフォルダ

Dim Folder As String = _

System.IO.Path.GetDirectoryName( _ System.Reflection.Assembly. _

GetExecutingAssembly( ).Location )

If Not Folder.EndsWith( "¥" ) Then Folder &= "¥" 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 AndAlso T.IsPublic AndAlso _

Not T.IsAbstract AndAlso _

Not ( T.GetInterface( PluginName ) Is Nothing ) Then ' PluginInfo をコレクションに追加

Plugins.Add( New PluginInfo( Dll, T.FullName )) End If Next Catch End Try Next ' コレクションを配列に仕て復帰

Return CType( Plugins.ToArray( GetType( PluginInfo )), PluginInfo( )) End Function

' プラグインクラスのインスタンスを作成するメソッド Public Function CreateInstance( ) As Plugin.IPlugin Try

' アセンブリの読込

Dim Asm As System.Reflection.Assembly = _ System.Reflection.Assembly.LoadFrom( Me.Location ) ' クラス名からインスタンスを作成

Return CType( Asm.CreateInstance( Me.ClassName ), Plugin.IPlugin ) Catch

End Try

Return Nothing End Function End Class

(5)

C# using System;

namespace Plugin {

// プラグインに関する情報 public class PluginInfo {

private string _location; private string _className;

// PluginInfo クラスのコンストラクタ

// 引数は、path:アセンブリファイルのパス、cls:クラスの名前 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 { // アセンブリと仕て読み込む

(6)

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( )

{ try { // アセンブリを読み込む System.Reflection.Assembly asm = System.Reflection.Assembly.LoadFrom( this.Location ); // クラス名からインスタンスを作成する return ( Plugin.IPlugin ) asm.CreateInstance( this.ClassName ); } catch { return null; } } } } FindPlugins メ ソ ッ ド が 多 少 複 雑 な の で 、 簡 単 に 説 明 し て 置 く 。 FindPlugins メ ソ ッ ド で は Assembly.LoadFrom メソッドでアセンブリを読み込んだ後、アセンブリ内の総ての型に付いて、其の 型がクラスで有り、パブリックで有り、抽象クラスで無い事を確認し、更に、Type.GetInterface メソ ッドに依り、IPlugin インターフェイスを実装して居る事を確認する。此等総ての条件に当て嵌る場合 に有効なプラグインと判断する(拠って、此の例では、1 つのアセンブリファイルに複数のプラグイン クラスを定義する事が出来る)。 此処迄来れば、後は簡単で有る。PluginInfo クラスを使ったメインのクラス(エントリポイント)のサ ンプルは、下記の様に成る。猶、下記は、コンソールアプリケーションと仕て作成し、実行ファイルの 在るフォルダ(編集時には、bin/Debug フォルダ)直下に plugins と謂う名前のフォルダが在り、其の 中にプラグインファイル(前述の CountChars.dll 等)が在る物とする。亦、前述の Plugin.dll と PluginInfo.dll の参照が追加されて居る物とする。

(7)

Visual Basic Imports System

Module PluginHost

< STAThread( )> _ Public Sub Main( )

Dim Pis( ) As PluginInfo.PluginInfo = PluginInfo.PluginInfo.FindPlugins( )

' 総てのプラグインクラスのインスタンスを作成する Dim Plugins( Pis.Length - 1 ) As Plugin.IPlugin For I As Integer = 0 To ( Plugins.Length - 1 ) Plugins( I ) = Pis( I ).CreateInstance( )

Next

' 有効なプラグインを表示し、使用するプラグインを選ばせる Dim Number As Integer = -1

Do

For I As Integer = 0 To ( Plugins.Length - 1 ) Console.WriteLine( "{0}:{1}", I, Plugins( I ).Name ) Next

Console.WriteLine( "使用するプラグインの番号を入力して下さい。:" ) Try

Number = Integer.Parse( Console.ReadLine( )) Catch

End Try

Loop While Number < 0 OrElse Number >= Pis.Length Console.WriteLine( Plugins( Number ).Name + " を使用する。" )

' プラグインに渡す文字列の入力を促す

Console.WriteLine( "文字列を入力して下さい。:" ) Dim S As String = Console.ReadLine( )

' プラグインの Run メソッドを呼び出して結果を取得する Dim R As String = Plugins( Number ).Run( S ) ' 結果の表示 Console.WriteLine( "結果:" ) Console.WriteLine( R ) Console.ReadLine( ) End Sub End Module C# using System; namespace MainApplication {

public class PluginHost {

[ STAThread ]

static void Main( string[ ] args ) {

(8)

// インストールされて居るプラグインを調べる

PluginInfo[ ] pis = Plugin.PluginInfo.FindPlugins( );

// 総てのプラグインクラスのインスタンスを作成する

Plugin.IPlugin[ ] plugins = new Plugin.IPlugin[ pis.Length ]; for ( int i = 0; i < plugins.Length; i++ )

plugins[ i ] = pis[ i ].CreateInstance( );

// 有効なプラグインを表示し、使用するプラグインを選ばせる int number = -1;

do {

for ( int i = 0; i < plugins.Length; i++ )

Console.WriteLine( "{0}:{1}", i, plugins[ i ].Name );

Console.WriteLine( "使用するプラグインの番号を入力して下さい。:" ); try

{

number = int.Parse( Console.ReadLine( )); }

catch {

Console.WriteLine( "数字を入力して下さい。" ); }

} while ( number < 0 || number >= pis.Length );

Console.WriteLine( plugins[ number ].Name + " を使用する。" ); // プラグインに渡す文字列の入力を促す Console.WriteLine( "文字列を入力して下さい。:" ); string str = Console.ReadLine( ); // プラグインの Run メソッドを呼び出して結果を取得する string result = plugins[ number ].Run( str );

// 結果の表示 Console.WriteLine( "結果:" ); Console.WriteLine( result ); Console.ReadLine( ); } } } 前述の通り、メインアプリ実行前に実行ファイルの有るフォルダにplugins と謂うフォルダを作り、其 処に先程作成したCountChars.dll をコピーして置く。此れで、CountChars.dll をプラグインと仕て認 識出来る。色々なプラグインを作成し、plugins フォルダに格納して、プラグインを選択する事が出来 る様に仕て、動作確認して欲しい。 基本的なプラグイン機能の実現方法は以上で有る。併し、より高度なプラグイン機能が必要な場合には、 此れ丈では不十分かも知れない。例えば、プラグインからメインアプリにフィードバックし度い等、プ ラグインからメインアプリケーションの機能(メソッド)を呼び出し度いケースも有る。其の様な場合 には、プラグインを使う側で実装するインターフェイスを定義すると謂う方法が有る。続いては、 Windows アプリケーションのサンプルと仕て、此の方法を紹介する。

(9)

■ Windows アプリケーションでプラグイン機能を実現する

此処からは更に実用的な例と仕て、Windows アプリケーションでプラグイン機能を実現する方法を紹 介する。此処では、具体的に、プラグインの使用出来る簡単なエディタを作成する事にする。

飽く迄、プラグイン機能を説明する事が目的なので、エディタは思い切り単純にし、フォームに RichTextBox と MainMenu 而巳を配置する事にする。プラグインからエディタの RichTextBox コント ロールにアクセスする事に依り、プラグインの機能が果たせる様にする。 ■ インターフェイスを定義する 前回と同じ様に、先ずプラグインのクラスが実装す可きインターフェイスを定義する。今回はプラグイ ンのインターフェイスに加えて、プラグインを使用するホストの側が実装す可きインターフェイスも定 義する事にする。ホストの為のインターフェイスでは、プラグインのホストと仕て必要な機能をメンバ と仕て定義し、プラグインから此のメンバを通してホストにアクセス出来る様にする。 具体的には、プラグインから指定されたメッセージをホストで表示する為のメソッドと、ホストの RichTextBox コントロールを取得する為のプロパティ、更にホストのメインフォームを取得する為のプ ロパティを定義する事にする。 其れでは、実際に此等のインターフェイスを作成する事にする。前回と同様、クラスライブラリと仕て 作成する為、Visual Studio ではクラスライブラリのプロジェクトを作成し(Plugin と謂う名前で作成

して居る)、.NET SDK では/target:library コンパイラオプションを使用する。亦、アセンブリファイ

ル 名 は 、 Plugin.dll と す る 。 更 に 今 回 は Windows ア プ リ ケ ー シ ョ ン を 扱 う 為 、 System.Windows.Forms.dll を参照に追加する(参照に追加するには、Visual Studio .NET の場合は、 ソリューションエクスプローラの「参照設定」を、.NET SDK の場合は、/reference コンパイラオプシ ョンを使用する)。 コードは、下記の様に成る。IPlugin インターフェイスがプラグインの為のインターフェイスで、 IPluginHost インターフェイスがプラグインのホストの為のインターフェイスで有る。 Visual Basic 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( )

(10)

' プラグインのホストで実装するインターフェイス Public Interface IPluginHost

' ホストのメインフォーム

ReadOnly Property MainForm( ) As Form

' ホストの RichTextBox コントロール

ReadOnly Property RichTextBox( ) As RichTextBox

' ホストでメッセージを表示する

' 引数は、Plugin:メソッドを呼び出すプラグイン、Msg:表示するメッセージ Sub ShowMessage( ByVal Plugin As IPlugin, ByVal Msg As String ) End Interface End Namespace 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; }

// ホストでメッセージを表示する

// 引数は、plugin:メソッドを呼び出すプラグイン、msg:表示するメッセージ void ShowMessage( IPlugin plugin, string msg );

} }

(11)

IPlugin は、前回と比べ、プラグインのバージョンと説明を取得する為のプロパティが新たに追加され、 更に、Run メソッドもパラメータ、戻り値が無く成った。亦、IPluginHost を設定、取得する為のプロ パティも加えられて居る。 ■ プラグインを作成する 次に、IPlugin インターフェイスを実装したプラグインのクラスを作成する。此処では、RichTextBox 内の文字数を表示するプラグイン(CountChars クラス)を作成して観る事にする。 プラグインも前回と同様に、クラスライブラリと仕て作成し、Plugin.dll を参照に追加する。亦、 System.Windows.Forms.dll も参照に追加する。出力するアセンブリファイル名は、CountChars.dll とする(Visual Studio .NET の Visual Basic の場合は、プロジェクトのプロパティの「ルート名前空 間」が空白に成って居る物とする。デフォルトではプロジェクト名と成って居るので、変更する必要が 有る)。

CountChars クラスのコードは下記の様に成る。

Visual Basic Imports System

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 ' IPlugin のプロパティメンバ(プラグインのバージョン)

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

' IPlugin のプロパティメンバ(プラグインの説明)

Public ReadOnly Property Description( ) As String Implements Plugin.IPlugin.Description Get Return "エディタで編集中の文章の文字数を表示する。" End Get End Property ' IPlugin のプロパティメンバ(プラグインのホスト)

Public Property Host( ) As Plugin.IPluginHost Implements Plugin.IPlugin.Host Get

(12)

Return Me._host End Get

Set( ByVal value As Plugin.IPluginHost ) Me._host = value

End Set End Property

' IPlugin のメソッドメンバ(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 C# using System; namespace CountChars { // 文字数を表示する為のプラグイン

public class CountChars : Plugin.IPlugin {

private Plugin.IPluginHost _host;

// IPlugin のプロパティメンバ(プラグインの名前) public string Name

{ get { return "文字数取得"; } } // IPlugin のプロパティメンバ(プラグインのバージョン) public string Version

{ get { // 自分自身の Assembly を取得し、バージョンを返す System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly( ); System.Version ver = asm.GetName( ).Version;

return ver.ToString( ); }

}

// IPlugin のプロパティメンバ(プラグインの説明) public string Description

{ get { return "エディタで編集中の文章の文字数を表示する。"; } } // IPlugin のプロパティメンバ(プラグインのホスト) public Plugin.IPluginHost Host

(13)

{ get { return this._host; } set { this._host = value; } } // IPlugin のメソッドメンバ(RichTextBox の文字数を表示する) public void Run( )

{ string msg = string.Format( "文字数 : {0} 文字", this._host.RichTextBox.Text.Length ); this._host.ShowMessage( this, msg ); } } }

特に説明を要さないと思う。Run メソッドでは、IPluginHost オブジェクトから RichTextBox にアク セスし、文字数を取得し、IPluginHost の ShowMessage メソッドで結果をホストで表示して居る。 ■ ウィンドウを表示するプラグインの作成 次にWindows アプリケーションらしく、ウィンドウを表示するプラグインを作成して観る事にする。 此処では、「検索」ウィンドウに依り、RichTextBox から指定された文字列を検索するプラグインを作 る(エディタと仕ては、プラグインで処理する機能では無いが)。 先ず、CountChars クラスと同様、クラスライブラリのプロジェクトを作成し(名前は、FindString と する)、Plugin.dll と System.Windows.Forms.dll を参照に追加する(System.Windows.Forms.dll は今

追加しなくても、「Windows フォームの追加」でプロジェクトにフォームを追加すれば、自動的に追加 される)。 続いて、「Windows フォームの追加」でプロジェクトにフォーム(FindForm)を追加し、「検索」ウィ ンドウを作成する。此のフォームに配置するコントロール、及び、変更するプロパティ(或いは、イベ ント)の一覧は下記の様に成る。 コントロールの種類 プロパティ プロパティの設定値 フォーム Name FindForm Text 検索 AcceptButton btnFind CancelButton btnClose FormBorderStyle FixedToolWindow ShowInTaskbar false テキストボックス Name txtFindString Text 空白 ボタン1 Name btnFind Text 次を検索 DialogResult OK Click イベント btnFind_Click

(14)

ボタン2 Name btnClose Text 閉じる DialogResult Cancel Click イベント btnClose_Click チェックボックス1 Name chkWholeWord Text 単語単位で検索する チェックボックス2 Name chkMatchCase Text 大文字小文字を区別する チェックボックス3 Name chkReverse Text 上へ検索する 更に、FindForm クラスに下記のコードを追加し、指定された RichTextBox を検索出来る様にする。 Visual Basic Imports System.Windows.Forms Public Class FindForm

' 検索するリッチテキストボックス Friend RTB As RichTextBox

' ボタン(次を検索)がクリックされた時の処理

Private Sub btnFind_Click( ByVal sender As System.Object, ByVal e As System.EventArgs ) _ Handles btnFind.Click

' 検索オプションの決定

Dim Finds As RichTextBoxFinds = RichTextBoxFinds.None If chkWholeWord.Checked Then

Finds = Finds Or RichTextBoxFinds.WholeWord End If

If chkMatchCase.Checked Then

Finds = Finds Or RichTextBoxFinds.MatchCase End If

If chkReverse.Checked Then

Finds = Finds Or RichTextBoxFinds.Reverse End If

' 検索範囲の決定

Dim StartPos, EndPos As Integer If Not chkReverse.Checked Then

StartPos = Me.RTB.SelectionStart + Me.RTB.SelectionLength EndPos = -1

If StartPos >= Me.RTB.TextLength Then

MessageBox.Show( "検索が完了しました。", "検索" ) Return End If Else StartPos = 0 EndPos = Me.RTB.SelectionStart If EndPos <= 0 Then MessageBox.Show( "検索が完了しました。", "検索" ) Return End If End If

(15)

' 検索

If Me.RTB.Find( txtFindString.Text, StartPos, EndPos, Finds ) < 0 Then MessageBox.Show( "検索が完了しました。", "検索" ) Else Me.RTB.Focus( ) End If End Sub ' ボタン(閉じる)がクリックされた時の処理

Private Sub btnClose_Click( ByVal sender As System.Object, ByVal e As System.EventArgs ) _ Handles btnClose.Click Me.Close( ) End Sub End Class C# // 下記は Class ブロック而巳を記述 // using System.Windows.Forms; がソースファイルの一番上に書かれて居る物とする // 検索するリッチテキストボックス

internal RichTextBox RichTextBox;

// ボタン(次を検索)がクリックされた時の処理

private void btnFind_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.rtb.SelectionStart + this.rtb.SelectionLength; endPos = -1; if ( startPos >= this.rtb.TextLength ) { MessageBox.Show( "検索が完了しました。", "検索" ); return; } } else { startPos = 0; endPos = this.rtb.SelectionStart; if ( endPos <= 0 ) { MessageBox.Show( "検索が完了しました。", "検索" ); return; } } // 検索

(16)

if ( this.rtb.Find( findString.Text, startPos, endPos, finds ) < 0 ) MessageBox.Show( "検索が完了しました。", "検索" ); else this.rtb.Focus( ); } // ボタン(閉じる)がクリックされた時の処理

private void btnClose_Click( object sender, System.EventArgs e ) { this.Close( ); } 次に、此のフォームを表示させるプラグインクラス(FindString)を作成する。コードは、下記の様に 成る。 Visual Basic Imports System Imports System.Windows.Forms Public Class FindString

Implements Plugin.IPlugin Private Hst As Plugin.IPluginHost Private Frm As FindForm ' IPlugin のプロパティメンバ(プラグインの名前)

Public ReadOnly Property Name( ) As String Implements Plugin.IPlugin.Name Get Return "文字列の検索" End Get End Property ' IPlugin のプロパティメンバ(プラグインのバージョン)

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

' IPlugin のプロパティメンバ(プラグインの説明)

Public ReadOnly Property Description( ) As String Implements Plugin.IPlugin.Description Get Return "編集中の文章から指定された文字列を検索する。" End Get End Property ' IPlugin のプロパティメンバ(プラグインのホスト)

Public Property Host( ) As Plugin.IPluginHost Implements Plugin.IPlugin.Host Get

(17)

End Get

Set( ByVal value As Plugin.IPluginHost ) Hst = value

End Set End Property

' IPlugin のメソッドメンバ(RichTextBox の文字数を表示する) Public Sub Run( ) Implements Plugin.IPlugin.Run ' フォームが表示されて居ればアクティブにして終了 If Not ( Me.Frm Is Nothing ) AndAlso _ Not Me.Frm.IsDisposed Then

Me.Frm.Activate( ) Return

End If

' 検索ウィンドウを作成して表示 Me.Frm = New FindForm

Me.Frm.RTB = Me.Hst.RichTextBox Me.Frm.Owner = Me.Hst.MainForm Me.Frm.Show( ) End Sub End Class 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 "文字列の検索"; } } // IPlugin のプロパティメンバ(プラグインのバージョン) public string Version

{ get { // 自分自身の Assembly を取得し、バージョンを返す System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly( ); System.Version ver = asm.GetName( ).Version;

return ver.ToString( ); }

}

(18)

public string Description { get { return "編集中の文章から指定された文字列を検索する。"; } } // IPlugin のプロパティメンバ(プラグインのホスト) public Plugin.IPluginHost Host

{ get { return _host; } set { _host = value; } } // IPlugin のメソッドメンバ(RichTextBox の文字数を表示する) 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 の設定と、オーナーウィンドウの設定を行って居る)。 ■ メインアプリケーションの作成 愈々、プラグインを使用するホストのアプリケーションを作成する事にする。 ホストアプリケーションは、Windows アプリケーションプロジェクトと仕て作成し(名前は、 MainApplication とする)、Plugin.dll を参照に追加する。 フォームには、RichTextBox と、メニュー、更に、メッセージを表示する為の StatusBar コントロール を配置する。変更するフォームのプロパティと、フォームに配置するコントロールと其のプロパティ(然 して、イベント)の一覧を下記に示す。 【此処から】

(19)

コントロールの種類 プロパティ プロパティの設定値 フォーム Name Form1 Menu mainMenu Load イベント Form1_Load リッチテキストボックス Name mainRichTextBox Dock Fill ステータスバー Name mainStatusbar メインメニュー Name mainMenu メニューアイテム1 Name menuPlugins Text プラグイン(&P) Click イベント menuPlugin_Click メニューアイテム2 Name menuHelp Text ヘルプ(&H) メニューアイテム3 Name menuAbout Text バージョン情報(&A)... Click イベント menuAbout_Click 次に前回で作成したPluginInfo クラスをプロジェクトに追加する。但し、CreateInstance メソッドで IPluginHost オブジェクトを IPluginHost.Host プロパティに設定する様に変更して居る。 PluginInfo クラスは下記の様なコードで有る。 Visual Basic Imports System ' プラグインに関する情報 Public Class PluginInfo

Private _location As String Private _className As String ' PluginInfo クラスのコンストラクタ

' 引数は、path:アセンブリファイルのパス、cls:クラスの名前 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

(20)

' 有効なプラグインを探す(戻り値は、有効なプラグインの 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

(21)

'アセンブリを読み込む

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 C# using System; namespace MainApplication { // プラグインに関する情報 public class PluginInfo {

private string _location; private string _className;

// PluginInfo クラスのコンストラクタ

// 引数は、path:アセンブリファイルのパス、cls:クラスの名前 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; //プラグインフォルダ

(22)

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 の設定

(23)

plugin.Host = host; return plugin; } catch { return null; } } } } IPluginHost インターフェイスは、フォームクラスで実装する。亦、プラグインの読込と、メニューへ の表示はフォームのLoad イベントハンドラで行い、メニューを選択する事に依り、プラグインを実行 出来る様にする。 下記に変更を加えたフォームクラスの主要部分のコード(Windows フォームデザイナが作成したコー ドを除く)を示す。 Visual Basic 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 'インストールされて居るプラグインを探す

(24)

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 C# namespace MainApplication {

public class Form1 : System.Windows.Forms.Form, Plugin.IPluginHost {

(25)

//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) {

(26)

{ //クリックされたプラグインを実行する 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 をコピーする。旨く行く と、「プラグイン」メニューに「文字数取得」と「文字列の検索」が追加され、プラグインの機能を呼 び出す事が出来る様に成る。 以上でプラグイン機能を実現させる方法に関する解説は終了で有る。此処で紹介した知識を応用する事 に依り、より複雑なプラグインも作成出来ると思う。

参照

関連したドキュメント

Program’s name number 1 02:30 203°F 300G. 300G

品名(Part name) 数量(Quantity).. 品名(Part name) 数量(Quantity).. 品名(Part name) 数量(Quantity).. 部品番号 (Part No.) 品名(Part name)

画像の参照時に ACDSee Pro によってファイルがカタログ化され、ファイル プロパティと メタデータが自動的に ACDSee

業種 事業場規模 機械設備・有害物質の種 類起因物 災害の種類事故の型 建設業のみ 工事の種類 災害の種類 被害者数 発生要因物 発生要因人

13.荷送人名称、住所、国名 及び電話番号 Consignor Name, Address, Country, Telephone Number 14.荷受人名称、住所、国名 及び電話番号 Consignee Name,

3.3 液状化試験結果の分類に対する基本的考え方 3.4 試験結果の分類.. 3.5 液状化パラメータの設定方針

産業廃棄物の種類 建設汚泥 廃プラスチック類 排    出  

産業廃棄物の種類 排    出   量. 産業廃棄物の種類 排