動的に追加、削除可能なDOC,VIEW DLL を作成するのはDOC,VIEWクラスのDLLを静的リンクするよりは労力を要します。
アプリケーションは新しい種類の Document クラスを使用可能にするために、まずCDocTemplate クラスのインスタンスを作成し、そのクラスをCWinAppクラス(の派生クラス)のメンバ関数 AddDocTemplate( ) を呼び出し、アプリケーションに Document, View, FrameWnd, メニューなどのリソースの関連性を登録します。
一般的には CMyApp クラスの InitInstance( ) 関数で、以下のようなコードを記述することで行います。
CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate(IDR_MYTYPE, RUNTIME_CLASS(CMyDoc), RUNTIME_CLASS(CChildFrame), RUNTIME_CLASS(CMyView)); AddDocTemplate(pDocTemplate);
さて、 EXE ファイルから DOC, VIEW クラスを分離し、DOC, VIEW を Plugin 形式で自由に追加、削除できるようにした場合、EXEファイルコンパイル時には Document, View のクラス名を知ることができません(EXEファイルを実行し、何らかの手段で Plugin DLLの一覧を取得するまではどのような Document/View があるのかはわからないということです)。
したがって、EXE ファイルの CWinApp::InitInstance() 内で CDocTemplate クラスを生成&登録することはできません。
この解決方法として、次のような方法があります。
DOC/VIEWが実装されたDLLに RegisterDocDll() というような関数を実装し、これをエクスポートします。
アプリケーションにCDocTemplateを登録するために、アプリケーションが実行され、Doc/View Plugin の一覧の取得後、各PluginDLLのRegisterDocDll() 関数をコールします。この関数は CWinApp & 型の引数を受け取り、Dll内部で Document, Viewの登録処理を行います。
RegisterDocDll関数の内部は次のようになります。
BOOL __stdcall RegisterDocDll( CWinApp &App )
{
CMultiDocTemplate *pDocTemplate = new CDocTemplate(
IDR_MYTYPE,
RUNTIME_CLASS( CMyDoc ),
RUNTIME_CLASS( CFrameWnd ),
RUNTIME_CLASS( CMyView ) );
App.AddDocTemplate( pDocTemplate );
return TRUE;
}
ほかに、DLLの初期化処理が必要であれば、この関数内でやってしまいます。
Plugin ファイルの一覧を EXE側で列挙するための方法は、たとえば、Plugin DLL の拡張子を PDV(plugin doc view) 等に変更したり、あるいは設定ファイルやレジストリにあらかじめ値を書き込んでおくなどすることにより対処できます。
さて、今、DocViewDll とのインターフェースを C言語形式の関数呼び出しで作成しました。
実行ファイルから
BOOL __stdcall RegisterDocDll( CWinApp &App );
という関数を呼び出すことでプラグインを使用可能にしています。
しかし、せっかくC++のクラスライブラリを使用しているのに、プラグイン結合の部分だけCインターフェースというのも少し気分が悪いです。
また、現在は、プラグインを登録するインターフェースしか用意していませんが、今後、インターフェースが増えるに従いCインターフェースでは処理が煩雑になってしまいます(僕だけかな・・・?)。
C++のクラスを動的リンクすることはできないでしょうか?
COM化すれば確かに可能です。COMもずいぶん手軽に使えるようになりました。
しかし、COMよりはるかに簡単に、たとえば LoadLibrary 関数でクラスを動的ロードできるような仕組みを作ることはできないでしょうか?(無論、クラスのインターフェースも自由に呼び出すことができるような仕組みです)
結論を言ってしまうと、可能です。
これについては、別に公開したいと思います。