LoadLibrary()错误代码127

27

我在使用LoadLibrary()时遇到了问题,出现了一个对我来说毫无意义的错误:

   ::SetLastError(0);

   m_hDll = ::LoadLibrary(szName);

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

错误代码是127(“找不到指定的程序”)。在调用LoadLibrary()时,这对我来说毫无意义。我还没有调用GetProcaddress()。

DLL文件(以及应用程序)是使用VS++ 2005 SP1编译的。

可能出了什么问题?


也许库中没有 DllMain 函数?如果是这样,::LoadLibrary 会失败吗? - Janusz Lenar
如果 DllMain 设置 "最后错误" 为 127,并返回 FALSE,那么在从 ::LoadLibrary 返回之前,系统会覆盖 "最后错误" 吗? - Janusz Lenar
9个回答

42

我们一步一步来看:

  1. 这个错误信息意味着找到了dll文件,但缺少一个必须的函数。(Jitter说得没错。)这意味着你已经拥有所需的dll文件,但版本不正确。(Davefiddes也没错,尽管问题可能是任何dll文件,而不仅仅是 Microsoft 运行库。对于主要更新,微软会为其运行库使用不同的名称,所以在这种情况下不是问题。)

  2. 这不合理,因为还没有从正在加载的dll文件中请求任何函数。(Adam说得对。)

  3. 因此,缺少的函数预计应该不在通过 LoadLibrary 命令显式加载的 dll 文件中找到,而是在依赖的 dll 文件中找到,因为第一个 dll 文件需要它。(Zebrabox离答案很近。)

  4. 依赖的 dll 是通过导入库或 .lib 文件在显式加载的库上“静态”链接的 dll,在显式加载的 dll 的链接器步骤中包含。(我打赌你不知道“动态链接库”可以被“静态”链接。现在你知道了。)

  5. 如果你在不同的文件夹中有多个相同版本的 dll,则这也可能是搜索路径问题(如 zebrabox 所建议的)。Dll 路径搜索顺序本身就是一个复杂的主题:请参见 http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx。它取决于操作系统,等等。如果实际可行,最安全的做法是将所有可能出现问题的 dll 文件放在与你的 exe 相同的文件夹中。

  6. 依赖的dll也可以有它们自己的依赖dll,这可能使得解决此问题非常困难。Depends 可能有所帮助,但是如果无法解决,请尝试使用 filemon。在错误消息之前成功读取的最后一个 dll 是错误版本的 dll。


这对我很有帮助,即使我没有使用C++。 - Jann Poppinga

18

微软的gflags工具将精确告诉您哪个依赖项未能加载以及原因。

运行gflags -i your_application.exe +sls。然后在调试器下执行应用程序以捕获加载器跟踪

gflags是调试工具的一部分--您可以检查C:\Program Files (x86)\Windows Kits\10\Debuggers\x64是否已经安装。您可以将该目录添加到您的路径中,或者在cmd.exe中直接从该目录执行gflags。

例如,在运行gflags之后,在::LoadLibrary(_T("foo"))调用上设置断点,并在查找Visual Studio输出窗口中的加载器错误时跨越它,例如。

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

这意味着在加载 foo.dll 的过程中,引用了依赖项 bar.dll,但是 bar.dll 的引用失败了。
依赖项引用失败是因为缺少 ?SetObject@vis_DollarMap@@QEAAXHPEAX@Z 过程 -- 你可以通过 demangle 将其转换为 public: void __cdecl vis_DollarMap::SetObject(int,void * __ptr64) __ptr64
可能是由于依赖项版本不正确 -- 也许你需要重新构建依赖项以使其更新。

之后运行gflags -i your_application.exe -sls以禁用加载器跟踪。


4

错误消息意味着找到了一个合适的DLL,但缺少所需的过程导出。您是否拥有正确版本的DLL?

您可以使用dumpbin.exe检查DLL导出的功能并检查拼写。


2
我还没有调用 GetProcAddress()。哪个导出可能丢失了? - Adam Tegen

4

安装调试工具并运行gflags -i your_application.exe +sls。之后在调试器下执行应用程序以捕获加载器跟踪。


3

我猜测有两种可能:
1. LoadLibrary调用指定DLL的DllMain函数(第一次尝试连接到进程时)。这个可能性不大,但是你可以检查一下是否存在。
2. LoadLibrary将加载指定的DLL及其所有依赖项。因此,如果DLL的某个依赖模块在搜索路径中找不到,就会导致加载失败-您可以使用depends.exe进行检查-可以在这里下载。


请问您能否澄清一下?“搜索路径”中是否包括正在加载的DLL所在的目录,还是只包括应用程序的目录?(或者两者都不包括,或者都包括?) - user97698
我的DLL是在Debug模式下构建的(多线程调试),并且目标机器上没有所需的库(使用depends.exe找到了它)。因此,切换到Release模式(多线程)解决了这个问题。 - Farzan

2

您的应用程序和DLL使用的运行时不匹配吗?

在过去的VS 2005中曾经困扰过我的一个问题是,其中一部分是作为Release版本构建的,而另一部分是作为Debug版本构建的。这些版本引入了不同版本的Microsoft运行时DLL,它们是不兼容的,因为在给定进程中只能加载一个。

我认为您看到错误127的原因是因为您的DLL正在查找已加载的运行时DLL中不存在的函数,因为它是错误的运行时。


0

好的,这是我的解决方案:我们有一个复杂的依赖系统,其中有两个同名的DLL(即server.dll),但位于不同的路径下。

当使用LOAD_WITH_ALTERED_SEARCH_PATH加载client.dll时,似乎Windows无法确定应该使用哪个server.dll进行符号解析(当然,两个server.dll都已成功加载)。

解决方案非常简单:让加载的dll具有唯一的名称,即server-1.dllserver-2.dll


0

在调用LoadLibrary()后,我一直得到相同的错误代码。最终通过依赖项查看器发现,模块(szName)的某些依赖项丢失了。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接