Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why building a DLL without precompiled headers causes a weird error when used?

In summary: Today I discovered that when a DLL is built without precompiled headers, a strange error shows when you try to use it.

Building the DLL goes fine when precompiled headers are disabled. However as soon as the DLL is attached (either compile-time or run-time) it results in the error "Invalid parameter". The actual error codes are different for both cases. When attaching compile-time a dialog pops up with error code 0xc000000d, when calling LoadLibrary() it returns a NULL pointer and GetLastError() returns 0x57.

EDITs:

I discovered that the problem goes away when incremental linking is disabled. Somehow I missed the following error showed by Visual Studio when running a client that attaches to the DLL compile-time:

'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).

As requested, the function declaration:

#ifdef __cplusplus
extern "C" {
#endif

MYTEST_API int MyTestFoo(int a);

#ifdef __cplusplus
}
#endif

There's one thing that is remarkable about this: When you create a new DLL using a wizard (New project -> Visual C++ -> Win32 -> Win32 Project), the wizard forces you to use precompiled headers when selecting DLL as application type. See answer from ta.speot.is.

I drastically changed the question, as it looked first like I thought that it was somehow documented that PCH is required for DLL projects. This is not the case, it's probably a weird kind of bug (let's hope it's not) or probably I'm doing something very stupid...

like image 463
Bart Avatar asked Aug 26 '12 20:08

Bart


People also ask

Do I need precompiled headers?

Usage of precompiled headers may significantly reduce compilation time, especially when applied to large header files, header files that include many other header files, or header files that are included in many translation units.

What are precompiled headers used for?

Precompiled headers (PCH) are a performance feature supported by some compilers to compile a stable body of code, and store the compiled state of the code in a binary file. During subsequent compilations, the compiler will load the stored state, and continue compiling the specified file.


2 Answers

Why are precompiled headers required when building a DLL?

They're not.

In summary: Today I discovered that it's not possible to make a (functioning) DLL without building it with precompiled headers. Does anyone know what the reason is for this?

The reason for discovering this is that you misread something.

You can make binaries without precompiled headers just fine.

There's one thing that is remarkable about this: When you create a new DLL using a wizard (New project -> Visual C++ -> Win32 -> Win32 Project), the wizard forces you to use precompiled headers when selecting DLL as application type.

Perhaps in Visual C++ 6, but my experience with Visual Studio suggests otherwise. If you make an empty project with the wizard you do not get a precompiled header.

Wizard

All that aside, I had a look on Google for "for its manifest, ntstatus 0xc000000d" and ultimately I wound up here. The last answer suggests that your CRT versions are mismatched, which would be very hard to do if you're letting Visual Studio create the projects for you and sticking with the defaults.

It might pay to check that you are linking to the same version of the CRT in your "host" application and library (e.g. both are multi-threaded debug).

The only other thing I can think of is that you're moving TestDll.dll into the Debug folder without its accompanying TestDll.dll.manifest file (if it has one).

like image 81
ta.speot.is Avatar answered Nov 14 '22 21:11

ta.speot.is


I found out that the DLL has an embedded manifest resource containing only a little-endian UTF-16 byte order mark. The windows DLL loader crashes with the described error when it tries to load such a DLL.

I'm convinced that this just is a weird bug: If I build the DLL using Visual Studio or MSBuild, it results in an DLL with the bogus manifest resource. If I execute the commands reported by MSBuild manually on the command line, the DLL contains a valid manifest resource with a UTF-8 BOM.

  • As described building a DLL with PCH disabled results in a manifest resource containing only an UTF-16 LE BOM.
  • If a DLL is built with PCH enabled, the manifest resource contains a UTF-8 BOM followed by valid XML.
  • If a DLL is built with PCH disabled AND incremental linking disabled, the manifest resource contains only XML and no BOM at all.

Another option is to remove the faulty manifest resource using a resource editor after the build has been completed, than the error also disappears.

This is very reproducable, using wizard or if you create an empty project and do everything yourself.

like image 44
Bart Avatar answered Nov 14 '22 22:11

Bart