为什么在没有预编译头的情况下构建DLL会在使用时导致奇怪的错误?

时间:2012-08-26 20:58:15

标签: c++ c visual-studio dll precompiled-headers

总结:今天我发现当构建没有预编译头文件的DLL时,当你尝试使用它时会出现一个奇怪的错误。

禁用预编译头时,构建DLL会很好。但是,只要附加DLL(编译时或运行时),就会导致错误“无效参数”。两种情况下的实际错误代码都不同。附加编译时会弹出一个错误代码为0xc000000d的对话框,当调用LoadLibrary()时,它会返回一个NULL指针,而GetLastError()会返回0x57。

编辑:

我发现禁用增量链接后问题就消失了。 不知何故,我错过了Visual Studio在运行附加到DLL编译时的客户端时显示的以下错误:

'TestClient.exe': Loaded 'D:\Projects\PchDllTest2\Debug\TestClient.exe', Symbols loaded.
'TestClient.exe': Loaded 'C:\WINDOWS\system32\ntdll.dll', Cannot find or open the PDB file
'TestClient.exe': Loaded 'C:\WINDOWS\system32\kernel32.dll', Cannot find or open the PDB file
'TestClient.exe': Loaded 'D:\Projects\PchDllTest2\Debug\TestDll.dll', Symbols loaded.
SXS: RtlCreateActivationContext() failed 0xc000000d
LDR: LdrpWalkImportDescriptor() failed to probe D:\Projects\PchDllTest2\Debug\TestDll.dll for its manifest, ntstatus 0xc000000d
Debugger:: An unhandled non-continuable exception was thrown during process load
The program '[5292] TestClient.exe: Native' has exited with code -1073741811 (0xc000000d).

根据要求,函数声明:

#ifdef __cplusplus
extern "C" {
#endif

MYTEST_API int MyTestFoo(int a);

#ifdef __cplusplus
}
#endif

有一件事值得注意:当你使用向导创建一个新的DLL(新项目 - > Visual C ++ - > Win32 - > Win32项目)时,向导强制你使用预编译选择DLL作为应用程序类型时的标头。 请参阅ta.speot.is的回答。

我彻底改变了这个问题,因为它首先看起来像我认为有些文件表明PCH是DLL项目所必需的。事实并非如此,它可能是一种奇怪的错误(让我们希望不是这样)或者说我做的事情非常愚蠢......

3 个答案:

答案 0 :(得分:6)

  

为什么构建DLL时需要预编译头?

他们不是。

  

总结:今天我发现,如果不用预编译的头文件构建它,就不可能制作一个(正常运行的)DLL。有谁知道原因是什么?

发现这一点的原因是你误读了一些东西。

你可以制作没有预编译标题的二进制文件。

  

有一点非常值得注意:当您使用向导创建新DLL(新项目 - > Visual C ++ - > Win32 - > Win32项目)时,向导会强制您在选择时使用预编译的标头DLL作为应用程序类型。

也许在Visual C ++ 6中,但我使用Visual Studio的经验表明不然。如果使用向导创建一个空项目,则不会获得预编译的头文件。

Wizard

除此之外,我在谷歌上看到“因为它的清单,ntstatus 0xc000000d”,最终我结束了here。最后一个答案表明您的CRT版本不匹配,如果您让Visual Studio为您创建项目并坚持使用默认值,这将很难做到。

检查您是否在“主机”应用程序和库中链接到相同版本的CRT(例如,两者都是多线程调试)可能会付出代价。

我能想到的唯一另一件事是你将TestDll.dll移动到Debug文件夹而没有附带的TestDll.dll.manifest文件(如果有的话)。

答案 1 :(得分:4)

我发现DLL有一个嵌入式清单资源,只包含一个小端UTF-16字节顺序标记。当Windows DLL加载程序尝试加载这样的DLL时,它会因所描述的错误而崩溃。

我确信这只是一个奇怪的错误:如果我使用Visual Studio或MSBuild构建DLL,它会导致带有伪造清单资源的DLL。如果我在命令行上手动执行MSBuild报告的命令,则DLL包含一个带有UTF-8 BOM的有效清单资源。

  • 如上所述,在禁用PCH的情况下构建DLL会导致清单资源仅包含UTF-16 LE BOM。
  • 如果在启用PCH的情况下构建DLL,则清单资源包含UTF-8 BOM,后跟有效的XML。
  • 如果在禁用PCH且禁用增量链接的情况下构建DLL,则清单资源仅包含XML且根本不包含BOM。

另一种选择是在构建完成后使用资源编辑器删除错误的清单资源,而错误也会消失。

这是非常可重复的,使用向导或者如果你创建一个空项目并自己做所有事情。

答案 2 :(得分:0)

使用“预编译”标头,您可以有效地使用先前编译的代码。如果您稍后介绍了一个错误,“预编译”将不会编译错误,而是使用较旧的无错代码。