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

如何判断Windows模块句柄是否仍然有效?,windows,winapi,module,handle,Windows,Winapi,Module,Handle,一个模块可以卸载,那么我如何确定它是否仍在内存中?我有一个从GetModuleHandle获得的句柄。当我尝试对其调用GetHandleInformation时,我看到错误0xc0000008-“指定了无效句柄”。这是在卸载之前发生的。术语“句柄”在这里有点过载-Win32 API中的许多不同类的对象称为“句柄” GetHandleInformation用于内核对象(文件、注册表项、互斥体等)的句柄 GetModuleHandle返回的HMODULE由加载程序使用,并且不是实际的内核对象,因此G

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

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

GetHandleInformation用于内核对象(文件、注册表项、互斥体等)的句柄

GetModuleHandle返回的HMODULE由加载程序使用,并且不是实际的内核对象,因此GetHandleInformation失败。但是,GetHandleInformation中的两个标志对于HMODULE都没有意义

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

两种解决方案:

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

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

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

这是一个非常简单的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

那么有没有其他方法来检查HMODULE?谢谢。您可以通过两种方式之一来完成此操作:要么手头有“合同”:即库文档指定加载或卸载dll的时间和方式,要么自己调用LoadLibrary。否则,线程可以随时卸载库,并在同一基址加载不同的dll。
(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