38

I have a static library that may get linked into either a .exe or a .dll. At runtime I want one of my library functions to get the HMODULE for whatever thing the static library code has been linked into.

I currently use the following trick (inspired from this forum):

const HMODULE GetCurrentModule()
{
    MEMORY_BASIC_INFORMATION mbi = {0};
    ::VirtualQuery( GetCurrentModule, &mbi, sizeof(mbi) );

    return reinterpret_cast<HMODULE>(mbi.AllocationBase);
}

Is there a better way to do this that doesn't look so hacky?

(Note: The purpose of this is to load some Win32 resources that I know my users will have linked in at the same time as my static library.)

Chan Kim
  • 5,177
  • 12
  • 57
  • 112
pauldoo
  • 18,087
  • 20
  • 94
  • 116

5 Answers5

59
HMODULE GetCurrentModule()
{ // NB: XP+ solution!
  HMODULE hModule = NULL;
  GetModuleHandleEx(
    GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
    (LPCTSTR)GetCurrentModule,
    &hModule);

  return hModule;
}
Serge Wautier
  • 21,494
  • 13
  • 69
  • 110
  • 1
    Cool. I remember now that when I wrote my GetCurrentModule() function we had to support Windows 2000. Which is why I used the VirtualQuery() hack instead of GetModuleHandleEx(). – pauldoo Feb 18 '09 at 08:57
  • GLad to help. Out of curiosity, why did you prefer my solution over the __ImageBase one? – Serge Wautier Feb 18 '09 at 14:23
  • 1
    Probably due to not understanding how Windows fixes up symbol addresses. – MSN Feb 18 '09 at 19:50
  • 6
    Note that if this succeeds, it increases the refcount on the module, so you'll need to call `FreeLibrary`. – Adrian McCarthy Apr 08 '10 at 20:24
  • 17
    @Adrian: Or use GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT. – Amnon Aug 17 '10 at 10:58
  • @Amnon this however returns the handle from the host in my case from the executable and not the dll that was called into. – Samuel Mar 18 '14 at 09:08
  • 1
    I believe that Annon intended to suggest that you combine GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT with GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, via bitwise OR, like so:GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT. This is exactly how I implemented a call to get the instance handle of my C++ unit test module, without resorting to writing a DLLMain routine of my own. – David A. Gray Nov 28 '16 at 05:40
  • You save the bacon! Thank you! – Damian Nov 29 '18 at 08:29
32

__ImageBase is a linker generated symbol that is the DOS header of the module (MSVC only). From that you can cast its address to an HINSTANCE or HMODULE. So it's more convenient than going through an API.

So you just need to do this:

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

From https://web.archive.org/web/20100123173405/http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx

Community
  • 1
  • 1
MSN
  • 53,214
  • 7
  • 75
  • 105
  • 1
    According to the link in my original question, the __ImageBase is only the preferred loading address, not always the actual loading address. – pauldoo Feb 17 '09 at 20:52
  • 2
    You doubt Raymond Chen? The discussion at the link demonstrates a fundamental misunderstanding of a linker constant, but the final comment is correct. – Mark Ransom Feb 17 '09 at 21:15
  • 5
    Err... __ImageBase is a symbol. If it weren't fixed up when the .dll or .exe is loaded, neither would any other symbol and everything would break. Therefore, it's valid to use it since its address is fixed up at image load time. – MSN Feb 17 '09 at 21:43
  • And the discussion at Raymond Chen's blog has a good discussion about the horrible side effects of GetCurrentModule (not Ex). – MSN Feb 17 '09 at 21:46
  • @MSN: I guess the remark on `GetCurrentModule` is a typo, as there is no such symbol in the Windows API. What were you referring to, and which comments discuss those side effects (and what are they)? – IInspectable Jun 13 '16 at 12:58
  • @MSN: That's the same link you posted in your answer already, and it doesn't mention `GetCurrentModule`. I assume you meant to say `GetModuleHandle`. But even then, neither the blog entry nor the comments mention any side effects. – IInspectable Jun 13 '16 at 19:25
  • @IInspectable What side effects are you referring to? The side effects of directly referencing `__ImageBase`? It's a symbol. There are no side effects. – MSN Jun 14 '16 at 17:01
  • @MSN: I was referring to your comment above: *"Raymond Chen's blog has a good discussion about the horrible side effects of GetCurrentModule (not Ex)"*. I assume that should read *"horrible breakage*" instead, as there are no side effects either. Not trying to split hairs. Just wanted to make sure that I haven't overlooked any pitfalls I wasn't aware of. – IInspectable Jun 14 '16 at 17:16
  • I don't know which version introduced support for `__ImageBase`, but both Clang's `lld` and GCC's `ld` support it as well. It's no longer *"MSVC only"*. – IInspectable Jan 31 '23 at 15:21
4

I'd look at GetModuleHandleEx() using the flag GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS. It looks like you can change your GetCurrentModule() to call this routine instead of VirtualQuery(), and pass the address of GetCurrentModule() as the lpModuleName argument.

ETA:

const HMODULE GetCurrentModule()
{
    DWORD flags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS;
    HMODULE hm = 0;
    ::GetModuleHandleEx( flags, reinterpret_cast<LPCTSTR>( GetCurrentModule ), &hm );   
    return hm;
}

I didn't try it, but I think that'll do what you want.

Rob K
  • 8,757
  • 2
  • 32
  • 36
0
#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 
} 

More here https://www.apriorit.com/dev-blog/74-hmodule-hinstance-handle-from-static-library-in-c

Peter
  • 1,124
  • 14
  • 17
-4

The HMODULE is the HINSTANCE is the base address of the module. So, I'd see how it worked. But if all you want is the HMODULE of the executable, why not enumerate all HMODULE's in the process (EnumProcessModules). One of them will have your .lib linked in.

The limitation I see is that you have no idea which DLL or EXE your .lib comes from. You might want to compare the HMODULEs (base addresses) against the _ReturnAddress you get from your .lib. Your .lib will belong to the highest HMODLUE smaller than your _ReturnAddress

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • Enumerating a list of modules is very inefficient, and not nearly as tidy as calling GetModuleHandleEx. Let's see; get the answer I need with a single, fast API call, or loop through potentially dozens of modules, performing string comparisons (VERY expensive!) as I go. I think I'll take the shortcut. – David A. Gray Nov 28 '16 at 05:47