我有一个C ++单元测试项目,我正在使用LoadLibraryEx
函数来加载我为我的应用程序创建的dll,但LoadLibraryEx
失败并返回NULL,之后我调用{{1函数和错误是182.我还注意到在执行GetLastError
行后的输出窗口中出现错误LoadLibraryEx
请注意,当我运行应用程序时,库成功加载,加载仅在从单元测试加载时失败。
答案 0 :(得分:1)
你的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"
有了这个,当你将加载时 - 将始终使用 comctl32.dll 的版本6+
这样的研究错误怎么样?
在调用{之前“ ntdll.dll (在xp - DWORD LdrpDebugFlags
到BOOLEAN ShowSnaps
)到true
之间设置0xFFFFFFBF
的最有效方法{1}}在调试器中。因此,链接器在dll加载期间打印详细的调试消息 - 您可以准确查看进程失败的位置。另外,在某些困难的情况下,还要记录成功dll加载并比较这些日志。
序号 345 无法在动态链接库中找到 COMCTL32.DLL
当我们有序号而不是名字 - 运行
LoadLibrary
并查看日志。在日志中我们可以找到:
link.exe /dump /exports "<path>comctl32.lib" > comctl32.log
现在查看TaskDialogIndirect
的msdn要求部分 - 当我们查看 Comctl32.dll (版本6 )时 - 一切都变得清晰了