プラグインのロードはManager クラスのコンストラクタで行う。

手順としては、plugin フォルダの内部からアセンブリを探し、順にロードする。
そして、ロードしたアセンブリの中から、ISaver 実装型を検索するという流れだ。

では、コンストラクタを作る。

========== Manager.cpp ==========

#include "config.hpp"
#include "Manager.hpp"

#using "Loafer.ScreenSaver.dll"

using namespace System;
using namespace System::IO;
using namespace System::Reflection;
using namespace Loafer::ScreenSaver;

namespace Loafer {
namespace ScreenSaver {
namespace Host {

Manager::Manager() {
   
    // プラグインフォルダを探索し
    // プラグインを含むアセンブリを得る

    String ^hostDir = Path::GetDirectoryName(Assembly::GetExecutingAssembly()->Location);
    String ^pluginDir = Path::Combine(hostDir, "plugins");
    array ^paths = Directory::GetFiles(pluginDir, "*.dll");

    // アセンブリを読み込み、ISaver 実装型を得る

    // ISaver の Type を用意
    Type ^interfaceType = ISaver::typeid;

    for each (String ^path in paths) {

        // アセンブリを AppDomain にロード
        Assembly ^plugin = Assembly::LoadFrom(path);

        // 型を列挙
        for each (Type ^type in plugin->GetTypes()) {

            // public でかつ抽象ではなく、
            // ISaver を実装し、デフォルトコンストラクタを持つ
            if (type->IsPublic && !type->IsAbstract
                    && interfaceType->IsAssignableFrom(type)
                    && type->GetConstructor(Type::EmptyTypes) != nullptr) {

                types.Add(type);

            }

        }

    }

}

========== end of Manager.cpp ==========

「plugins」フォルダは、ホストのあるフォルダを基準とするため、
まず Assembly::GetExecutingAssembly() で、
自分自身(=ホスト)のアセンブリを取得し、
Location プロパティを参照して自分のパスを得る。

次いで、Path::GetDirectoryName() でフォルダ名を取りだし、
"plugins" を連結してサブディレクトリを得る。
そして、Directory::GetFiles() でアセンブリの配列を得る。

後は、プラグインの動的ロードの日記で書いたコードと同じ。
個々のアセンブリを読み込み、型を列挙するだけだ。

これで、ISaver を実装したクラスの Type 一覧が取得できるようになる。