如何判断Windows模块句柄是否仍然有效?

时间:2009-07-10 20:31:12

标签: windows winapi module handle

可以卸载模块,那么如何确定它是否仍在内存中?我有一个句柄,从GetModuleHandle获得。当我尝试在其上调用GetHandleInformation时,我看到错误0xc0000008 - “指定了无效的HANDLE”。这发生在它可以被卸载之前。

3 个答案:

答案 0 :(得分:4)

术语“句柄”在这里有点重载 - Win32 API中许多不同类别的对象称为“句柄”。

GetHandleInformation用于内核对象的句柄 - 文件,注册表项,互斥锁等。

GetModuleHandle返回的HMODULE由加载器使用,并不是实际的内核对象,因此GetHandleInformation失败。你在GetHandleInformation中获得的任何标志都不适用于HMODULE。

如果你想检查HMODULE是否仍然在内存中加载,你可以调用GetModuleHandle - 这个API应该足够快,可以多次调用。但是,GetModuleHandle的结果在返回时可能无效 - 另一个线程可以调用FreeLibrary。最好确保DLL确实保持加载状态。您可以通过自己调用LoadLibrary或调用GetModuleHandleEx来执行此操作,这将增加DLL的引用计数。

答案 1 :(得分:2)

两种解决方案:

1

在HMODULE上调用GetModuleFileName()。如果加载模块,您将获得有效的文件名。如果未加载,则不会获得有效的文件名。在调用GetModuleFileName()或检查返回值之前,请确保将返回的文件名数组的第一个字节设置为“\ 0”。如果在调用之前设置第一个字节,则可以有效地忽略返回值,并将零长度字符串视为“未加载”信号。

TCHAR szModName[MAX_PATH + 1];

szModName[0] = _T('\0');
GetModuleFileName(hMod, szModName, MAX_PATH);

// zero length string if not loaded, valid DLL name if still loaded

2

调用VirtualQuery()传递HMODULE作为要查询的地址。作为实验,在已加载的库和您知道要释放的库上执行此操作。您会发现它们对返回的MEMORY_BASIC_INFORMATION有非常不同的结果。我留给你制定一个合适的算法来确定两者之间的差异。

买者

当然,在运行这些测试时,另一个线程可能会卸载库的警告适用。根据我的经验,这种情况极不可能发生,但这在很大程度上取决于你在做什么,为什么要这样做,以及当你在做这个程序的执行路径时。 谨慎使用。

答案 2 :(得分:0)

这是非常简单的API。

PIMAGE_NT_HEADERS (NTAPI* _RtlImageNtHeader)

示例程序:

(PVOID)typedef PIMAGE_NT_HEADERS (NTAPI *RTLIMAGENTHEADER)(PVOID);
RTLIMAGENTHEADER RtlImageNtHeader;
HMODULE hDll = GetModuleHandle("ntdll.dll");
HMODULE hDllTmp = LoadLibrary("ws2_32.dll");
RtlImageNtHeader = (RTLIMAGENTHEADER)GetProcAddress(hDll,"RtlImageNtHeader");

struct _IMAGE_NT_HEADERS *r,*r2;
r= RtlImageNtHeader(hDllTmp); 
FreeLibrary(hDllTmp);
r2= RtlImageNtHeader(hDllTmp);

//r = NULL
//r2 = return ws2_32 PE Header address