プラグインとなるアセンブリはできたが、
それをホストが見つけて読み込むためには、
プラグインの登録方法をルール化しなければならない。

今回は、ホストのあるフォルダに「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 クラスは読み取り専用配列っぽくなった。