总结:今天我发现当构建没有预编译头文件的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项目所必需的。事实并非如此,它可能是一种奇怪的错误(让我们希望不是这样)或者说我做的事情非常愚蠢......
答案 0 :(得分:6)
为什么构建DLL时需要预编译头?
他们不是。
总结:今天我发现,如果不用预编译的头文件构建它,就不可能制作一个(正常运行的)DLL。有谁知道原因是什么?
发现这一点的原因是你误读了一些东西。
你可以制作没有预编译标题的二进制文件。
有一点非常值得注意:当您使用向导创建新DLL(新项目 - > Visual C ++ - > Win32 - > Win32项目)时,向导会强制您在选择时使用预编译的标头DLL作为应用程序类型。
也许在Visual C ++ 6中,但我使用Visual Studio的经验表明不然。如果使用向导创建一个空项目,则不会获得预编译的头文件。
除此之外,我在谷歌上看到“因为它的清单,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的有效清单资源。
另一种选择是在构建完成后使用资源编辑器删除错误的清单资源,而错误也会消失。
这是非常可重复的,使用向导或者如果你创建一个空项目并自己做所有事情。
答案 2 :(得分:0)
使用“预编译”标头,您可以有效地使用先前编译的代码。如果您稍后介绍了一个错误,“预编译”将不会编译错误,而是使用较旧的无错代码。