C++单元测试项目 LoadLibrary 失败,出现"序号未找到"错误

C++ unit-test project LoadLibrary fail with Ordinal Not Found error

本文关键字:quot 错误 单元测试 失败 出现 C++ 项目 LoadLibrary      更新时间:2023-10-16

我有一个C++单元测试项目,我正在使用LoadLibraryEx函数加载我为我的应用程序创建的dll,但LoadLibraryEx失败并返回NULL,之后我调用了GetLastError函数,错误为182。 我还注意到,在执行LoadLibraryEx行后的输出窗口中出现错误Exception thrown at 0x771718D6 (ntdll.dll) in vstest.executionengine.x86.exe: 0xC0000138: Ordinal Not Found.

请注意,当我运行应用程序时,库加载成功,并且仅在从单元测试加载时加载失败。

您的 dll 是从 Comctl32.dll 导入TaskDialogIndirect函数,但此函数仅由Comctl32.dll版本 6及更高版本导出。 但要使用此版本,必须处于活动激活上下文,其中存在:

<dependency>
<dependentAssembly>
<assemblyIdentity type='win32' 
name='Microsoft.Windows.Common-Controls' 
version='6.0.0.0' processorArchitecture='*'   
publicKeyToken='6595b64144ccf1df' />
</dependentAssembly>
</dependency>

否则将加载ComCtl325.82 版本.dll其中不导出TaskDialogIndirect并且 dll 无法加载。

哪个激活上下文将在 DLL 加载时处于活动状态?

如果 DLL 有自己的清单 (RT_MANIFESTISOLATIONAWARE_MANIFEST_RESOURCE_ID) - 激活上下文将基于 DLL 清单创建,并将在 DLL 加载期间使用。 否则未定义。 这可以是基于 exe 文件中的清单或其他文件的清单创建的(所有上下文中更快的)。

根据您的错误 - 我可以说 - 您的 DLL 没有 (RT_MANIFESTISOLATIONAWARE_MANIFEST_RESOURCE_ID) 清单资源。 这是错误。 加载 DLL 的应用程序可能有自己的清单,其中声明了公共控件的版本 6,因此 DLL 加载正常。 但是单元测试 EXE 根本没有清单,或者清单中没有版本 6。 结果加载了旧版本的 Comctl32.dll并且此处未导出TaskDialogIndirect.

无论如何,DLL 不能依赖于外部上下文 - 它加载的位置。 为此,它必须有自己的清单。

因此,请为 DLL 创建清单,该清单具有<dependency>-<dependentAssembly>用于<assemblyIdentity type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' />,并将此清单作为资源包含在内:

ISOLATIONAWARE_MANIFEST_RESOURCE_ID RT_MANIFEST "manifest file name"

有了这个,当你DLL将被加载时 - 总是使用Comctl62.dll的版本6+


怎么会这样研究错误?

最有效的方法是在调试器中调用LoadLibrary之前将DWORD LdrpDebugFlagsNTDLL.dll(在 XP 中 -BOOLEAN ShowSnapstrue中)设置为准确0xFFFFFFBF。 结果链接器在DLL加载期间打印详细的调试消息 - 并且您准确地查看进程失败的位置。 此外,在某些困难的情况下,也做好日志成功DLL加载并比较此日志。

序号345无法在动态链接库中找到康克特尔32.dll

当我们有序号代替名称时 - 运行

link.exe /dump /exports "<path>comctl32.lib" > comctl32.log

在日志中,我们可以找到:

345    TaskDialogIndirect

现在查看 msdn 要求部分以获取TaskDialogIndirect- 当我们查看Comctl32.dll(版本 6)时 - 一切都变得清晰起来