Q: I have an MFC application that runs on my computer, but when I try to run it on another PC I receive an error message that the application failed to initialize and I should re-install it. What should I do?
A: By default, Visual C++ 2005 builds all native C/C++ applications as isolated applications, i.e. self-describing applications that use manifest files to describe their dependencies to VC++ libraries. The problem occurs because your application doesn’t have a manifest, or it has dependencies to assemblies that don’t exist on the target PC, or they have a different version number. Basically you have to do two things to solve the problem:
- Distribute a manifest resource file along with your application
- Deploy the re-distributable assemblies that your application depends upon
Q: What is a manifest resource?
A: A manifest resource is an XML file that describes the dependencies of your application. Such dependencies can include the most current version of the Windows common controls, as well as library assemblies, such as MFC, ATL or CRT assemblies.
Your manifest should have the same name as the application and the extension "manifest" and should specify the version number of your assembly (executable or dynamic library), processor architecture, name of the assembly and platform type; a description of your assembly is also recommended.
<?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <assemblyIdentity version="126.96.36.199" processorArchitecture="X86" name="CompanyName.ProductName" type="win32" /> <description>Description of your application.</description> </assembly>
Q: How do I specify dependencies?
A: You have to add a element to the XML-based manifest. For instance, if you want your application to use the Windows common controls with the XP-like style, add a dependency to the assembly called "Microsoft.Windows.Common-Controls":
<?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <assemblyIdentity version="188.8.131.52" processorArchitecture="X86" name="CompanyName.ProductName" type="win32" /> <description>Description of your application.</description> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="184.108.40.206" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" /> </dependentAssembly> </dependency> </assembly>
Q: I now understand what a manifest resource is, but what are re-distributable assemblies?
A: These are assemblies provided as dynamic link-libraries that you can deploy with your application, because they are required for the application to work. Assemblies are provided in several configurations, Release and Debug, but you can only re-distribute the release configurations (can be found in Visual Studio 8 installation folder, VC\redist).
Visual C++ 2005 supports a new deployment model for Windows client applications based on isolated applications and side-by-side assemblies. Basically, assemblies can be:
- shared (they are globally registered in the system, installed in the Global Assembly Cache – GAC folder in Windows – and available to all applications) or
- side-by-side, described with a manifest, distributed with the application and available only to that application
In Visual C++ 2005, library assemblies (such as MFC, ATL, CRT) have been rebuilt as shared side-by-side assemblies and installed in the native assembly cache, WinSxS folder in Windows. That means they are not globally registered in the system, but are globally available to the applications that specify a dependency with a manifest file.
The target machine where you run your application may already have the required dependencies installed. You can look-up for them in the WinSxS folder. Assemblies are grouped here on categories, each with its own folder. Folder names start with the platform name, followed by Microsoft, category (Windows, VC80, MSXML, Tools), assembly name, a token number, version and additional identifiers. The manifest files for these assemblies are located in the Manifest subfolder of WinSxS and have the same name as the folder of the assembly group they contain information about.
Q: How do I specify dependencies for my application in the manifest file?
A: Suppose your application uses MFC as a shared library, so it has at least a dependency on MFC and one on the C runtime library and C++ runtime library (these two part of the CRT assembly group). In this case your manifest file should look like this:
<?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <assemblyIdentity version="220.127.116.11" processorArchitecture="X86" name="CompanyName.ProductName" type="win32" /> <description>Description of your application.</description> <dependency> <dependentAssembly> <assemblyIdentity type='win32' name='Microsoft.VC80.CRT' version='8.0.50727.42' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /> </dependentAssembly> </dependency> <dependency> <dependentAssembly> <assemblyIdentity type='win32' name='Microsoft.VC80.MFC' version='8.0.50727.42' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /> </dependentAssembly> </dependency> </assembly>
If the target machine already has these assemblies and the version info (process architecture, version, public key token) matches, you don’t have to redistribute anything, because your application will be able to use the assemblies from the native assembly cache (WinSxS). Since you cannot be sure of that you should distribute these assemblies with your application (in the same folder with the application). Windows will first looks-up for assemblies in the current folder and then in WinSxS and GAC, so distributing them in the working folder ensures those assemblies are used.
To distribute the correct assemblies after building the application, go to the Visual Studio 8 installation folder in VC\redist and select your target platform folder, i.e. x86 or amd64. Inside, you will see folders for ATL, MFC, CRT, MFCLOC and OPENMP.
The Microsoft.VC80.MFC folder contains 4 DLLS and a manifest file, called Microsoft.VC80.MFC.manifest. You must copy at least MFC80.DLL (or MFC80U.DLL if you built for UNICODE) to your application working folder. You must make sure that the version number of the MFC assembly specified in this manifest matches the one you put in your application manifest and the one of the DLL itself (this should be implicit, but should check that from the file properties, Alt + Enter > Version).
The Microsoft.VC80.CRT contains 3 DLLs and the manifest. Of these three DLLs you need at least msvcr80.dll (C runtime library) and msvcp80.dll (C++ runtime library). The same caution for the version number must be taken.
With all these taken care of, your application should correctly run on any target machine.