tags:

views:

2558

answers:

4

I have a static library that may get linked into either a .exe or a .dll. At runtime I want ony 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.)

+1  A: 

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
A: 

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
+5  A: 
HMODULE GetCurrentModule()
{ // NB: XP+ solution!
  HMODULE hModule = NULL;
  GetModuleHandleEx(
    GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
    (LPCTSTR)GetCurrentModule,
    &hModule);

  return hModule;
}
Serge - appTranslator
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
GLad to help. Out of curiosity, why did you prefer my solution over the __ImageBase one?
Serge - appTranslator
Probably due to not understanding how Windows fixes up symbol addresses.
MSN
Note that if this succeeds, it increases the refcount on the module, so you'll need to call `FreeLibrary`.
Adrian McCarthy
@Adrian: Or use GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT.
Amnon
+4  A: 

__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 http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx

MSN
According to the link in my original question, the __ImageBase is only the preferred loading address, not always the actual loading address.
pauldoo
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
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
And the discussion at Raymond Chen's blog has a good discussion about the horrible side effects of GetCurrentModule (not Ex).
MSN