Thursday, March 23, 2006

unmanaged Visual C++ for Visual Studio 2005 causes (soluble) dll loading problems

Hi All,

This message is about where dlls go when they are part of “isolated assemblies.” Everyday C++ users may run into this when they move their code from a development machine to a node on a compute cluster.

1. When you copy an executable to the cluster, it now needs not only dlls but also manifest files copied with it, or we have to install them on the cluster for the users.

2. There is a common occurrence where a failure in the linker can cause an executable to fail ever to load. There is a quick fix for this.

Part I:
When compiling unmanaged visual C++ applications in VS2005, you have to pay attention to how you distribute the dlls. Normally, you just put Dlls beside the exe. That isn’t working for some good reasons. I’m going to give you an outline here of where the bodies lie, trying to show you pertinent directories, tools, and project settings.

Google keywords: Isolated applications, side-by-side assemblies, winsxs
Web pages:
About isolated apps and assemblies
http://msdn2.microsoft.com/en-us/library/ms235342(en-US,VS.80).aspx
blog with details on how to do installation with isolated apps
http://blogs.msdn.com/nikolad/
Windows Installer XML – use xml file to create an msi.
http://sourceforge.net/projects/wix

There is a section in VS under Linker->Manifests that says you can
- embed manifest – yes/no
- allow isolation – yes/no

Visual Studio now distributes the CRT and debug CRT and versions of ATL and MFC libraries in VS
C:\Program Files\Microsoft Visual Studio 8\VC\redist\x86
C:\Program Files\Microsoft Visual Studio 8\VC\redist\Debug_NonRedist\x86

Here you find the directory Microsoft.VC80.DebugCRT\ with the files
- Microsoft.VC80.DebugCRT.manifest
- msvcm80d.dll
- msvcp80d.dll
- msvcr80d.dll

Executables, under various conditions, are supposed to be able to find dlls in various directories if you put the manifest with them
- C:\Windows\WinSXS
- <appdirectory>
- <appdirectory>\<appname>.exe.local
- <appdirectory>\<manifestname>


Part II: The Common Deal-breaker: Oldnames.lib

When you compile code which links to libraries using older, deprecated methods, the linker finds those methods in an implicit library called Oldnames.lib. Because of a flaw in the linker, any time it pulls in oldnames.lib, it will also pull in a copy of the wrong CRT. That is, if you link against the debug CRT, it will pull in the release CRT, and vice versa. This wouldn’t normally cause the executable to fail to run, except that the linker includes only the correct assembly. For instance, when linking against the debug CRT, the following manifest is included in the executable, even though the linker mistakenly linked to the runtime CRT, as well.


<assembly xmlns="'urn:schemas-microsoft-com:asm.v1'" manifestversion="'1.0'">
<dependency>
<dependentassembly>
<assemblyidentity type="'win32'" name="'Microsoft.VC80.DebugCRT'" version="'8.0.50608.0'" processorarchitecture="'x86'" publickeytoken="'1fc8b3b9a1e18e3b'">
</dependentassembly>
</dependency>
</assembly>

The solution is to tell the linker to ignore the other CRT. In other words, if you link with msvcrtd.lib, you have to explicitly tell the linker to ignore msvcrt.lib, and vice versa. That makes the linker think longer about where it can find the references it needs, and it comes back around to the correct library.

Mind that Microsoft would not consider this problem a linker flaw because I have only seen it happen when linking to libraries older than my current version of Visual Studio, and linking Visual Studio 2005 projects to those of Visual Studio 2003 or Visual Studio 6 is not supported. This is likely confounded with the fact that I am linking release and debug always to a release library, which is not supported. Does any company really distribute their development libraries as MT, MD, MTd and MDd? I've only seen VRCO do this.

At this point, I’ve also created an installer for the C runtimes, as described in the blog link above, so that’s what is loading. I just run vccrt.msi, then my application runs. I used this tool called WIX to install it. It’s a bit of open source from Microsoft. The project doesn't appear to be under development any longer, but it's still working for now.

Drew

No comments: