プラグイン・プログラミング(9)

 

2007年2月1日………プラグイン・プログラミング(8)の執筆後、引き続きこれを書いている。
これにてプラグイン・プログラミングは今度こそ終了である、予め断っておくと今回は今までのまとめに過ぎない。
つまり、今まで読み進めてきた者には不要である。冗長な文章を読むのが面倒な者や、注意点のまとめを見たい者の為である。

★プラグイン作成の基本

・関数のエクスポートは、「extern "C" __declspec(dllexport)」かモジュール定義ファイルで

・呼び出し規約は「cdecl」あるいは「stdcall」で、メンバ関数も同じだがBCCとVCなら「thiscall」もOK

・該当のDLLを「LoadLibrary」し、「GetProcAddress」で関数ポインタを取得し、「FreeLibrary」で解放する

・関数ポインタはtypedefで定義しておく、その方がソースコードの可読性も上がるしGetProcAddressで使いやすい

・DLL側からEXE側のエクスポートされた関数を取得するには、「GetProcAddress(GetModuleHandle(NULL), "「関数名」")」

★クラス&構造体(共通)

・仮想デストラクタを持たせてはならない

・パディングを統一しておく、具体的にはソースコードの最初に読み込まれる部分で「#pragma pack(1)」あるいは「#pragma pack(4)」

★クラス&構造体(継承して使う場合)

・BCCとVC以外でのプラグイン作成を許可する場合、全てのメンバ関数の呼び出し規約をcdeclに変えておく

・エクスポートするクラス(あるいは構造体)は単一継承で全てのメンバ関数を仮想にし、クラスに対応したFactory関数を用意する

・クラスを解放する為にDeleteInstance関数を用意する、あるいはSuicide関数のような自殺する為のメンバ関数をクラスに持たせておく

★クラス&構造体(そのまま使う場合)

・DLLで確保しEXEで解放する場合やその逆、メンバ関数内でnew/deleteを行う場合はnew/deleteをオーバーロードしなければならない

・方法は二つ存在する:EXE側のnew/deleteをDLL側のnew/deleteが呼び出すか、あるいはnew/deleteでのメモリの確保/解放をWINAPIに委譲する

★BCCとVCの相違点

・VCは「__declspec(dllexport)」で関数を修飾すると装飾名の先頭の「_」を勝手に削除してしまう、解決策は三つ

    1.「__declspec(dllexport)」で関数を修飾せず、モジュール定義ファイルを使用する

    2.BCCでモジュール定義ファイルを使用する、内容は装飾名の先頭の「_」を削除するもの

    3.VCでモジュール定義ファイルを使用する、内容は削除された先頭の「_」を再び追加するもの

・BCCで実行ファイルを作成する場合はモジュール定義ファイルが使用できない、よって3の方法しか選択肢がない

★その他

・プラグインによる動的な機能追加を実装する場合、switch構文ではなく「map<ユニークID、関数ポインタ>」で管理する

・EXE側は「map<ユニークID、関数ポインタ>に登録する関数」を用意しておき、DLL側はDllMainでmapに登録して機能追加を行う

・DLLがLoadLibrary時に行う処理は、DllMainの引数である「fdwReason」が「DLL_PROCESS_ATTACH」であるかをチェックしてから行う

・同じくDLLがFreeLibrary時に行う処理は、DllMainの引数である「fdwReason」が「DLL_PROCESS_DETACH」であるかをチェックしてから行う

・DLLのファイル名が分からないのでEXE側が検索しLoadLibraryする必要がある、DLLを検索しLoadLibraryするソースコードは以下に記す↓

#include <windows.h>
#include <vector>

using namespace std;

vector<HINSTANCE> hLibs;

void LoadPlugin(){
	HANDLE hFind;
	WIN32_FIND_DATA fd;

	hFind = FindFirstFile("*.dll", &fd);
	if(hFind!=INVALID_HANDLE_VALUE){
		do{
			hLibs.push_back(LoadLibrary(fd.cFileName));
			if(hLibs.back()==NULL){
				hLibs.pop_back();
			}
		}while(FindNextFile(hFind, &fd));
		FindClose(hFind);
	}
}

・上記のソースコードでLoadLibraryした全てのDLLにFreeLibraryを行うには、「hLibs」をイテレーティングすればよい(書く必要はないとも思うが一応)

 

 

 

以上、これで(9)は終了である。

 

前へ                                        戻る                                        次へ