Once long time ago I was curious how to get a descriptor of the module mapped into memory (.exe
or .dll
), if its name and other attributes needed for using special API functions are unknown. If in the case of GetModuleHandle
with zero parameter value the process or .exe descriptor is being returned, how to deal with .dll
then? I didn’t find a solution at that time, though now it seems a really simple task.
How To Get The HMODULE, HINSTANCE, or HANDLE From Static Library In C++
Variant 1.
GetModuleHandleEx
. As you see from the title it’s extended. The function takes on a flag value as one of parameters. Among its values GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
is presented. As far as I understood, it brings in a sense of order: I have a certain address in the executable code – I wish to know which module it belongs to. It ideally matches my task, when from static library in several dynamic modules I need to retrieve a descriptor of each one.
But MSDN writes:
Requirements
Client: Requires Windows XP.
Server: Requires Windows Server 2003.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Well, if so – then it’s truth, though severe one.
In the Internet I had come across the following:
// from ATL 7.0 sources
#ifndef _delayimp_h
extern "C" IMAGE_DOS_HEADER __ImageBase;
#endif
....
HMODULE Module()
{
// from ATL 7.0 sources
return reinterpret_cast(&__ImageBase);
}
Also works wonderful. However, it has restrictions on the compiler used. First, it must be MS compiler and second, not lower for the version 7.0. I.e. on MS VS 6.0 it’s not a true already. Therefore…
Variant 3.
How system operates at LoadLibrary? It maps an executable file into the process memory. Then receives all the necessary structures from the header of PE file (on PE format please refer to the documentation – it can be found everywhere), one of which is IMAGE_NT_HEADERS32:: OptionalHeader:: SizeOfImage
. Based on the value of this field, the loader allocates and transfers physical memory by means of unique universal tool, VirtualAlloc
, to a certain block, to which it copies an image of the whole file to the addresses which are specified in the same PE header for each separate section. Further there is the usual routine work on loading additional functions from the table of import, correction of addresses and so on. Then the starting input point (Original Entry Point – OEP) is calculated and pass of control to OEP is performed. In the case of .dll
this call leads via DLL startup code (you can view it in the dllcrt0.c
file in the Studio) and finally brings to DLLMain
if it exists.
So what does HMODULE
, aka HINSTANCE
, aka HANDLE
mean for DLL
module? It is a pointer to the block of memory allocated for image by VirtualAlloc
function and provided to HMODULE
.
We can be convinced of it after viewing in a debugger a piece of memory to which the value of HMODULE
refers. It starts with
MZ...............@...........!..L.!
This program cannot be run in DOS mode.
Here it is, the beginning of PE header, namely its DOS section.
Thus, how to get HMODULE
from static library? It is necessary to find only the beginning of the piece of virtual memory which had been allocated for the copy of PE module image. How to get it then? If there was a VirtualAlloc
, then VirtualQuery
will work fine. It takes on an optional address within the limits of the selected and handled region of physical memory and returns the next describing structure at that:
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;
PVOID AllocationBase;
DWORD AllocationProtect;
DWORD RegionSize;
DWORD State;
DWORD Protect;
DWORD Type;
} MEMORY_BASIC_INFORMATION;
typedef MEMORY_BASIC_INFORMATION
*PMEMORY_BASIC_INFORMATION;
Here the AllocationBase
field catches our eyes. It contains the starting address of the allocated region. It’s just what we need. This is how the extended function looks with consideration of the Variant 2:
#if _MSC_VER >= 1300 // for VC 7.0
#ifndef _delayimp_h
extern "C" IMAGE_DOS_HEADER __ImageBase;
#endif
#endif
...
HMODULE module()
{
#if _MSC_VER < 1300 // earlier than .NET compiler (VC 6.0)
MEMORY_BASIC_INFORMATION mbi;
static int address;
;::VirtualQuery(&address, &mbi, sizeof(mbi));
return reinterpret_cast(mbi.AllocationBase);
#else // VC 7.0
// from ATL 7.0 sources
return reinterpret_cast(&__ImageBase);
#endif
}