連載 .NETでWindowsアプリを作ろう

第4回 Amazon用プラグインでAmazon Webサービスでも画像検索

デジタルアドバンテージ 遠藤 孝信
2006/01/14
Page1 Page2 Page3

アプリケーション本体の改造

 次に、アプリケーション本体を改造して、プラグインのロードと選択を行えるようにしましょう。以降では前回で作成したソース・ファイル(WebImageSearchフォルダに含まれるForm1.cs/Form1.vb)を修正していきます。

 まずは、フォーム上のテキストボックスと2つのボタンを右にずらして、プラグインを選択するためのコンボボックス(ComboBoxコントロール)を追加します。ここではコンボボックスの名前を「comboBoxPlugin」とします。

コンボボックスを追加したフォーム

 後はすべてコードの修正です。最初にGoogle用プラグインのインスタンス化を行っていたフィールドを削除して、ロードしたプラグイン用の配列と、検索に使用するプラグインのためのフィールドを記述します。

//IWebImage google = new GoogleImage();
IWebImage[] plugins; // プラグイン配列
IWebImage plugin = null; // 使用するプラグイン
'Dim google As IWebImage = New GoogleImage
Dim plugins As IWebImage() ' プラグイン配列
Dim plugin As IWebImage = Nothing
プラグインのインスタンスを保持するためのフィールドの追加(上:C#、下:VB.NET)

 変数pluginは、現在コンボボックスで選択されているプラグインのインスタンスを入れるためのものです。

■コンボボックスでのプラグインの一覧

 アプリケーションの起動時には、EXEファイルと同じディレクトリに配置されている各プラグインをロードしてインスタンス化し、それをいま宣言した配列pluginsに保存します。もしロードすべきプラグインがなければ、アプリケーションはメッセージを表示して終了します。

// プラグイン・オブジェクトを取得して追加
plugins = GetPlugins();
if (plugins.Length == 0)
{
  MessageBox.Show("プラグインがありません。", appName);
  Application.Exit();
}
comboBoxPlugin.DataSource = plugins;
comboBoxPlugin.DisplayMember = "Name";
' プラグイン・オブジェクトを取得して追加
plugins = GetPlugins()
If plugins.Length = 0 Then
  MessageBox.Show("プラグインがありません。", appName)
  Application.Exit()
End If
comboBoxPlugin.DataSource = plugins
comboBoxPlugin.DisplayMember = "Name"
Form1_Loadメソッドに追加するコード(上:C#、下:VB.NET)

 GetPluginsメソッドは各プラグインをロードしてインスタンス化し、その配列を返すためのものです(後述)。

 コンボボックスへの追加は、配列pluginsをDataSourceプロパティに設定し、DisplayMemberプロパティに「Name」を設定すればOKです。すべてのプラグインは、その名称を返すNameプロパティを実装しているはずです。

 そして[検索開始]ボタンがクリックされたときには、検索を開始する前に、現在コンボボックスで選択されているプラグインを変数pluginに設定します。

//google.Reset();
// 使用するプラグインの設定
plugin = plugins[comboBoxPlugin.SelectedIndex];
plugin.Reset();
'google.Reset()
' 使用するプラグインの設定
plugin = plugins(comboBoxPlugin.SelectedIndex)
plugin.Reset()
buttonStart_Clickメソッドでの修正(上:C#、下:VB.NET)

 残りのコードについては、これと同様に、変数googleだったところ(全部で3カ所)を、すべて「plugin」に変更します。

●addingメソッド内:

  • google.GetImages(keyword) → plugin.GetImages(keyword)
  • google.MoveNext() → plugin.MoveNext()

●addToThumbViewerメソッド内:

  • google.CurrentPage → plugin.CurrentPage

■プラグインのロードとインスタンス化

 最後に、プラグインのロードとインスタンス化を行うGetPluginsメソッドを記述すればアプリケーションは完成です。

 プラグインのロードとインスタンス化は、以下の手順をコーディングすることにより可能となります。

EXEファイルと同じディレクトリにあるDLLファイルを列挙する。
それぞれのDLLファイルをロードする。
ロードしたDLLファイルに含まれるクラスを列挙する。
それぞれのクラスが実装しているインターフェイスを列挙する。
インターフェイスがIWebImageインターフェイスであれば、そのクラスをインスタンス化する。

 については、Directoryクラス(System.IO名前空間)のGetFilesメソッドを使用します(参考:「.NET TIPS:ファイルやディレクトリの一覧を取得するには?」)。

 については、.NET Frameworkのリフレクションと呼ばれる機能を利用して実現できます。この機能を使えば、VS.NETのオブジェクト・ブラウザ(これは[表示]メニューの[オブジェクト ブラウザ]で起動できる)が表示するような情報をプログラム・コードにより取得できます。

 またリフレクション機能を使えば、特定のクラスをインスタンス化したり、オブジェクトのメソッドを動的に実行したりできます。これについては「.NET TIPS: 文字列で指定したクラスのインスタンスを作成するには?」を参考にしてください。

 さて、上記の手順をコーディングしたGetPluginsメソッドの実装は次のようになります。

IWebImage[] GetPlugins()
{
  ArrayList pluginArray = new ArrayList();

  foreach (string dll in Directory.GetFiles(".", "*.dll")) //
  {
    Assembly asm = Assembly.LoadFrom(dll); //
    foreach (Type t in asm.GetTypes())  //
    {
      if (!t.IsAbstract)
      {
        foreach (Type i in t.GetInterfaces()) //
        {
          if (i == typeof(IWebImage)) //
          {
            pluginArray.Add(Activator.CreateInstance(t));
          }
        }
      }
    }
  }
  return (IWebImage[])pluginArray.ToArray(typeof(IWebImage));
}
Function GetPlugins() As IWebImage()

  Dim pluginArray As New ArrayList

  For Each dll As String In Directory.GetFiles(".", "*.dll") '

    Dim asm As [Assembly] = [Assembly].LoadFrom(dll) '
    For Each t As Type In asm.GetTypes() '

      If Not t.IsAbstract Then

        For Each i As Type In t.GetInterfaces '

          If i Is GetType(IWebImage) Then '

            pluginArray.Add(Activator.CreateInstance(t))
          End If
        Next
      End If
    Next
  Next
  Return CType(pluginArray.ToArray(GetType(IWebImage)), IWebImage())
End Function
プラグインのロードとインスタンス化を行うGetPluginsメソッド(上:C#、下:VB.NET)

 ここでは詳細な解説は割愛しますが、リフレクションの世界では、ロードしたDLLファイルはAssemblyオブジェクト(System.Reflection名前空間)として、またAssemblyオブジェクトに含まれているクラスやインターフェイスはTypeオブジェクト(System名前空間)として扱われることに注意してください。

 なお、Amazon用プラグインの基本クラスであるAmazonBaseクラスはIWebImageインターフェイスを実装していますが、抽象クラスとして定義していますのでインスタンス化はできません(例外が発生します)。そのようなクラスをスキップするために、ループ内ではTypeオブジェクトのIsAbstractプロパティをチェックしています*

* 上記コード内ののブロック内をtry 〜 catchステートメントにより囲み、CreateInstanceメソッドでのインスタンス化の失敗による例外発生をすべて無視してしまうという荒技も可能です。

■ボタンをWindows XPスタイルに!

 以上でアプリケーションは完成ですが、前回でボタンなどのGUI部品をWindows XPスタイルに設定するのを忘れていました。単なる見た目だけの問題ですが、人に使ってもらうにはこれは重要なポイントです。

 アプリケーションをXPスタイルにするには、VS.NETでフォームの2つのボタンのFlatStyleプロパティを「System」に設定し、フォームが作成される前に、Application.EnableVisualStylesメソッドを呼び出します。これについての詳細は「.NET TIPS:WindowsアプリケーションをWindows XPスタイルの外観にするには?」を参考にしてください。

 Application.EnableVisualStylesメソッドの呼び出しは、C#ではMainメソッド内で記述できます。VB.NETではMainメソッドがデフォルトでは作成されませんので、フォームのコンストラクタに記述します。

static void Main()
{
  Application.EnableVisualStyles();
  Application.Run(new Form1());
}
Public Sub New()
  MyBase.New()

  ' この呼び出しは Windows フォーム デザイナで必要です。
  InitializeComponent()

  ' InitializeComponent() 呼び出しの後に初期化を追加します。

  Application.EnableVisualStyles()
End Sub
Application.EnableVisualStylesメソッド呼び出しの追加(上:C#、下:VB.NET)

■アプリケーションの実行

 ではソリューションをビルドして、WISAmazonディレクトリ配下に作成されるWISAmazon.dllと、WISGoogleディレクトリ配下に作成されるWISGoogle.dllを、WebImageSearch.exeと同じディレクトリ(デバッグ時には「WebImageSearch\bin\Debug」/「WebImageSearch\bin」)にコピーしてください。

 第1回目でも触れているように、このときファイル名を「1WISGoogle.dll」「2WISAmazon.dll」などに変更することにより、コンボボックスに表示される順番を制御することができます。これはDirectory.GetFilesメソッドがファイルを列挙するときにソートしてくれるためです*

* これはドキュメントには明記されていませんが、少なくともファイル・システムがNTFSの場合にはソートされるようです。

 アプリケーションを実行すれば、いま作成したプラグインがコンボボックスに列挙されるはずです。以下の画面は「Amazon DVD」で「グウィネス」を検索しているところです。

完成したWebImageSearchの実行画面
コンボボックスにはプラグインによる選択可能なサイトの一覧が表示される。

 以上で4回にわたって解説してきたWeb画像検索ツール「WebImageSearch」の作成は完了です。もし興味があれば、ぜひともほかのサイトに対応したプラグインの作成にチャレンジしてみてください。そしてどこかで公開していただければ幸いです。それではまたお会いしましょう。End of Article

 

 INDEX
  .NETでWindowsアプリを作ろう
  第4回 Amazon用プラグインでAmazon Webサービスでも画像検索
    1.Amazon用プラグインの作成(1)
    2.Amazon用プラグインの作成(2)
  3.アプリケーション本体の改造
 
インデックス・ページヘ  「.NETでWindowsアプリを作ろう 」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間