22
votes

I'm having trouble with LoadLibrary() and getting an error that doesn't make sense to me:

   ::SetLastError(0);

   m_hDll = ::LoadLibrary(szName);

   if (m_hDll == NULL) // Failure to load the DLL.
   {
      DWORD err = GetLastError();
   }

The error is 127 ("The specified procedure could not be found.") That doesn't make any sense to me on a call to LoadLibrary(). I haven't called GetProcaddress() yet.

The DLL (and the application) are both compiled with VS++ 2005 SP1.

What could be going wrong?

9
Maybe there's no DllMain in the library? Should it fail ::LoadLibrary?Janusz Lenar
If DllMain sets 'last error' as 127 and then returns FALSE, will 'last error' be overwritten by the system before returning from ::LoadLibrary?Janusz Lenar

9 Answers

34
votes

Let's take this step by step:

  1. The error message means that the dll was found but a required function is missing. (Jitter is right.) This implies that you have the dll you need, but not the right version. (Davefiddes is right, although the problem can be any dll, not just the Microsoft runtime library. And, at least for major updates, Microsoft gives its runtime libraries different names, so in that case it wouldn't be an issue.)

  2. This doesn't make sense, because no function has been requested from the dll being loaded. (Adam is right.)

  3. Therefore, the missing function was expected to be found not in the dll which is being explicitly loaded by the LoadLibrary command, but in a dependent dll which is being implicitly loaded at the same time, because the first dll requires it. (Zebrabox was close.)

  4. A dependent dll is a dll that is "statically" linked to the library being explicitly loaded, via an import library, or .lib file, included on the linker step of the explicitly loaded dll. (I bet you didn't know that a "dynamic link library" could be "statically linked." Well, now you do.)

  5. If you have multiple versions of the same dll in different folders, then this could also be a search path problem (as zebrabox suggests). Dll path search order is a complicated subject in itself: see http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx . It depends on operating system, among other things. The safest bet, where practical, is to put all the potential problem dlls in the same folder as your exe.

  6. Dependent dlls can also have their own dependent dlls, which can make this problem very difficult to resolve. Depends might help, but if it doesn't, try filemon. The last dll that's successfully read before your error message is the one that's the wrong version.

13
votes

The Microsoft gflags tool will always tell you exactly what dependency is failing to load and why.

Run gflags -i your_application.exe +sls. After that execute the application under the debugger to capture the loader traces.

gflags is part of Debugging Tools -- you might check in C:\Program Files (x86)\Windows Kits\10\Debuggers\x64 to see if you already have it. You can add that directory to your path, or just execute gflags from that directory in cmd.exe.

For example, after running gflags, put a break point on the ::LoadLibrary(_T("foo")) call and step over it while looking for loader errors in your Visual Studio output window, e.g.

4b00:396c @ 479194074 - LdrpSnapThunk - ERROR: Procedure "?SetObject@vis_DollarMap@@QEAAXHPEAX@Z" could not be located in DLL "bar.dll"
First-chance exception at 0x0000000077307EF8 (ntdll.dll) in your_application.exe: 0xC0000139: Entry Point Not Found.
4b00:396c @ 479194074 - LdrpGenericExceptionFilter - ERROR: Function LdrpSnapIAT raised exception 0xc0000139
    Exception record: .exr 0000000000129070
    Context record: .cxr 0000000000128B80
4b00:396c @ 479194074 - LdrpHandleOneOldFormatImportDescriptor - ERROR: Snapping the imports from DLL "C:\test\64Debug\foo.DLL" to DLL "C:\test\64Debug\bar.dll" failed with status 0xc0000139

This means that during the load of foo.dll, the dependency bar.dll was imported, and the bar.dll import failed.

The dependency import failed because the procedure ?SetObject@vis_DollarMap@@QEAAXHPEAX@Z was missing -- you can demangle that to public: void __cdecl vis_DollarMap::SetObject(int,void * __ptr64) __ptr64.

You probably have the wrong version of a dependency -- maybe you need to rebuild the dependency to get it up to date.


Run gflags -i your_application.exe -sls afterwards to disable the loader traces.

4
votes

The error messag means that there is an appropriate DLL found but a required procedure export is missing. Do you have the right version of the DLL?

You can use dumpbin.exe to check what functions your DLL exports and check the spelling.

4
votes

Install Debugging tools and run the gflags -i your_application.exe +sls. After that execute application under the debugger to capture the loader traces.

2
votes

Do you have a mismatch between the runtimes used for your app and the DLL?

A problem that's bitten me with VS 2005 in the past is that one part is built as a Release build and the other as a Debug build. These pull in different versions of the Microsoft runtime DLLs which are incompatible as you can only have one loaded in a given process.

I think the reason that you see Error 127 is because your DLL is looking for a function in the loaded runtime DLL which isn't there because it's the wrong runtime.

2
votes

Two guesses from me
1. LoadLibrary calls the DllMain of the specified DLL (the first time you try and attach to your process). Long shot but is it there?
2. LoadLibrary will load the specified DLL and all it's dependencies. So if a dependant module of the DLL can't be located in the search path that will cause the load to fail - you can use depends.exe to check - available here

0
votes

I was getting the same error code after calling LoadLibrary(). Finally found through dependency walker that some dependencies of module (szName) were missing.

0
votes

I would suggest using Dependency Walker to find out which method is missing or what DLLs are required or missing.

0
votes

Ok, here is my solution: we had a complex dependency system and among them there were two DLLs with the same name (i.e. server.dll), but located on different paths.

When client.dll was loaded with LOAD_WITH_ALTERED_SEARCH_PATH, it seems, that windows wasn't able to figure out which one of server.dll should be used in symbols resolution (both server.dll were successfully loaded, of course).

The solution was quite easy: let the loaded dlls have unique names, i.e server-1.dll and server-2.dll.