Building and deploying dll on windows: SxS, manifests and all that jazz

假装没事ソ 提交于 2019-12-03 01:53:39

We use a simple include file in all our applications & DLL's, vcmanifest.h, then set all projects to embedded the manifest file.

vcmanifest.h

/*----------------------------------------------------------------------------*/

#if _MSC_VER >= 1400

/*----------------------------------------------------------------------------*/

#pragma message ( "Setting up manifest..." )

/*----------------------------------------------------------------------------*/

#ifndef _CRT_ASSEMBLY_VERSION
#include <crtassem.h>
#endif 

/*----------------------------------------------------------------------------*/

#ifdef WIN64
    #pragma message ( "processorArchitecture=amd64" )
    #define MF_PROCESSORARCHITECTURE "amd64"
#else
    #pragma message ( "processorArchitecture=x86" )
    #define MF_PROCESSORARCHITECTURE "x86"
#endif 

/*----------------------------------------------------------------------------*/

#pragma message ( "Microsoft.Windows.Common-Controls=6.0.0.0") 
#pragma comment ( linker,"/manifestdependency:\"type='win32' " \
                  "name='Microsoft.Windows.Common-Controls' " \
                  "version='6.0.0.0' " \
                  "processorArchitecture='" MF_PROCESSORARCHITECTURE "' " \
                  "publicKeyToken='6595b64144ccf1df'\"" )

/*----------------------------------------------------------------------------*/

#ifdef _DEBUG
    #pragma message ( __LIBRARIES_ASSEMBLY_NAME_PREFIX ".DebugCRT=" _CRT_ASSEMBLY_VERSION ) 
    #pragma comment(linker,"/manifestdependency:\"type='win32' "            \
            "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".DebugCRT' "         \
            "version='" _CRT_ASSEMBLY_VERSION "' "                          \
            "processorArchitecture='" MF_PROCESSORARCHITECTURE "' "         \
            "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
#else
    #pragma message ( __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT=" _CRT_ASSEMBLY_VERSION ) 
    #pragma comment(linker,"/manifestdependency:\"type='win32' "            \
            "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT' "              \
            "version='" _CRT_ASSEMBLY_VERSION "' "                          \
            "processorArchitecture='" MF_PROCESSORARCHITECTURE "' "         \
            "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
#endif

/*----------------------------------------------------------------------------*/

#ifdef _MFC_ASSEMBLY_VERSION
    #ifdef _DEBUG
        #pragma message ( __LIBRARIES_ASSEMBLY_NAME_PREFIX ".MFC=" _CRT_ASSEMBLY_VERSION ) 
        #pragma comment(linker,"/manifestdependency:\"type='win32' "            \
                "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".MFC' "              \
                "version='" _MFC_ASSEMBLY_VERSION "' "                          \
                "processorArchitecture='" MF_PROCESSORARCHITECTURE "' "         \
                "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
    #else
        #pragma message ( __LIBRARIES_ASSEMBLY_NAME_PREFIX ".MFC=" _CRT_ASSEMBLY_VERSION ) 
        #pragma comment(linker,"/manifestdependency:\"type='win32' "            \
                "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".MFC' "              \
                "version='" _MFC_ASSEMBLY_VERSION "' "                          \
                "processorArchitecture='" MF_PROCESSORARCHITECTURE "' "         \
                "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
    #endif
#endif /* _MFC_ASSEMBLY_VERSION */

/*----------------------------------------------------------------------------*/

#endif /* _MSC_VER */

/*----------------------------------------------------------------------------*/

The simplest thing to do: Assuming a default install of VS2005, you will have a path like:

C:\Program Files\Microsoft Visual Studio 8\VC\redist\x86\Microsoft.VC80.CRT

Go, grab the files in this redist folder, and place the .manifest AND the msvcr80.dll (At least) in your applications .exe folder. These files, present in the root of your installation, should enable your exe and all dlls linked against them, to work flawlessly without resorting to merge modules, MSIs or indeed any kind of just-in-time detection that the runtime is not installed.

Here is the blog entry explaining the rational behind the SxS crt decision for VC++. It includes explaining how bad it is to statically link the crt, and why you shouldn't do that.

Here is the documentation on how to statically link the crt.

Brian

Well, I've encountered some of these issues, so perhaps some of my comments will be helpful.

  1. The manifest is an xml file. While VS can and will make one for you when you compile, the other solution is to produce a resource file (.rc) and compile it into a compiled resource file (.res) using the resource compiler (rc.exe) included with VS. You'll want to run the VS commandline from the tools menu, which will cause rc to be in the path, as well as setting various environmental variables correctly. Then compile your resource. The resulting .res file can be used by other compilers.
  2. Make sure your manifest xml file's size is divisible by 4. Add whitespace in the middle of it to achieve this if needed. Try to avoid having any characters before the openning xml tag or after the closing xml tag. I've sometimes had issues with this. If you do step 2 incorrectly, expect to get side by side configuration errors. You can check if that is your mistake by openning the exe in a resource editor (e.g. devenv.exe) and examining the manifest resource. You can also see an example of a correct manifest by just opening a built file, though note that dlls and exes have tiny differences in what id the resource should be given.

You'll probably want to test on Vista to make sure this is working properly.

They are redistributable and you have redistributable packages inside msvs directory.

Build with runtime of your choice, add corresponding package to your installer and don't bother - it will work. The difference is - they are installed in a different place now (but that is also where your app is going to look for libraries).

Otherwise, MSDN or basically any not-too-old book on windows c++ programming.

Thanks for the answer. For deployment per se, I can see 3 options, then:

  • Using .msi merge directive.
  • Using the redistributable VS package and run it before my own installer
  • Copying the redistributable files along my own application. But in this case, how do I refer to it in a filesystem hierarchy (say bar/foo1/foo1.dll and bar/foo2/foo2.dll refer to msvcr90.dll in bar/) ? I mean besides the obvious and ugly "copy the dll in every directory where you have dll which depends on it).

You can't use the VC++8 SP1/9 CRT as a merge module on Vista and windows Server 2008 if you have services you want to start or programs that you want to run before the "InstallFinalize" action in the MSI.

This is because the dlls are installed in WinSXS in the "InstallFinalize" action.

But the MSI "ServiceStart" action comes before this.

So use either a bootstrapper "http://www.davidguyer.us/bmg/publish.htm"

Or look into using the installer chainging in the installer 4.5. But this means you need a bootstrapper to install 4.5 so it seems a bit pointless..

If you intend to deploy the Microsoft DLLs/.manifest files and are using Java JNI then you will need to put them in the bin directory of your JDK/JRE.

If you are running the app in JBoss, then you will need to put them in the JBoss/bin directory.

You can put your JNI DLL where appropriate for your application.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!