Tips of VC++ >
DLL >
明示的リンク
★ 前へ戻る ★ 次へ進む ★
このドキュメントにはサンプルプログラムが含まれています。
ワークスペース
ソースファイル(テキスト)
最初に「DLL概要」と 「エクスポートとインポートとリンク」を 読むと、すんなりと理解できるでしょう。 また、DLLのリンク方法には、「暗黙的リンク」を お薦めします。理由は単純に記述が楽だから。明示的リンクは面倒です。
名前のとおり、明示的リンクはAPIを呼び出してDLLをロードし、 関数アドレスへのポインタを取得して、関数を呼び出す方法です。 暗黙的リンクは、暗黙のうちに、このへんも処理をやってくれましたよね? まあ、利点もあるわけですが…。そのへんは 「エクスポートとインポートとリンク」を参照。
明示的リンクに使用する手順は以下です。
なんだかんだ言って、使う関数は二つです。まず一個目
HMODULE LoadLibrary(
LPCTSTR lpFileName // モジュールのファイル名
);
DLLをロードして、メモリにマップさせ、そのDLLのDllMain関数を呼び出します。 引数にはDLLへのパスを指定します。 絶対パスを記述すればいいですが、その他の場合の検索の手順は以下のとおり。
環境変数PATHってよく分かりません。(ぉぃぉぃ
この関数はDLLではなくEXEファイルもロードできます。
LoadResourceとか使って他の実行可能ファイルのリソースを読み込めます。
ここでは、DLLの関数を呼び出すのが目的なので、 戻り値であるハンドルをGetProcAddressに渡します。 指定したパスにDLLがなかったり、 DllMainがTRUEを返さなかった場合、エラーになります。
FARPROC GetProcAddress( HMODULE hModule, // DLL モジュールのハンドル LPCSTR lpProcName // 関数名 );
DLL内のエクスポート済関数のアドレスを取得します。
戻り値は関数アドレスです。
FARPROCってのはただのポインタなので、呼び出す関数に合わせて
typedefを使って新たに細かい関数型を作ったほうがいいです。
パラメータは、LoadLibraryの戻り値であるライブラリへのハンドル。
また、関数名を示す文字列へのポインタです。
これはDLL内部での関数名ではないのがミソです。
エクスポートされている識別名(?)みたいなもので、
VisualC++付属のツールに含まれているDependency Walkerや、
同じく付属されているDUMPBIN.EXEとか、
Windows付属のクイックビューアを使えば見れます。
また、オンラインソフトにもDachoさんという方の
[Dependency Viewer]というソフトがあって、
Dependency Walkerとほぼ同じ機能が使えます。すごいなぁ…。→
ここから
これらのソフトで表示される名前をそのまま使います。
また、序数でエクスポートされている場合、
数字をそのままLPCTSTR型にキャストして使ってください。
こっちのほうが楽かもしれませんね。
あとは、ポインタを使って関数を呼び出します。 関数ポインタの使い方さえ知っていれば、何も難しいことはないテクニックです。
サンプルを使って、試しに作ってみます。 DLLの関数を呼び出すだけなので、単一ファイルでいいでしょう。 適当な名前のソースファイルを作って以下のように書きます。 同時に二つのDLLを使ってみました。export1.dllとexport2.dllは、それぞれ、 __declspec(dllexport)を使ってエクスポートと モジュール定義ファイル(.DEFファイル)を使ってエクスポート のサンプルに対応しています。
#include <windows.h> // ユニークな関数型の定義 typedef int (*AVERAGE)(int,int); // DLLへの相対パス const char DLLPATH1[]="export1.dll"; const char DLLPATH2[]="export2.dll"; int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // DLLをロード HMODULE hDll1= ::LoadLibrary(DLLPATH1); HMODULE hDll2= ::LoadLibrary(DLLPATH2); // 関数アドレス取得 AVERAGE average1= (AVERAGE)::GetProcAddress(hDll1,"?average@@YAHHH@Z"); AVETAGE average2= (AVERAGE)::GetProcAddress(hDll2,(LPCTSTR)100); // 関数呼び出し int result1= average1(8456,562); int result2= average2(562,8456); // 結果表示ルーチン char buf[100]; ::wsprintf(buf,"result1= %d\r\nresult2= %d",result1,result2); ::MessageBox(NULL,buf,"finish",MB_ICONEXCLAMATION); return 0; }
もちろん結果は、いずれとも4509になるはず。
Jul.26, 2002