最近看代码,遇到一个很有趣的问题:如何获取一个静态库代码链接进模块的句柄?
模块句柄值实际上是这个模块加载内存中的基地址。我们暂且放下这个问题,先看看动态库是如何获取句柄值的。
动态库获取句柄值
正常情况下一个动态库dll获取它的句柄,可以通过GetModuleHandle或者GetModuleHandleEx这个API来获取。
HMODULE WINAPI GetModuleHandle(
_In_opt_ LPCTSTR lpModuleName
);
BOOL WINAPI GetModuleHandleEx(
_In_ DWORD dwFlags,
_In_opt_ LPCTSTR lpModuleName,
_Out_ HMODULE *phModule
);
这个两个API都需要把dll模块名传进去才能获取句柄值。但是dll可能被人重命名,所以这个方法不一定百分百可靠。
另外一种办法是在DLLMain入口函数里保存hinstDLL值。但是不一定所有的Dll都有Dll,所以这个方法也是不一定百分百可靠。
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
);
还有种方法是调用VirtualQuery接口获取MEMORY_BASIC_INFORMATION值:
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;
MEMORY_BASIC_INFORMATION结构体里面的MEMORY_BASIC_INFORMATION.AllocationBase就是基地址,可以转换成模块的句柄。这个算是获取Dll句柄的终极办法了。但是这个办法毕竟有些hack,不到万不得已,就别用。
从http://www.codeguru.com/Cpp/W-P/dll/tips/article.php/c3635/ 学到一个办法,这里有段代码是专门用来解决这个问题的:
//#if _MSC_VER >= 1300 // for VC 7.0
//// from ATL 7.0 sources
//#ifndef _delayimp_h
//extern "C" IMAGE_DOS_HEADER __ImageBase;
//#endif
//#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
//}
这段代码里面还有另外一种获取模块句柄的方法:__ImageBase。
__ImageBase是Microsoft编译器生成的伪变量,__ImageBase代表着模块的DOS头,也就是模块的起始地址。换言之,也就是这个模块的基地址,这个模块的句柄。
静态库获取句柄值
因为你不知道静态库会被哪个模块链接,所以无法使用GetModuleHandle这个API来获取句柄。它没有DLLMain函数,也无法使用VirtualQuery。幸好静态库同样可以使用__ImageBase。详见https://blogs.msdn.microsoft.com/oldnewthing/20041025-00/?p=37483/ 介绍。