动态获取当前模块的HMODULE/HINSTANCE值

如何动态获取当前代码运行时所在的模块句柄?这里介绍三种方法。

1. 使用GetModuleHandle

这是标准方案,可以动态获取exe或者dll模块句柄。

1
2
3
HMODULE WINAPI GetModuleHandle(
_In_opt_ LPCTSTR lpModuleName
);

其中lpModuleName为dll或者exe名,如果扩展名被省略,默认会追加.dll后缀。如果结尾为.,则表示模块没有后缀名。一般来说,只需要执行模块名就可以了,如果指定了完整路径,分隔符必须使用\,不能使用/,如果使用NULL,则返回创建当前进程的exe句柄。另外,如果dll文件是以资源文件形式被加载,即指定了LOAD_LIBRARY_AS_DATAFILE,是无法使用该函数获取到句柄的。

2. 使用VirtualQuery

函数原型为

1
2
3
4
5
SIZE_T WINAPI VirtualQuery(
_In_opt_ LPCVOID lpAddress,
_Out_ PMEMORY_BASIC_INFORMATION lpBuffer,
_In_ SIZE_T dwLength
);

其中,MEMORY_BASIC_INFORMATION结构体中的AllocationBase就是模块基址,可以转换成模块句柄。

1
2
3
4
5
6
7
8
9
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;
PVOID AllocationBase;
DWORD AllocationProtect;
SIZE_T RegionSize;
DWORD State;
DWORD Protect;
DWORD Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;

3. 使用伪变量__ImageBase

1
2
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)

如果使用Microsoft链接器,就可以使用上面的方法来获取当前代码所在模块的句柄。伪变量__ImageBase表示模块的DOS头,即这个模块的起始地址。

一般使用场景为,编写了一个静态库,提供给其他人调用,需要动态获取运行时所在模块的句柄。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#if _MSC_VER >= 1300    // for VC 7.0
// from ATL 7.0 sources
extern "C" IMAGE_DOS_HEADER __ImageBase;
#endif

HMODULE GetCurrentModule()
{
#if _MSC_VER < 1300 // earlier than .NET compiler (VC 6.0)
// Here's a trick that will get you the handle of the module
// you're running in without any a-priori knowledge:
// http://www.dotnet247.com/247reference/msgs/13/65259.aspx

MEMORY_BASIC_INFORMATION mbi;
static int dummy;
VirtualQuery(&dummy, &mbi, sizeof(mbi));

return reinterpret_cast<HMODULE>(mbi.AllocationBase);

#else // VC 7.0
// from ATL 7.0 sources

return reinterpret_cast<HMODULE>(&__ImageBase);
#endif
}

参考链接:

发布时间: 2018年05月14日 - 18时38分
更新时间: 2018年10月17日 - 21时42分
原始链接: https://oaoa.me/posts/2eca455a/