At Loss for Words

…of Programming, Love and Metaphors

GetCurrentModuleHandle

,

There is a one very common problem when writing a DLL. Getting a HINSTANCE of your module after you have missed it in DllMain (or you just don't want to use a global variable, or don't want to propagate it all the way, whatever). Retrieving resources from the module, and thus almost every UI call, is impossible without this handle. And you have already found that GetModuleHandle(NULL) is useless, because it returns handle to the EXE (usually preferred 0x00400000), not your DLL handle.

First note that HINSTANCE (or HMODULE) of the module (exe/dll/...) is simply a pointer to the address where the module has been loaded, the image base pointer. And it so happens that newer MSVC and MinGW linkers (and probably some others too) do export symbol called __ImageBase. If you are this lucky, the following implementation should be sufficient:

HINSTANCE GetCurrentModuleHandle () {
    extern char __ImageBase;
    return reinterpret_cast <HINSTANCE> (&__ImageBase);
}
This code will work for you if it don't err at compile (link) time.

If you don't have this symbol available but can restrict your application to Windows XP and newer, there is GetModuleHandleEx flag GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS. Important thing is that you must pass an address that reside inside your image. Static variables and function pointers will usually work but consult manual to your compiler. Local variables that live on stack or heap-allocated pointers will not work. Rough approach to use this technique may look like this:

HINSTANCE GetCurrentModuleHandle () {
    HMODULE hModule = NULL;
    if (GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, 
                           reinterpret_cast <LPCTSTR>
                                            (&GetCurrentModuleHandle),
                           &hModule)) {
        return hModule;
    } else {
        return NULL;
    };
}

And sometimes, when you need your program to work on Windows 2000, the PSAPI library and the EnumProcessModules function will come in handy. This is the hard way where you enumerate all modules in the process and compare their bounding addresses. My rough implementation follows to make the idea clearer:

HINSTANCE GetCurrentModuleHandle () {

    // avoiding repeated calls and conversions in the algorithm below
    //  - p is the reference pointer that we are looking for

    const HANDLE hHeap = GetProcessHeap ();
    const HANDLE hProcess = GetCurrentProcess ();
    const char * p = reinterpret_cast <const char *>
                                      (&GetCurrentModuleHandle);
    DWORD n = 0;
    HINSTANCE hRetVal = NULL;

    // determine number of bytes (n) required to list handles to all modules
    if (EnumProcessModules (hProcess, NULL, 0u, &n)) {

        // allocate space for the handles
        if (HMODULE * hModules = (HMODULE *) HeapAlloc (hHeap, 0u, n)) {
            
            // retrieve the handles
            if (EnumProcessModules (hProcess, hModules, n, &n)) {

                // adjust n to number of the handles
                n /= sizeof (HMODULE);

                for (unsigned int i = 0u; i < n; ++i) {

                    // retrieve also upper boundary of the module
                    MODULEINFO mi;
                    if (GetModuleInformation (hProcess, hModules [i],
                                              &mi, sizeof mi)) {
                        
                        const char * mp = static_cast <char *>
                                                      (mi.lpBaseOfDll);

                        // search is done when p belong to some module image
                        if (p >= mp && p < mp + mi.SizeOfImage) {
                            hRetVal = hModules [i];
                            break;
                        };
                    };
                };
            };
            HeapFree (hHeap, 0u, hModules);
        };
    };

    // hRetVal is NULL if API call failed or p wasn't found (unlikely)
    return hRetVal;
}

And one last note: Putting this function into some common functionality DLL is not exactly bright idea :)

Serving XHTML correctly with simple backward compatibilityConservative variable size memory sharing