在 Windows 上构建和部署 dll:SxS、清单和所有爵士乐

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/110249/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 11:16:09  来源:igfitidea点击:

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

windowsdllmanifestsxs

提问by David Cournapeau

Since VS 2005, I see that it is not possible to simply build a dll against MS runtime and deploy them together (http://www.ddj.com/windows/184406482). I am deeply confused by manifest, SxS and co: MSDN documentation is really poor, with circular references; specially since I am more a Unix guy, I find all those uninformative. My core problem is linking a dll against msvc9 or msvc8: since those runtime are not redistributable, what are the steps to link and deploy such a dll ? In particular, how are the manifest generated (I don't want mt.exe, I want something which is portable across compilers), how are they embedded, used ? What does Side by side assembly mean ?

从 VS 2005 开始,我发现不可能简单地针对 MS 运行时构建 dll 并将它们部署在一起(http://www.ddj.com/windows/184406482)。我对 manifest、SxS 和 co 深感困惑:MSDN 文档真的很差,有循环引用;特别是因为我更像是一个 Unix 人,我发现所有这些都没有提供信息。我的核心问题是将 dll 链接到 msvc9 或 msvc8:由于这些运行时不可再分发,链接和部署此类 dll 的步骤是什么?特别是,清单是如何生成的(我不想要 mt.exe,我想要可以跨编译器移植的东西),它们是如何嵌入和使用的?并排组装是什么意思?

Basically, where can I find any kind of specification instead of MS jargon ?

基本上,我在哪里可以找到任何类型的规范而不是 MS 行话?

Thank you to everyone who answered, this was really helpful,

感谢所有回答的人,这真的很有帮助,

采纳答案by titanae

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

我们在所有应用程序和 DLL 中使用一个简单的包含文件 vcmanifest.h,然后将所有项目设置为嵌入清单文件。

vcmanifest.h

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 */

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

回答by Chris Becke

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

最简单的做法:假设默认安装 VS2005,您将拥有如下路径:

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.

去,获取这个 redist 文件夹中的文件,并将 .manifest 和 msvcr80.dll(至少)放在您的应用程序 .exe 文件夹中。这些文件位于安装的根目录中,应该使您的 exe 和所有链接到它们的 dll 能够完美运行,而无需求助于合并模块、MSI 或任何类型的即时检测,即未安装运行时。

回答by 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.
  1. 清单是一个 xml 文件。虽然 VS 可以并且会在您编译时为您制作一个,但另一种解决方案是生成一个资源文件 (.rc) 并使用 VS 附带的资源编译器 (rc.exe) 将其编译为已编译的资源文件 (.res) . 您需要从工具菜单运行 VS 命令行,这将导致 rc 出现在路径中,并正确设置各种环境变量。然后编译你的资源。生成的 .res 文件可供其他编译器使用。
  2. 确保清单 xml 文件的大小可以被 4 整除。如果需要,在它的中间添加空格以实现这一点。尽量避免在开始的 xml 标签之前或结束的 xml 标签之后有任何字符。我有时会遇到这个问题。如果您不正确地执行第 2 步,预计会出现并排的配置错误。您可以通过在资源编辑器(例如 devenv.exe)中打开 exe 并检查清单资源来检查这是否是您的错误。您还可以通过打开构建的文件来查看正确清单的示例,但请注意,dll 和 exe 在应提供资源的 id 方面存在细微差别。

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

您可能希望在 Vista 上进行测试以确保它正常工作。

回答by Steve Steiner

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.

这是解释 VC++ 的 SxS crt 决定背后的原因的博客条目。它包括解释静态链接 crt 有多糟糕,以及为什么不应该这样做。

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

这是有关如何静态链接 crt文档

回答by ima

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

它们是可再发行的,并且您在 msvs 目录中有可再发行的包。

Build with runtime of your choice, add corresponding package to your installer and don't bother - it will work. The difference is - they are installedin 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.

否则,MSDN 或基本上任何关于 windows c++ 编程的不太老的书。

回答by David Cournapeau

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

谢谢你的回答。对于部署本身,我可以看到 3 个选项,然后:

  • Using .msi merge directive.
  • Using the redistributable VS package and run it before my own installer
  • Copying the redistributable filesalong 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).
  • 使用 .msi 合并指令。
  • 使用可再发行的 VS 包并在我自己的安装程序之前运行它
  • 沿着我自己的应用程序复制可再发行文件。但在这种情况下,我如何在文件系统层次结构中引用它(比如 bar/foo1/foo1.dll 和 bar/foo2/foo2.dll 引用 bar/ 中的 msvcr90.dll)?我的意思是除了明显和丑陋的“在每个依赖于它的 dll 的目录中复制 dll”。

回答by EricJ

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.

如果您打算部署 Microsoft DLLs/.manifest 文件并使用 Java JNI,那么您需要将它们放在 JDK/JRE 的 bin 目录中。

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

如果您在 JBoss 中运行该应用程序,则需要将它们放在 JBoss/bin 目录中。

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

您可以将 JNI DLL 放在适合您的应用程序的位置。

回答by garthy

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.

如果您有要启动的服务或要在 MSI 中的“InstallFinalize”操作之前运行的程序,则不能将 VC++8 SP1/9 CRT 用作 Vista 和 Windows Server 2008 上的合并模块。

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

这是因为 dll 安装在 WinSXS 中的“InstallFinalize”操作中。

But the MSI "ServiceStart" action comes before this.

但是MSI“ServiceStart”操作在此之前。

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

所以使用引导程序“ 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..

或者考虑在安装程序 4.5 中使用安装程序链接。但这意味着你需要一个引导程序来安装 4.5 所以它似乎有点毫无意义..