この場合、動的にロードされたDLLは、ファイル/フォルダーのプロパティページに新しいプロパティシート(新しいタブ)を追加するために、Windowsエクスプローラーによってロードされます。
この簡単な例は、StrmExt.dll(ダウンロードソース)です。この例(Microsoftが提供するソース)では、DLLはスレッドローカルストレージ(TLS)を使用しないため、複数のプロパティページを同時にロードするときに大きな問題が発生します。
ソースを確認すると、DLLには1つのスレッドベース変数(ファイルのファイルパス)が必要でした...
static TCHAR g_szFile[MAX_PATH];
この1行のコードを次のように変更します。
_declspec (thread) TCHAR g_szFile[MAX_PATH];
... DLLが複数のスレッドをサポートできるようにしたため、プロパティシートの複数のインスタンスをサポートできるようになりました。ただし、この変更はWindows Vista以降でのみサポートされることを私は知っていました(Windows 7でのテストは非常に肯定的です)。たとえば、XPは、動的にロードされたライブラリではこれをサポートしません...そしてアプリケーションをクラッシュさせることが知られています。(最後の段落を参照)。
XPで実行するために、この宣言を使用できませんでした。DLLエントリポイントを次の場所から拡張する必要があると思いました。
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
_Module.Init(ObjectMap, hInstance, &LIBID_STRMEXTLib);
DisableThreadLibraryCalls(hInstance);
}
else if (dwReason == DLL_PROCESS_DETACH)
_Module.Term();
return TRUE; // ok
}
...このようなものに...以前にここで見たように
struct ThreadData {
static TCHAR g_szFile[MAX_PATH];
};
...
DWORD g_dwThreadIndex;
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance,
DWORD dwReason, LPVOID /*pReserved*/)
{
ThreadData* pData;
switch (dwReason) {
case DLL_PROCESS_ATTACH:
g_dwThreadIndex = ::TlsAlloc();
if (g_dwThreadIndex == TLS_OUT_OF_INDEXES)
return FALSE;
// execute the DLL_THREAD_ATTACH code
case DLL_THREAD_ATTACH:
// allocate memory for this thread
pData = (ThreadData*) ::LocalAlloc(LPTR, sizeof(ThreadData));
if (pData == 0)
return FALSE;
::TlsSetValue(g_dwThreadIndex, (LPVOID) pData);
break;
case DLL_THREAD_DETACH:
// release memory for this thread
pData = (ThreadData*) ::TlsGetValue(g_dwThreadIndex);
if (pData != 0)
::LocalFree((HLOCAL) pData);
break;
case DLL_PROCESS_DETACH:
// release memory for this thread
pData = (ThreadData*) ::TlsGetValue(g_dwThreadIndex);
if (pData != 0)
::LocalFree((HLOCAL) pData);
// release the TLS index
::TlsFree(g_dwThreadIndex);
break;
}
return TRUE;
}
これは、1つまたは2つのスレッドを作成するかどうかに関係なく、DLLの最初のロード中に正常に機能します。DLLが解放された後、ライブラリの次のロード時にExplorerがクラッシュします。
私は何を誤解していますか?元の開発者がDLLプロセスの接続通知時にスレッド通知を意図的に無効にしていることに気付きました。なんで?
DisableThreadLibraryCalls(hInstance);