Thread: HMODULE from current DLL

  1. #1
    Registered User
    Join Date
    Dec 2003
    Posts
    68

    HMODULE from current DLL

    Hi all,

    I have a DLL which has a method (extractRcdata) which extracts a resorurce from itself. This works perfectly when it's run as a standalone binary, but not as a dll.

    Code:
    /**
     * 		@brief	Extracts given resource and returns it as a character array.
     *		@param	hMod			Module to extract resource from.
     *		@param	resourceId		ID of the resource to extract
     *		@return	Character array containing the resource.
     */
    char* extractRCDATA( int resourceId )
    {
    	return extractRCDATA( GetModuleHandle(NULL), resourceId );
    }
    char* extractRCDATA( HMODULE hMod, int resourceId )
    {
    	HRSRC hRsrc;
    	HGLOBAL hResource;
    	char* cResource = new char;
    
    	hRsrc = FindResource(hMod, MAKEINTRESOURCE( resourceId ), RT_RCDATA);
    
    	logError( TEXT("FindResource") , GetLastError(), "Errors.log", false );
    
    	hResource = LoadResource(hMod, hRsrc);
    	logError( TEXT("LoadResource") , GetLastError(), "Errors.log", false );
    
    	cResource = (char*)LockResource(hResource);
    	logError( TEXT("LockResource") , GetLastError(), "Errors.log", false );
    
    	return cResource;
    }
    When run as an exe, GetModuleHandle(NULL) is used for hMod, so the resource gets extracted just fine. When build as a DLL, GetModuleHandle(NULL) now returns the handle for the exe invoking the DLL, not the DLL itself.

    My hope was to use a global variable in my dll wrapper which would be populated from the HINSTANCE of dllMain, like so:

    Code:
    HINSTANCE hinstDLL_;
    
    /**
     *		@brief	DLL Entry point.
     */
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
        switch (fdwReason)
        {
            case DLL_PROCESS_ATTACH:
                // attach to process
                // return FALSE to fail DLL load
                hinstDLL_ = hinstDLL;
                break;
            case DLL_PROCESS_DETACH:
                // detach from process
                break;
            case DLL_THREAD_ATTACH:
                // attach to thread
                break;
            case DLL_THREAD_DETACH:
                // detach from thread
                break;
        }
    
        return TRUE; // successful
    }
    
    myClass myInstance( _hinstDLL );
    hinstDLL_ then gets passed to the constructor of my class, and eventually passed to extractRCDATA(). However _hinstDLL seems to be null?

    I have two questions;

    1: Where am I going wrong with _hinstDLL? - Why is it null?

    2: Is there a better way to go about this? - Using C++, no MFC/ATL.

    Thanks guys, I've extensively goggled this over the weekend and have concluded that I must be missing something - it can't be as complex as I'm making it out to be

    Thanks!

  2. #2
    Registered User
    Join Date
    Apr 2006
    Posts
    137
    I'm not sure if I'm just imagining things but is this right?

    Code:
    HINSTANCE hinstDLL_;
    myClass myInstance( _hinstDLL );
    ★ Inferno provides Programming Tutorials in a variety of languages. Join our Programming Forums. ★

  3. #3
    Registered User
    Join Date
    Dec 2003
    Posts
    68
    Quote Originally Posted by execute View Post
    I'm not sure if I'm just imagining things but is this right?

    Code:
    HINSTANCE hinstDLL_;
    myClass myInstance( _hinstDLL );
    That was the only bit I typed out rather than copying & pasting, and I messed it up. The code actually reads
    Code:
    myClass myInstance( hinstDLL_ );
    If I do the following, it works perfectly. But I'd rather not hardcode the filename.
    Code:
    myClass myInstance( GetModuleHandle("myfile.dll") );

  4. #4
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    GetModuleHandleEx
    Code:
    HMODULE GetCurrentModuleHandle()
    {
        HMODULE hMod = NULL;
        GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
              reinterpret_cast<LPCWSTR>(&GetCurrentModuleHandle),
              &hMod);
         return hMod;
    }

  5. #5
    Registered User
    Join Date
    Dec 2003
    Posts
    68
    Quote Originally Posted by adeyblue View Post
    Thanks adeyblue. Currently my application runs on Win95+ (other than GetLastError which is 2k+), I'm not keen to introduce dependencies on this newer stuff unless I have to.

    Can you think of any other options? I'm still unsure why passing hinstDLL from dllMain isn't working.

  6. #6
    Registered User
    Join Date
    Dec 2003
    Posts
    68
    adeyblue,

    I've given up looking for a decent alternative solution and am trying to use the code, however it errors as follows

    file.cpp|75|error: invalid reinterpret_cast from type `HINSTANCE__*(MyNamespace::MyClass::*)()' to type `const WCHAR*'|
    Code:
    Code:
    HMODULE MyClass::getCurrentModuleHandle()
    {
    	HMODULE hMod = NULL;
    	GetModuleHandleExW(
    		GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
    		reinterpret_cast<LPCWSTR>(&MyNamespace::MyClass::getCurrentModuleHandle),
    		&hMod);
    
    	return hMod;
    }
    Any thoughts? Thanks in advance.

  7. #7
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> myClass myInstance( _hinstDLL );
    myInstance is constructed before your DllMain is called - thus _hinstDLL hasn't been set. Also keep in mind that global constructors run within the context of the real DllMain (within the CRT), which means there are things you can and can't do: Best Practices for Creating DLLs

    gg

  8. #8
    Registered User
    Join Date
    Dec 2003
    Posts
    68
    Thanks codeplug, I understand why that code doesn't work now. I've read through the Microsoft document you referred to (I'd seen it before, but was worth re-reading). The document says the ideal DllMain should just be an empty stub (It's safe to say, mine's empty).

    If myInstance is constructed before DllMain gets called, what's the best way for me to pass hInstance over to my constructor? Can I construct myInstance as part of DLL_PROCESS_ATTACH? Surely then the scope of myInstance would be local, and not accessible by the methods I have which make use of myInstance and are exported for the DLL?

    What's the best way for me to achieve what I'm wanting to do?

    Sorry for what are basic questions, I've worked my way through a few different books but haven't had chance to pickup a WIN32 book yet.

  9. #9
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Maybe something like:

    Code:
    std::auto_ptr<myClass> myInstance;
    
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
        switch (fdwReason)
        {
            case DLL_PROCESS_ATTACH:
                // attach to process
                // return FALSE to fail DLL load
                myInstance = std::auto_ptr<myClass>(new myClass(hinstDLL));
                break;
            case DLL_PROCESS_DETACH:
                // detach from process
                break;
            case DLL_THREAD_ATTACH:
                // attach to thread
                break;
            case DLL_THREAD_DETACH:
                // detach from thread
                break;
        }
    
        return TRUE; // successful
    }
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  10. #10
    Registered User
    Join Date
    Dec 2003
    Posts
    68
    Quote Originally Posted by Sebastiani View Post
    Maybe something like:

    Code:
    std::auto_ptr<myClass> myInstance;
    
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
        switch (fdwReason)
        {
            case DLL_PROCESS_ATTACH:
                // attach to process
                // return FALSE to fail DLL load
                myInstance = std::auto_ptr<myClass>(new myClass(hinstDLL));
                break;
            case DLL_PROCESS_DETACH:
                // detach from process
                break;
            case DLL_THREAD_ATTACH:
                // attach to thread
                break;
            case DLL_THREAD_DETACH:
                // detach from thread
                break;
        }
    
        return TRUE; // successful
    }
    Thanks, just tried that but the same problem ocured. I've even tried using std:fstream in DllMain to write out some info but nothing happens :/

    If I manually do myClass myinstance(getModuleHandle("myDll.dll")) it works as expected, but that obviously means the DLL can never be renamed.

  11. #11
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Make sure you're not using a "stale" copy of the DLL.

    Otherwise, now's a good time to get familiar with your debugger.

    gg

  12. #12
    Registered User
    Join Date
    Dec 2003
    Posts
    68
    Nope, DLL is the latest version.

    My DLL test app is currently c#, which makes debugging the usage a bit of a pain. I'll rewrite my test app in c++ using LoadLibrary rather than DllImport/PInvoke in c# which will hopefully make debugging using gdb a bit easier.

  13. #13
    Registered User
    Join Date
    Dec 2003
    Posts
    68
    Thanks for all your help thus far guys. I've rewritten my test case to use C++ and get the same problem.

    Dllmian is as follows:
    Code:
    std::auto_ptr<myClass> myInstance;
    /**
     *		@brief		DLL Entry point.
     */
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
    	std::ofstream debugLog("debug.log", std::ios::out | std::ios::app );
    	debugLog << "DllMain" << std::endl;
    
        switch (fdwReason)
        {
            case DLL_PROCESS_ATTACH:
                // attach to process
                // return FALSE to fail DLL load
    			myInstance = std::auto_ptr<myClass>(new myClass( GetModuleHandle("myFile.dll") ));
    
                break;
            case DLL_PROCESS_DETACH:
                // detach from process
                break;
            case DLL_THREAD_ATTACH:
                // attach to thread
    			break;
            case DLL_THREAD_DETACH:
                // detach from thread
                break;
        }
    
        return TRUE; // succesful
    }
    debug.log never gets created, so DllMain never gets called. I've been looking online for tips on debugging DLLs with GDB but can't find much.

    Any thoughts as to why DllMain isn't getting called?

  14. #14
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Have you considered using Visual Studio Express (it's free). It has a GUI debugger that should much easier to use as a first-time debugger.

    gg

  15. #15
    Registered User
    Join Date
    Dec 2003
    Posts
    68
    Thanks Codeplug,

    I've actually got a full Visual Studio 2008 license for some work that I do so will just install the c++ component and try and compile with VS2008 and see what I get.

    Will let you know how I get on

    Cheers

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Immediate programming help! Please!
    By xMEGANx in forum C++ Programming
    Replies: 6
    Last Post: 02-20-2008, 12:52 PM
  2. Problem with simple case statements
    By shoobsie in forum C Programming
    Replies: 2
    Last Post: 05-08-2006, 08:39 AM
  3. dll communicating between each other
    By cloudy in forum C++ Programming
    Replies: 5
    Last Post: 06-17-2005, 02:20 AM
  4. compiler build error
    By KristTlove in forum C++ Programming
    Replies: 2
    Last Post: 11-30-2003, 10:16 AM
  5. linked list recursive function spaghetti
    By ... in forum C++ Programming
    Replies: 4
    Last Post: 09-02-2003, 02:53 PM