在这种情况下,我的动态加载的DLL是由Windows资源管理器加载的,以便向文件/文件夹属性页面添加新的属性表(新选项卡)。
一个简单的例子是StrmExt.dll(下载源代码)。在这个例子中(由Microsoft提供的源代码),该DLL没有使用线程本地存储(TLS),因此在同时加载多个属性页时会造成重大问题。
在审查源代码后,该DLL需要一个基于线程的变量(文件路径)。...
这在第一次加载DLL时运行良好,无论我创建1个或2个线程。在释放DLL后,资源管理器在下一次加载库时崩溃。
我误解了什么?我注意到原始开发人员故意禁用了DLL进程附加通知的线程通知。为什么?
一个简单的例子是StrmExt.dll(下载源代码)。在这个例子中(由Microsoft提供的源代码),该DLL没有使用线程本地存储(TLS),因此在同时加载多个属性页时会造成重大问题。
在审查源代码后,该DLL需要一个基于线程的变量(文件路径)。...
static TCHAR g_szFile[MAX_PATH];
将这一行代码更改为:
_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;
}
这在第一次加载DLL时运行良好,无论我创建1个或2个线程。在释放DLL后,资源管理器在下一次加载库时崩溃。
我误解了什么?我注意到原始开发人员故意禁用了DLL进程附加通知的线程通知。为什么?
DisableThreadLibraryCalls(hInstance);
DisableThreadLibraryCalls
的调用,以便接收DLL_THREAD_ATTACH
和DLL_THREAD_DETACH
。除此之外,我猜您可能会因为DllMain的不确定性而有一些泄漏问题。 - David Heffernan