DLLのスケルトン
DllMain() 関数は必須ではなく、以下のコード例では単純に、DllMain() 関数を含んだ骨格的なコードを提供するつもりでしたが、DLL を作りたい場合、実際にはエントリ関数である
の部分のみを記述するだけでも DLL としてコンパイルできてしまいます。コンパイルは、 bcc32 -tWD dllsample.cpp で行います。(bccコンパイラの場合)
この場合は "dllsample.dll" が作成されます。
DLL に記述した関数を外部から利用する最も基本的な方法は、LoadLibrary() 関数によりモジュール(DLL) のインスタンスを生成後、GetProcAddress() 関数によりその具体的な関数の関数アドレスを得て使用する方法です。
// // program "dllsample.cpp" // bcc32 -tWD dllsample.cpp #include <windows.h> BOOL WINAPI DllMain ( HINSTANCE hinstDLL, DWORD dwDllMainEvent ,LPVOID lpvReserved ) { switch( dwDllMainEvent ) { case DLL_PROCESS_ATTACH : // LoadLibrary() (など) でこの DLL のインスタンスが生成されようとしている。このタイミングを利用して DLL 側の好きな初期化をすればいい。このまま DLL のインスタンス生成を続行せず、中断したい場合は FALSE を返すようにする。LoadLibrary() によるロードが行われた場合なら、NULL が返りインスタンスの生成が中止される。アプリケーションの初期化、と同じように考えてよいでしょう. // MessageBox( NULL , "Check!" , "DLL_PROCESS_ATTACH はちょうどこのタイミングです" , MB_OK | MB_APPLMODAL ) ; break ; case DLL_PROCESS_DETACH : // FreeLibrary() (など) により、インスタンスが破棄されようとしている。このタイミング(機会) に DLL の後始末などがあればそれを行う(使ったメモリで開放とか) . break ; case DLL_THREAD_ATTACH : break ; case DLL_THREAD_DETACH : break ; } return TRUE ; } extern "C" __declspec(dllexport) int func1( int i ,int j ) { return i + j ; } // -- #ifdef __cplusplus ... の書き方にしたいなら, // #ifdef __cplusplus // extern "C" // #endif // __declspec(dllexport) int func1( int i ,int j ) { return i + j ; }
関数をいくつか記述する場合、毎回の extern "C" の記述を避けたい場合は、{} でくくる以下の様な書き方もできます。 #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) int func1( int i ,int j ) {... __declspec(dllexport) int func2( int i ,int j ) {... __declspec(dllexport) int func3( int i ,int j ) {... #ifdef __cplusplus } #endif ファイル名を .cpp にしてしまえば C++ であることが確定するから、#ifdef __cplusplus の条件は必要もありませんが、一般的にはこのような書き方をします。 |
extern "C"
は、( C++でなく ) Cの関数のようにコンパイルすることを指定しています。__declspec(dllexport)
は、関数をエクスポートすることを指定しています。プロトタイプ宣言を記述する場合は、
extern "C" と __declspec(dllexport) は、プロトタイプ宣言のところにだけに指定しておけば済みます。extern は、コンパイル時に、静的リンクを超えて (グローバルよりも偉い) 識別名を有効にするための一般的なCのキーワード(予約語)です。
DLL は基本的に、関数をそこに記述し、エクスポートするためのもの (あとで動的に利用するもの) です。この「動的な関数」は基本的に LoadLibrary() 関数、GetProcAddress() 関数 (関数アドレスを得る) を介して利用します。
関数をエクスポートする目的以外でも、SetWindowsHook() 関数によりメッセージフックを行う場合でコンピュータ上全てのメッセージを捕まえたい場合には、DLL を利用しなくてはなりません。
そのほか、
・ DllMain() は必要すらありませんが、記述する場合でも、これに知らされる4種類のイベントメッセージは、とくにやることがなければなにもしなくても構いません。
・ 上記例では、GetProcAddress( ..., "func1" ) ; のようにすれば関数のアドレスを取得できるはずです。もちろん DLL の外から行うことに意義があります。
[トップ] [戻る]