----[testdll.cpp]---- #include <windows.h> extern "C"{ int WINAPI _declspec(dllexport) TestFunc2(int arg1,int arg2); }; int _declspec(dllexport) TestFunc1(int arg1,int arg2) { return (arg1-arg2); } int WINAPI _declspec(dllexport) TestFunc2(int arg1,int arg2) { return (arg1-arg2); } BOOL WINAPI DllEntryPoint(HINSTANCE hInstance, DWORD fdwReason, LPVOID*lpvReserved){ { BOOL flag; switch (fdwReason){ case DLL_PROCESS_ATTACH: //ロードされるときの処理 return TRUE; case DLL_PROCESS_DETACH: //アンロードされるときの処理 return TRUE; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; } return TRUE; }DLL の初期化と終了処理を記述したい場合には、上記のような DllEntryPoint を用意する。 DllEntryPoint はプロセスによりロード、アンロードされるときと、スレッドが起動、 終了するときに呼ばれる。 どの条件で呼ばれたかは、fdwReason で判別する。
次に関数を用意する。今回は2つの引数の差を返す関数 TestFunc1,TestFunc2 を用意する。 外部に公開する関数には _declspec(dllexport)を付ける。 また C++ の場合、実際につけられる関数名はユーザーが付けた名前を加工して作られる。 名前を加工して欲しくない場合は、extern "C" を宣言する。 また WINAPI を付けるのは、 外部公開名にアンダースコアが付かないようにするためである。
実際に DLL を作成するには DOS窓から以下のように打ち込む。
BCC32 -WD testdll.cpp
エラーがなければ、 testdll.dll が作成される。
外部公開名を確認するには、TDUMPを使う。
TDUMP testdll.dll
と入力して出力結果をみると TestFunc1 は
"TestFunc1(int, int)"として、
TestFunc2 はそのまま公開されているのが確認できる。
TestFunc1 の呼び出しは静的に結合を行う方法で、ライブラリーを使用する。この方法は一般的な API を呼び出す場合と同じである。
TestFunc2 の呼び出しは動的に結合を行う方法で、DLL を自分でロードして、
関数のアドレスを取得して呼び出す。
ライブラリーは使用しない。この方法は静的な方法に比べると面倒臭いが、
DLL や関数が見つからない場合でもアプリケーションで対処可能という利点がある。
以下はTestFunc2 を呼び出している部分である。
----[test3.cpp の一部]---- case IDC_CALL2: hdll=LoadLibrary("TestDll.DLL"); if(!hdll){ SetWindowText(GetDlgItem(hDlg,IDC_LABEL2),"DLL が見つかりません"); return TRUE;} fproc=GetProcAddress(hdll,"TestFunc2"); if(!fproc){ SetWindowText(GetDlgItem(hDlg,IDC_LABEL2),"関数が見つかりません"); FreeLibrary(hdll); return TRUE;} GetWindowText(GetDlgItem(hDlg,IDC_EDIT1),buf,80); n1=atoi(buf); GetWindowText(GetDlgItem(hDlg,IDC_EDIT2),buf,80); n2=atoi(buf); n3=(*(int (*)(int,int))fproc)(n1,n2); sprintf(buf,"%d",n3); SetWindowText(GetDlgItem(hDlg,IDC_LABEL),buf); FreeLibrary(hdll); return (TRUE);
初期化のルーチンが LibMain になっていたのを DllEntryPoint に修正。 Visual C と同じだと勘違いしていた。
外部公開名にアンダースコアが付かないようにするために、 以前はコンパイラオプションで -u- を指定していたが、 これだと C のライブラリ関数の呼び出しができなくなる副作用があるので、 WINAPI を付ける方法に変更した。
2000.12.05 修正