DllMain の処理タイミング | akusanのブログ

akusanのブログ

ゲーム、プログラミングなどなど種々雑多に興味あるものをのせております。プログラミングはたまにコード自体を載せております。

最近書いていなかったのでプログラミングネタでも。

Windows限定の話です。LINUX、UNIX系については参考にならんです。

WindowsでDLLを呼び出す場合、動的に呼び出す場合と静的に呼び出す場合の
2種類ありますよね。

動的の場合はLoadLibraryを使用して、FreeLibraryで解放。
静的の場合は、*.libファイルをロードしてDLLMain使いますよね。

さて、ここでなんですが、DLLMainを使用した終了処理でかなり大変な目にあったことが・・・。
C++のデストラクタの呼び出しタイミングとDllMainの終了処理タイミングです。

システムに組み込むモジュールとしてと音声認識エンジンとして有名なとあるミドルウェアを
呼び出していました。
DllMainで終了処理をしようとしたんですが、なんと・・・2重解放が発生してしまい、
終了と同時にハングアップ!
偶然システムとしては基本的に常時動作しているシステムだったので、頻繁に停止するということが
なく実質、被害はなかったんですが・・・本当に大変な目に・・・。さらに、
メモリリークが発生していて、それを突き止めるのに・・・数か月を要するという・・・。
結局、ミドルウェアの使用方法がシステムにあっていなかったようです・・・。

DllMainってこんな感じですよね。


BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}


基本的にDLL_PROCESS_ATTACH、DLL_THREAD_ATTACH は
起動時に読みだします。DLL_PROCESS_ATTACHはプロセス起動時です。
DLL_THREAD_ATTACHはスレッド起動時です。
逆にDLL_THREAD_DETACH、DLL_PROCESS_DETACHは終了時に呼び出します。

最後のほうでDLL_PROCESS_DETACHが呼び出されます。
たしかデストラクタの後、起動しているすべてのスレッド終了時後に呼び出されます。
なので、注意しないと2重に解放処理が起きたということも十分にありえます。

もうひとつはDLL_THREAD_DETACH、DLL_THREAD_ATTACHです。
この人たちはスレッド生成削除毎に呼び出されます。そして、どのスレッドが呼び出しているのか、
区別がありません。なので、マルチスレッドでは注意が必要で、本来は処理させたくないところで、
別のスレッドでその処理をやらせてしまうということが起こりえます。

こういうことを注意して使えばかなり使えますからね~。
いいタイミングでしかるべき処理ができますからね~。

詳しく知りたい場合は、デバッグモードで起動してそれぞれのプロセスでブレークポイントを
貼っておくとタイミングがよくわかります。