このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
プラグインとなるアセンブリはできたが、
それをホストが見つけて読み込むためには、
プラグインの登録方法をルール化しなければならない。
今回は、ホストのあるフォルダに「plugins」サブフォルダを作成し、
その中にアセンブリを放り込むというルールにしよう。
早速、HelloSaver.dll と HelloSaver2.dll を放り込む。
+ scrhost.scr
+ plugins\
+ HelloSaver.dll
+ HelloSaver2.dll
ホストは plugins ディレクトリを調べてアセンブリを読み込めば良いのだ。
では、これらプラグインを読み込む Manager クラスを作る。
少し飽きてきたので、Manager はマネージクラスとし、
列挙可能な IEnumerable<Type ^> を実装させてみよう。
C++/CLI で複雑なクラスを実装するテストになる。
========== Manager.hpp ==========
#ifndef z_loafer_screensaver_host_manager
#define z_loafer_screensaver_host_manager
#include <windows.h>
#using <System.dll>
namespace Loafer {
namespace ScreenSaver {
namespace Host {
private ref class Manager
: public System::Collections::Generic::IEnumerable<System::Type ^> {
public:
Manager(); // 実体は cpp へ
virtual System::Collections::Generic::IEnumerator<System::Type ^> ^GetEnumerator() {
return types.GetEnumerator();
}
virtual property int Count {
int get() {
return types.Count;
}
}
virtual property System::Type ^ default[int] {
System::Type ^get(int index) {
return types[index];
}
}
virtual System::Collections::IEnumerator ^IEnumerable_GetEnumerator()
= System::Collections::IEnumerable::GetEnumerator
{
return GetEnumerator();
}
private:
System::Collections::Generic::List<System::Type ^> types;
};
}}} // Loafer::ScreenSaver::Host
#endif // !z_loafer_screensaver_host_manager
========== end of Manager.hpp ==========
色々と要素を盛り込んでみた。
フィールドとして、List<System::Type ^>型のメンバ types を持たせ、
ISaver を実装するクラス型は全てそこに放り込む計画だ。
プラグインのロードはコンストラクタで行うが、
コードが長くなるので、cpp に記述することにする。
Manager で IEnumerable<Type ^> を実装するためには、
IEnumerator<Type ^> を返す GetEnumerator メソッドが必要だ。
実際の列挙子は、types フィールドの物を利用するので、
GetEnumerator は単に types の GetEnumerator を呼ぶだけで良い。
問題となるのは IEnumerable<Type ^>が、
非ジェネリック IEnumerable を継承していることだ。
非ジェネリック IEnumerable も GetEnumerator メソッドを持つが、
これは IEnumerable<Type ^>の GetEnumerator と名前が重複する。
名前が重複する場合は、異なる名前でメソッドを提供し、
それに対して、対応するインタフェースメソッドの名前を明示する必要がある。
C++/CLI では、インタフェースメソッドの明示実装のために、
純粋仮想関数の構文を拡張して利用している。
C# では、メソッド名は不要だが、C++/CLI では必要なので、
IEnumerable_GetEnumerator 等の適当な名前でメソッドを作る。
virtual System::Collections::IEnumerator ^IEnumerable_GetEnumerator()
= System::Collections::IEnumerable::GetEnumerator
{
...
}
そして、もう一つ、インデクサも実装してみた。
インデクサがあれば、配列のように扱うことができるので便利なのだ。
インデクサは追加引数を取ることができるプロパティであり、
通常のプロパティ構文(ブロック)に各括弧で追加引数の型を示す。
通常は既定(無名)のインデクサを作成することで、
オブジェクト自身を配列のように扱うことができるようになる。
C++/CLI では、default という特別なキーワードを使うことで、
既定のインデクサを示すことができる。
これは、C# では this に相当する。
virtual property System::Type ^ default[int] {
System::Type ^get(int index) {
return types[index];
}
}
これで、Manager クラスは読み取り専用配列っぽくなった。