--- title: 动态获取当前模块的HMODULE/HINSTANCE值 date: 2018-05-14 18:38:45 tags: [win32] categories: windows --- 如何动态获取当前代码运行时所在的模块句柄?这里介绍三种方法。 ## 1. 使用GetModuleHandle 这是标准方案,可以动态获取exe或者dll模块句柄。 ```c++ HMODULE WINAPI GetModuleHandle( _In_opt_ LPCTSTR lpModuleName ); ``` 其中`lpModuleName`为dll或者exe名,如果扩展名被省略,默认会追加.dll后缀。如果结尾为`.`,则表示模块没有后缀名。一般来说,只需要执行模块名就可以了,如果指定了完整路径,分隔符必须使用`\`,不能使用`/`,如果使用`NULL`,则返回创建当前进程的exe句柄。另外,如果dll文件是以资源文件形式被加载,即指定了`LOAD_LIBRARY_AS_DATAFILE`,是无法使用该函数获取到句柄的。 ## 2. 使用VirtualQuery 函数原型为 ```c++ SIZE_T WINAPI VirtualQuery( _In_opt_ LPCVOID lpAddress, _Out_ PMEMORY_BASIC_INFORMATION lpBuffer, _In_ SIZE_T dwLength ); ``` 其中,`MEMORY_BASIC_INFORMATION `结构体中的`AllocationBase `就是模块基址,可以转换成模块句柄。 ```c++ 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 ```c++ EXTERN_C IMAGE_DOS_HEADER __ImageBase; #define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase) ``` 如果使用Microsoft链接器,就可以使用上面的方法来获取当前代码所在模块的句柄。伪变量`__ImageBase `表示模块的DOS头,即这个模块的起始地址。 一般使用场景为,编写了一个静态库,提供给其他人调用,需要动态获取运行时所在模块的句柄。 ```c++ #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(mbi.AllocationBase); #else // VC 7.0 // from ATL 7.0 sources return reinterpret_cast(&__ImageBase); #endif } ``` --- 参考链接: - https://blogs.msdn.microsoft.com/oldnewthing/20041025-00/?p=37483/ - http://www.codeguru.com/Cpp/W-P/dll/tips/article.php/c3635/