如何正确地实现(c + +)线程本地存储在一个dynamic加载的DLL?

在这种情况下,我的dynamic加载的DLLWindows资源pipe理器加载,以便为文件/文件夹属性页添加一个新的propertysheet(新选项卡)。

一个简单的例子是StrmExt.dll( 下载源 )。 在这个例子中(微软提供的源代码)dll不使用线程本地存储(TLS),因此在同时加载多个属性页面时会导致严重的问题。

在审查源DLL时,需要一个线程基variables(文件的文件path)…

static TCHAR g_szFile[MAX_PATH]; 

将这一行代码更改为:

 _declspec (thread) TCHAR g_szFile[MAX_PATH]; 

…使dll支持多个线程,并因此支持propertysheet的多个实例。 不过,我知道这个改变只会被Windows Vista和更新版本所支持(Windows 7的testing非常积极)。 XP,例如,不会支持这个dynamic加载库…这是已知的崩溃的应用程序 。 (见最后一段)。

为了在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; } 

这工作正常的第一次加载的DLL是否创build1或2线程。 在释放dll后,资源pipe理器在下一次加载库时崩溃。

我误解了什么? 我注意到原来的开发人员故意禁用线程通知的DLL进程附加通知。 为什么?

 DisableThreadLibraryCalls(hInstance); 

先谢谢了。

在这种情况下,最好避免这个问题。 是的,你可能会有比线程更多的线程,是的,每个属性表将只与一个线程相关联,但是不能保证相反。 两个属性表可能共享一个线程,这取决于操作系统。 (而且这些无证的决定在版本之间改变)。

而是使用PROPSHEETPAGElParam成员。 在64位系统上也可以容纳一个指针。 指向你自己的班级。 终身管理比您尝试使用的DLL连接/分离简单得多; Windows在适当的时候调用PropSheetPageProc