Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 获取LoadLibrary无法加载DLL的原因_C++_Winapi_Loadlibrary - Fatal编程技术网

C++ 获取LoadLibrary无法加载DLL的原因

C++ 获取LoadLibrary无法加载DLL的原因,c++,winapi,loadlibrary,C++,Winapi,Loadlibrary,在Linux和Mac上,当使用dlopen()加载链接到另一个库的共享库时,如果由于缺少符号而导致链接失败,则可以使用dlerror()获取缺少符号的名称。上面写着 dlopen failed: cannot locate symbol "foo" 在Windows上,使用LoadLibrary()加载缺少符号的DLL时,只能从GetLastError()获取错误代码,对于此类问题,该错误代码始终为127。我如何才能确定缺少哪个符号,或者从LoadLibrary()中找到一条更详细的错误消息,

在Linux和Mac上,当使用
dlopen()
加载链接到另一个库的共享库时,如果由于缺少符号而导致链接失败,则可以使用
dlerror()
获取缺少符号的名称。上面写着

dlopen failed: cannot locate symbol "foo"

在Windows上,使用
LoadLibrary()
加载缺少符号的DLL时,只能从
GetLastError()
获取错误代码,对于此类问题,该错误代码始终为127。我如何才能确定缺少哪个符号,或者从
LoadLibrary()
中找到一条更详细的错误消息,解释函数失败的原因?

尽管Remy Lebeau的回答在技术上是正确的,但在Windows平台上仍然可以确定GetLastError()中缺少的符号。要理解到底缺少了什么,理解术语至关重要

符号:

编译DLL时,其函数由符号引用。 这些符号与函数名称直接相关(符号为 由可见和可读字符串表示),其返回类型,以及 这是参数。实际上,这些符号可以直接通过计算机读取 虽然在大型DLL中很难找到文本编辑器


缺少符号意味着在中找不到函数。如果此错误发生在使用GetProcAddress()之前,则可能由于缺少先决条件而无法加载任意数量的函数。这意味着您尝试加载的库可能还需要第一个无法加载的库。对于未知数量的层,这些依赖级别可能会继续,但GetLastError()可以确定的唯一答案是缺少符号。其中一种方法是使用来确定第一个库所需的缺少的库。一旦所有必需的库都可用并且可以被该库(可以是它自己的蠕虫罐)找到,就可以通过LoadLibrary()加载该库。

我找到了一种使用终端的方法。其他方法可能适用于GUI软件。 一个主要的警告是,这不能在纯C/C++中完成,也不能为最终用户发布。它只针对开发人员,但总比没有好

通过下载Windows SDK并取消选中除调试工具以外的所有选项来安装。 我可能错了,但安装此软件似乎会在Windows内核中安装一个钩子,以允许
LoadLibrary()
将详细信息写入stderr

以管理员身份打开MSYS2 Mingw64终端并运行

'/c/Program Files (x86)/Windows Kits/10/Debuggers/x64/gflags.exe' -i main.exe +sls
这会将以下内容打印到终端,以确认注册表已更改

Current Registry Settings for main.exe executable are: 00000002
    sls - Show Loader Snaps
如果您需要撤消,请使用
-sls
而不是
+sls
,因为我相信Windows中所有名为
main.exe
的程序都会全局更改,而不仅仅是您的文件

然后运行
main.exe
应该会将调试信息打印到stderr,但由于我正在调试
-mwindows
应用程序,它对我不起作用

但出于某种原因,使用MSYS2的gdb运行二进制文件可以将此调试信息打印到stderr。 使用MSYS2安装
mingw-w64-x86_64-gdb
,运行
gdb./main.exe
并键入
run
r
。 搜索类似于以下内容的部分

warning: 1ec8:43a0 @ 764081125 - LdrpNameToOrdinal - WARNING: Procedure "foo" could not be located in DLL at base 0x000000006FC40000.
warning: 1ec8:43a0 @ 764081125 - LdrpReportError - ERROR: Locating export "foo" for DLL "C:\whatever\plugin.dll" failed with status: 0xc0000139.
warning: 1ec8:43a0 @ 764081125 - LdrpGenericExceptionFilter - ERROR: Function LdrpSnapModule raised exception 0xc0000139
    Exception record: .exr 00000000050BE5F0
    Context record: .cxr 00000000050BE100
warning: 1ec8:43a0 @ 764081125 - LdrpProcessWork - ERROR: Unable to load DLL: "C:\whatever\plugin.dll", Parent Module: "(null)", Status: 0xc0000139
warning: 1ec8:43a0 @ 764081171 - LdrpLoadDllInternal - RETURN: Status: 0xc0000139
warning: 1ec8:43a0 @ 764081171 - LdrLoadDll - RETURN: Status: 0xc0000139

太好了!它说
过程“foo”在DLL中找不到,所以我们缺少了符号,就像POSIX/UNIX的
dlopen()

简短回答一样-您不能,因为Windows根本不提供这种详细信息。您知道吗?细粒度加载程序诊断是可用的,但默认情况下不启用。它们只对程序员有用,而不是最终用户。谷歌“WindowsShowLoaderSnaps”来了解如何做到这一点。事实上,任何关于这个错误的半正派Q+A都会记录这个btw,一定要用谷歌搜索更多。@HansPassant你能发布一个链接到“关于这个错误的半正派Q+A”吗?如果它存在的话,我可能已经找到了。你能详细说明一下我如何设置Dependency Walker来说明缺少了哪个符号吗?“Dependency Walker missing symbol”在Google中没有返回任何相关结果,Dependency Walker的手册中也没有提到“symbol”这个词。我更新了我的评论,扩展了符号的概念。符号表示函数,如果这些函数缺少它们所依赖的库,则无法加载这些符号。基本上,您可能缺少加载的库所需的库,以便提供符号表中列出的所有符号。Dependency Walker可帮助您确定您的库需要哪些库。随着Windows 8的引入,Dependency Walker在很大程度上变得毫无用处,至少是静态导入解析。我不知道动态(分析)模式是否会受到如此大的影响。这需要使用调试符号以
gdb
可以处理的格式编译目标EXE/DLL。不幸的是,并非所有针对Windows的第三方C/C++编译器都使用这种格式。加载程序快照诊断不会打印到stderr。转到调试输出(
OutputDebugString
),可以使用Visual Studio之类的调试器或类似的独立工具观察该输出。此功能不是MSYS终端独有的。您可以从任何类型的命令提示符配置gflags。您可以在调试器上观察任何类型的输出,而不仅仅是GDB。