C++ 单元测试项目 LoadLibrary 失败并出现 Ordinal Not Found 错误
C++ unit-test project LoadLibrary fail with Ordinal Not Found error
我有一个 C++ 单元测试项目,我正在使用 LoadLibraryEx
函数加载我为我的应用程序创建的 dll,但是 LoadLibraryEx
失败并且 return NULL 和之后我调用了 GetLastError
函数,错误是 182。我还注意到在执行 LoadLibraryEx
行后的输出 window 中出现错误 Exception thrown at 0x771718D6 (ntdll.dll) in vstest.executionengine.x86.exe: 0xC0000138: Ordinal Not Found.
请注意,当我 运行 应用程序库加载成功时,加载仅在从单元测试加载时失败。
您的 dll 是从 Comctl32.dll 导入 TaskDialogIndirect
函数。但此函数仅由 版本 6 和更高版本的 Comctl32.dll 导出。但要使用此版本必须是活动的激活上下文,其中存在:
<dependency>
<dependentAssembly>
<assemblyIdentity type='win32'
name='Microsoft.Windows.Common-Controls'
version='6.0.0.0' processorArchitecture='*'
publicKeyToken='6595b64144ccf1df' />
</dependentAssembly>
</dependency>
否则将加载 ComCtl32.dll 的 5.82 version 不导出 TaskDialogIndirect
并且 dll 无法加载。
哪个激活上下文将在 dll 加载时激活?
如果 dll 有自己的清单 (RT_MANIFEST
, ISOLATIONAWARE_MANIFEST_RESOURCE_ID
) - 将根据 dll 清单创建激活上下文,并将在 dll 加载期间使用它。否则它是未定义的。这可以是(更快的)基于 exe 文件或其他文件清单创建的上下文。
根据您的错误 - 我可以说 - 您的 dll 没有 (RT_MANIFEST
, ISOLATIONAWARE_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 时 - 总是使用 comctl32.dll 的版本 6+
怎么研究出这样的错误?
最有效的方式设置DWORD LdrpDebugFlags
从ntdll.dll(在xp中-BOOLEAN ShowSnaps
到true
)到0xFFFFFFBF
在调试器中调用 LoadLibrary
之前。作为结果,链接器在 dll 加载期间打印详细的调试消息 - 您可以准确查看进程失败的位置。此外,在某些困难的情况下,也记录成功的 dll 加载并比较此日志。
the ordinal 345 could not be located in the dynamic link library
comctl32.dll
当我们使用序号代替名称时 - 运行
link.exe /dump /exports "<path>comctl32.lib" > comctl32.log
并查看日志。在日志中我们可以找到:
345 TaskDialogIndirect
现在查看 TaskDialogIndirect
的 msdn 要求部分 - 当我们查看 Comctl32.dll(版本 6)时 -一切都清楚了
我有一个 C++ 单元测试项目,我正在使用 LoadLibraryEx
函数加载我为我的应用程序创建的 dll,但是 LoadLibraryEx
失败并且 return NULL 和之后我调用了 GetLastError
函数,错误是 182。我还注意到在执行 LoadLibraryEx
行后的输出 window 中出现错误 Exception thrown at 0x771718D6 (ntdll.dll) in vstest.executionengine.x86.exe: 0xC0000138: Ordinal Not Found.
请注意,当我 运行 应用程序库加载成功时,加载仅在从单元测试加载时失败。
您的 dll 是从 Comctl32.dll 导入 TaskDialogIndirect
函数。但此函数仅由 版本 6 和更高版本的 Comctl32.dll 导出。但要使用此版本必须是活动的激活上下文,其中存在:
<dependency>
<dependentAssembly>
<assemblyIdentity type='win32'
name='Microsoft.Windows.Common-Controls'
version='6.0.0.0' processorArchitecture='*'
publicKeyToken='6595b64144ccf1df' />
</dependentAssembly>
</dependency>
否则将加载 ComCtl32.dll 的 5.82 version 不导出 TaskDialogIndirect
并且 dll 无法加载。
哪个激活上下文将在 dll 加载时激活?
如果 dll 有自己的清单 (RT_MANIFEST
, ISOLATIONAWARE_MANIFEST_RESOURCE_ID
) - 将根据 dll 清单创建激活上下文,并将在 dll 加载期间使用它。否则它是未定义的。这可以是(更快的)基于 exe 文件或其他文件清单创建的上下文。
根据您的错误 - 我可以说 - 您的 dll 没有 (RT_MANIFEST
, ISOLATIONAWARE_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 时 - 总是使用 comctl32.dll 的版本 6+
怎么研究出这样的错误?
最有效的方式设置DWORD LdrpDebugFlags
从ntdll.dll(在xp中-BOOLEAN ShowSnaps
到true
)到0xFFFFFFBF
在调试器中调用 LoadLibrary
之前。作为结果,链接器在 dll 加载期间打印详细的调试消息 - 您可以准确查看进程失败的位置。此外,在某些困难的情况下,也记录成功的 dll 加载并比较此日志。
the ordinal 345 could not be located in the dynamic link library comctl32.dll
当我们使用序号代替名称时 - 运行
link.exe /dump /exports "<path>comctl32.lib" > comctl32.log
并查看日志。在日志中我们可以找到:
345 TaskDialogIndirect
现在查看 TaskDialogIndirect
的 msdn 要求部分 - 当我们查看 Comctl32.dll(版本 6)时 -一切都清楚了