DLL内部で作成したスレッドのスタックが終了時に解体されない

DLLを作成しました。
本体プログラムが終了するときには、DLLも終了します。
このDLLの中で、COMを使用しようと思ったのですが、意外と難しい。

DLLがプロセスやスレッドにアタッチされるとき(DLLが読み込まれたときや解放されたとき)、DllMain() 関数がコールされます。
DllMain()関数の引数に、何故DllMain()関数が呼び出されたのかという情報がシステムによって渡されて来ます。


BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // DLL モジュールのハンドル
DWORD fdwReason, // 関数を呼び出す理由
LPVOID lpvReserved // 予約済み
);


ここでいう fdwReason がその呼び出し理由です。

理由は4種類。

プロセスにアタッチされた。(DLL_PROCESS_ATTACH)
プロセスからデタッチされた。(DLL_PROCESS_DETACH)
スレッドにアタッチされた。(DLL_THREAD_ATTACH)
スレッドからデタッチされた。(DLL_THREAD_DETACH)


ここで問題その1は、スレッドのアタッチとデタッチ。
プロセス内の全てのスレッドに対してこのコールが発生する訳ではありません。

DLL_THREAD_ATTACH の場合、あくまでも新しく作成されたスレッドの中から、そのスレッドの処理を開始する前に DllMain() が呼び出されます。
もちろんDLLをアタッチした(ロードした)スレッドからは呼び出されません。

DLL_THREAD_DETACH の場合、DLLがアンロード(デタッチ)される前に終了したスレッドからのみDllMain() が呼び出されます。

このような仕様のため、使いにくいです。


DLL_PROCESS_ATTACH や、DLL_THREAD_DETACH の場合にも問題があります。
これらは、DLL_PROCESS_ATTACH は、DLLをロードしたスレッドから呼び出されますが、DLL_THREAD_DETACH は、それと同じスレッドから呼び出されるとは限りません。

これらは、COMの仕様である CoInitialize()/CoUninitialize() の呼び出しに影響します。

COMでは COMを使用するスレッド毎に CoInitialize()/CoUninitialize() の呼び出しが必要になります。
そのため、DLLを呼び出すスレッド全てにおいて、CoInitialize()/CoUninitialize() を正しく呼び出したいのですが、うまくいきません。

よくよく見ると、MSDNの CoInitialzie() の説明の最後に、
Because there is no way to control the order in which in-process servers are loaded or unloaded, do not call CoInitialize, CoInitializeEx, or CoUninitialize from the DllMain function.

などと、注意書きが。。。



そこで、DLLの中にスレッドを作成して、その1つのスレッドの中だけでCOM関連の処理を行う方法を考えました。
DLLの中でスレッドを作成、COM初期化、そして、COMを使用。

成功したかに見えましたが、DLLをロードしているプロセスが終了したときに、有無を言わせずにスレッドが停止してしまう事が判明しました。
スレッドのスタックの解体も行われないまま、、、
そのため、CoUninitialize() を呼び出す暇も、COMオブジェクトを解放する暇もありません。
最後の DllMain() が呼び出されたときには、跡形もなく破棄されてしまっています。

ひどい。
ひどすぎだ。

というわけで、DLL内でCOMを使うのは難しいという結論に至りました。

※ここで難しいのは、DLLを呼び出す側のアプリケーションは、自分で作成したものではないところです。
自分で作成したのなら、スレッドの開始や停止を制御できますので、全く問題なくCOMをつかえると思います。
今回は、あるプログラムの使用しているDLLと同じインターフェースのDLLを作って、処理を一部変更してしまおう!プロジェクトのため、こんな面倒な事になっています。

。。。不可能だ!

DLLだけでは不可能!

こうなったら、COMを使用する外部プログラムでも作って、共有メモリでも使ってデータを受け渡すしかないか。。。
[PR]
by isoq | 2006-12-26 11:04 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇
<< 足りなかったもの 原因不明のリンクエラー >>