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.dll5.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 LdrpDebugFlagsntdll.dll(在xp中-BOOLEAN ShowSnapstrue)到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)时 -一切都清楚了