7

OK, so I have a situation in which I call LoadLibrary on a DLL that I wrote. This call to LoadLibrary returns error #998, or ERROR_NOACCESS "Invalid access to memory location."

The DLL in question uses MFC in one configuration, and not in another; only the MFC configuration has this problem. It used to work, but I have no idea what I changed: I'd actually moved on to the non-MFC version and been tinkering quite a lot with that and I have no idea what I could have done that affected the MFC version.

I don't know a lot about DLLs. The original loading code was actually given to me, and I haven't changed it. Below is that code:

// submodule loading
#ifndef MFC
// Project uses standard windows libraries, define an entry point for the DLL to handle loading/unloading
BOOL WINAPI DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
{
    _MESSAGE("DllMain called.");
    switch(dwReason)
    {
    case DLL_PROCESS_ATTACH:    // dll loaded
        hModule = (HMODULE)hDllHandle;  // store module handle
        _MESSAGE("Attaching Submodule ..."); 
        break;
    case DLL_PROCESS_DETACH:    // dll unloaded
        _MESSAGE("Detaching Submodule ...");      
        break;
    }   
    return true;
}
#else
// Project uses MFC, we define here an instance of CWinApp to make this a 'well-formed' DLL
class CSubmoduleApp : public CWinApp
{
public:
    virtual BOOL InitInstance()
    {// dll loaded
        hModule = m_hInstance;  // store module handle
        _MESSAGE("Attaching Submodule ...");
        return true;
    }
    virtual int ExitInstance()
    {// dll unloaded
       _MESSAGE("Detaching Submodule ...");      
       return CWinApp::ExitInstance();
    }
} gApp;
#endif

Obviously, MFC is defined in the MFC configuration, and not otherwise.

I doubt this is enough information to solve this problem; I realize that. What I'm actually hoping to learn is where to look for problems that might cause this error. I'll be happy to supply any information you need — once I know it's needed.

Thanks for any tips.

Carey Gregory
  • 6,836
  • 2
  • 26
  • 47
KRyan
  • 7,308
  • 2
  • 40
  • 68
  • Have you tried running it in a debugger? That should pinpoint the error for you quickly. – Carey Gregory Oct 07 '11 at 22:58
  • What does `_MESSAGE` do? – David Heffernan Oct 07 '11 at 23:04
  • @CareyGregory: Unfortunately, the code that calls `LoadLibrary` is in another DLL (called by code I don't have access to), so "run in debugger" doesn't work, while at the same time I can't use "Attach to Process" before it's already attempted and given up on my DLL. Not sure if there's a way to get that to work... – KRyan Oct 07 '11 at 23:20
  • @DavidHeffernan: ah, sorry: it prints the enclosed message to the `.log` file associated with the DLL. Standard `format string, ...` arguments. – KRyan Oct 07 '11 at 23:20
  • 1
    You certainly can run this under the debugger. You need to set a break point nice and early in the code and assign a host app. – David Heffernan Oct 07 '11 at 23:23
  • I agree with David that it can be debugged. You can even just run Visual Studio from the command line using the -debugexe option, and then set a breakpoint in the code you posted. The breakpoint will appear to be unreachable when you set it, but once your DLL is loaded it will become reachable. – Carey Gregory Oct 07 '11 at 23:35
  • OK, I have the Debugging section of my project's Properties set to call the program that uses my DLL (the one that calls my other DLL). When I hit "Start Debugging", I get "Debugging information for "the program" cannot be found or does not match. Cannot find or open the PDB file. Do you want to continue debugging?" Even if I hit Yes, however, debugging ends before my breakpoint gets hit... Is this what you meant? – KRyan Oct 08 '11 at 00:01
  • OK, I think I figured out what the problem with the debugger is. This is the deal: the program I'm running is a short-lived loader. It executes another file, injects some code into it, and closes. The injected code is what calls my DLL. If I attach to the loader, I get nowhere. I have to attach to the executable called by the loader, but I have to do so 1. After the loader has called it, and 2. Before the injected code calls my DLL. I can't hit Attach to Process that fast. Is there any like... way to force a break? I've had some luck getting the Just In Time debugger to work... – KRyan Oct 08 '11 at 00:07
  • 1
    Have you tried loading your DLL from a test program instead of from the original host program? If you're lucky, it will exhibit the same error, which would make debugging a lot simpler. – Harry Johnston Oct 08 '11 at 01:06
  • Unfortunately, my code relies on a lot of code from that host program (though its interface API)... – KRyan Oct 08 '11 at 15:55
  • 1
    Maybe, but if the error is occurring as soon as the DLL loads, it won't make any difference, will it? – Harry Johnston Oct 09 '11 at 05:14
  • Oh: have you tried removing the calls to _MESSAGE? Just on the offchance? – Harry Johnston Oct 09 '11 at 05:16
  • @HarryJohnston: The same thing had dawned on me after I said that; unfortunately, I've been away from the code this weekend so I haven't been able to test that. As for `_MESSAGE`, it works perfectly in other parts of the code. Hell, the only reason I know what the error from `LoadLibrary` _is_ is because I have a `_MESSAGE` that outputs it. (both the DLL that is failing and the DLL that loads it to begin with have `_MESSAGE` in them; they are separate copies but identical code). – KRyan Oct 09 '11 at 19:02
  • 2
    DllMain (and hence, presumably, InitInstance) is a special case; code that works perfectly well elsewhere might break when called from DllMain. – Harry Johnston Oct 10 '11 at 01:14
  • @HarryJohnston: OK, I tried taking out `_MESSAGE` as absurd as that is — didn't help. I tried to load the module from a test project that just loads it; it fails citing numerous dependencies ("This application has failed to start because {the executable that the code is normally injected into} was not found. Re-installing the application may fix this problem."), and I don't know how to fix those. I still can't attach a debugger to it. Any other suggestions? – KRyan Oct 10 '11 at 22:20
  • To whom it may concern I was getting this error from incorrectly initializing a global variable in my .dll's .cpp file: const PropertyConnectionChoice::ChoiceDataList s_metaRouteChoiceList( std::begin( s_metaRouteChoiceData ), std::end( *s_metaMovementChoiceData* ) ); – Jonathan Mee Jul 10 '14 at 19:56

1 Answers1

14

OK, this question was answered by a friend of mine (no idea if he has a StackOverflow account; not going to pester him with answering it twice).

The deal is that I had a global object, the class of which had a constructor that called a function that depended upon another global object (ironically enough, the function in question was _MESSAGE, but by the time DllMain or InitInstance gets called, that function works fine). C++ doesn't allow you to specify the order in which globals get initialized, so when this global's constructor got run (when the computer attempted to load the DLL), it caused a memory error by attempting to use another global that hadn't been created yet.

So... that's the answer. A really specific case, but I guess if anyone else finds they're getting 998 errors and need to know what sorts of problems to check, this is something to look for: make sure all your globals are independent!

KRyan
  • 7,308
  • 2
  • 40
  • 68
  • 1
    There are standard techniques for enforcing order of static initialization – David Heffernan Oct 11 '11 at 06:24
  • 1
    OK, I did not know that (and I guess my friend didn't either). Point is, I wasn't using them. I'll look into that. – KRyan Oct 11 '11 at 11:59
  • 3
    @DavidHeffernan a reference would be useful. – atoMerz Dec 01 '13 at 10:15
  • 1
    This worked for me. Had a pointer bug in static initializations in the DLL that only got triggered during a manual LoadLibrary() call, not if linking to it directly via the DLL's import library. – metal Jul 11 '14 at 13:38
  • 1
    @atoMerz see https://stackoverflow.com/a/1463719/2604492 – Paul Dec 18 '20 at 17:36