manifest 文件

什么是.manifest 文件

[现象]
对这个问题的研究是起源于这么一个现象:当你用VC++2005(或者其
它.NET)写程序后,在自己的计算机上能毫无问题地运行,但是当把此exe文件拷贝到别人电脑上时,便不能运行了,大致的错误提示如下:应用程序配置不
正确,请重新安装程序……或者是MSVCR80D.dll没有找到什么的(我记得不是很清楚,不过大致是这样的)

[分析]
看到这样
的提示,当然不会傻到重装咯。第一反应应该是什么配置有问题、或者是缺少了什么依赖的库文件;于是我就根据以前Windows缺少库文件的经验,把所有库
文件(××.DLL)统统一股脑地复制到当前文件夹下来,满心欢喜以为可以运行了,以运行……@#¥@#%¥……还是挂了。

[探索]
于是开始网上搜索,我Google,我摆渡;渐渐我发现,这一切都和一个叫做***.manifest 类型的文件发生关系,那么到底什么是.manifest 文件呢?他有什么用,以前为什么没有?


来,经过艰苦努力,终于得知,原来这一切都是Windows 的AssemblyManifest搞的鬼。这个东东的作用就是为了解决
以前windows上的“Dll
地狱”问题才产生的新的DLL管理解决方案。大家知道,Dll是动态加载共享库,同一个Dll可能被多个程序所使用,而所谓“Dll地狱”就是当不通程序
依赖的Dll相同,但版本不同时,由于系统不能分辨到底哪个是哪个,所以加载错了Dll版本,然后就挂了。于是盖茨就吸取了教训,搞了一个程序集清单的东
东,每个程序都要有一个清单,这个清单存再和自己应用程序同名的.manifest文件中,里面列出其所需要的所有依赖,这儿所列出的依赖可不是简单地靠
文件明来区分的,而是根据一种叫做“强文件名”的东西区分的,那么什么是强文件明呢?我们来看一下这个.manifest文件便知道了。

<?xml version=‘1.0‘ encoding=‘UTF-8‘standalone=‘yes‘?>
<assembly xmlns=‘urn:schemas-microsoft-com:asm.v1‘manifestVersion=‘1.0‘>
<dependency>
<dependentAssembly>
<assemblyIdentity
type=‘win32‘name=‘Microsoft.VC80.CRT‘
version=‘8.0.50608.0‘processorArchitecture=‘x86‘
publicKeyToken=‘1fc8b3b9a1e18e3b‘/>
</dependentAssembly>
</dependency>
</assembly>

我们发现原来这是一个XML格式的文件,其中<dependency>这一部分指明了其依赖于一个名字叫做Microsoft.VC80.CRT的库。但是我们发现,<assemblyIdentity>属性里面还有其它的东东,分别是
type
系统类型,version版本号,processorArchitecture平台环境,publicKeyToken公匙(一般用来标示一个公司)……
把他们加在一起便成了“强文件名”了,有了这种“强文件名”,我们就可以根据其区分不同的版本、不同的平台……总之,有了这种强文件名,系统中可以有多个
不同版本的相同的库共存而不会发生冲突。

[深入]

恩,那么现在,我们就来具体了解一下这一套机制。
首先是强弱文件名
的问题。正如上面提到的那样,为了区分不同版本或不同厂商生成的相同的程序集,必须用一个AssemblyManifest程序清单来列出我这个程序集的
强文件名--慢着,到这里你可能会问:刚才不是说AssemblyManifest程序清单是列出其所依赖的程序集的强文件名呢,怎么这里变成了当前文件
的强文件明了呢?其实,AssemblyManifest程序清单有两部分功能,上面这个实例之所以标注了其所依赖的文件的强文件名是因为其是客户端的
AssemblyManifest,在服务端有另外一个Manifest 来标注。

<?xml version="1.0" encoding="UTF-8"standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"manifestVersion="1.0">
<noInheritable></noInheritable>
<assemblyIdentity
type="win32"name="Microsoft.VC80.CRT"
version="8.0.50727.42"processorArchitecture="x86"publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
<file name="msvcr80.dll"hash="2a0d797a8c5eac76e54e98db9682e0938c614b45"hashalg="SHA1"><asmv2:hashxmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:Transforms><dsig:TransformAlgorithm="urn:schemas-microsoft-com:HashTransforms.Identity"></dsig:Transform></dsig:Transforms><dsig:DigestMethodAlgorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>phRUExlAeZ8BwmlD8VlO5udAnRE=</dsig:DigestValue></asmv2:hash></file>
<file name="msvcp80.dll"hash="cc4ca55fb6aa6b7bb8577ab4b649ab77e42f8f91"hashalg="SHA1"><asmv2:hashxmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:Transforms><dsig:TransformAlgorithm="urn:schemas-microsoft-com:HashTransforms.Identity"></dsig:Transform></dsig:Transforms><dsig:DigestMethodAlgorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>7AY1JqoUvK3u/6bYWbOagGgAFbc=</dsig:DigestValue></asmv2:hash></file>
<file name="msvcm80.dll"hash="55e8e87bbde00d1d96cc119ccd94e0c02c9a2768"hashalg="SHA1"><asmv2:hashxmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:Transforms><dsig:TransformAlgorithm="urn:schemas-microsoft-com:HashTransforms.Identity"></dsig:Transform></dsig:Transforms><dsig:DigestMethodAlgorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>hWq8zazTsMeKVxWFBa6bnv4hEOw=</dsig:DigestValue></asmv2:hash></file>
</assembly>


个便是从WINDOWS\WinSxS\Manifests目录下取出来的一个manifest文件,再这个文件夹下有一陀子这种XML格式的
manifest文件,其是服务端的程序清单。WinSxs是windowsXP以上版本提供的[blue]非托管并行缓存(side-by-
sidecatche)[/blue]里面安装了各种版本的经过强文件名签名的系统库,而上面这个文件<assemblyIdentity>
正是标注了系统中Microsoft.VC80.CRT的一个版本的强文件名签名,如果其和客户端。.manifest清单里
面<dependentAssembly>所列出的依赖项对上的话,就会被加载。刚才说的side-by-side是指各种不同的版本并行运
行。
上面这个服务端manifest文件中<file>标签具体指明了当前强文件名签名的到底是哪一个文件,其中还有这个文件的Hash签名,以确保文件的完整性。


了,有了这一套机制,就可以非常非常安全地进行库文件关联了,但是、但是貌似还有一个一直困扰我们的问题:这套机制安全是安全了,但是却失去了以前良好的
前后版本兼容性,即如果你的系统库发生了升级,那么服务端的版本号发生了变化,那岂不是所有服务端程序都不能使用了吗?其实,windows还使用一个
policy的策略文件来确认映射关系。

<?xml version="1.0" encoding="UTF-8"standalone="yes"?>
<!-- Copyright ? 1981-2001 Microsoft Corporation-->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"manifestVersion="1.0">

<assemblyIdentity
type="win32-policy"name="policy.8.0.Microsoft.VC80.CRT"
version="8.0.50727.42"processorArchitecture="x86"publicKeyToken="1fc8b3b9a1e18e3b"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32"name="Microsoft.VC80.CRT" processorArchitecture="x86"publicKeyToken="1fc8b3b9a1e18e3b"/>
<bindingRedirectoldVersion="8.0.41204.256-8.0.50608.0"newVersion="8.0.50727.42"/>

</dependentAssembly>
</dependency>

</assembly>


便是在WINDOWS\WinSxS\Policies目录下的一个Policy文件,其中<bindingRedirect>标签便指定了
所有8.0.41204.256-8.0.50608.0变本的客户需求映射到8.0.50727.42这个我现在系统中安装的比较新的版本的库。当然我
们也能对别的字段进行映射,这样便能很好解决系统升级带来的问题。

[应用]
经过以上的讲解,大家对整个依赖查找过程都有了一个整体的认识,那么在实际中问题就好解决了。

我们回到实际问题中,我之前说了,把一个程序编译连接成可执行程序后,在别人的电脑上发现找不到其所依赖的库了,那么怎么办呢?聪明的你自然想到把其所依
赖的库相应的版本拷贝到目标计算机上面,可是……当你在拼命寻找那个可执行文件的assemblymanifests文件的时候,却突然发现找不到了,在
执行目录下面明明只有一个exe文件嘛。是不是没有生成呢?显然不会,原来是资源连接器把那个assemblymanifests文件连接到了可执行文件
里面了;不信,你可以用你的vc++打开一个可执行文件看看,在其资源项里面就有一个叫做RT_MANIFEST的项目。这个里面就是二进制标示的
manifests文件。那么根据这里面提供的要求,将相应版本的依赖文件(一般就是CRT运行库)拷贝到系统目录Windows\WinSxS\,记住
一般会是连带着一个特殊命名的目录一起拷贝到那个文件夹下,比如CRT的运行库就是
WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50608.0_x-ww_b7acac55
有这样一个目录,其标注了此库的版本号以及签名等信息,以防止多个版本重名时不能复制到同一WinSxS目录下。

这样就搞定了么?如果是以
前,那么一切都解决了,系统会在这个目录下面找到这个运行库,可是现在单单这样可不行,系统可是要找到这个运行库的assemblymanifests文
件,并且对比强文件名之后才能加载,所以所以千万别忘了把相应的manifests文件拷贝到\WinSxS\Manifests目录下面。


然,这样在目标的系统文件夹下面打动干戈,自然有些过于暴动了,还好,Windows还为我们提供了一种私有查找方式。这种方式会在前面的位置找不到合适
库的时候在本地文件夹下面找。所以你只要把之前的库以及那个manifests文件一起拷贝到你的应用程序的路径下面,就可以使用啦。

根据MSDN的说明,在本地查找并加载遵循一下规则:


应用程序本地文件夹中查找名为<assemblyName>.manifest的清单文件。在此示例中,加载程序试图在 appl.exe
所在的文件夹中查找Microsoft.VC80.CRT.manifest。如果找到该清单,加载程序将从应用程序文件夹中加载 CRT
DLL。如果未找到CRT DLL,加载将失败。

尝试在 appl.exe
本地文件夹中打开文件夹<assemblyName>,如果存在此文件夹,则从中加载清单文
件<assemblyName>.manifest。如果找到该清单,加载程序将从<assemblyName> 文件夹中加载
CRT DLL。如果未找到CRT DLL,加载将失败。

最后,我想补充的一点是,在你的VC++安装目录下面的
“Microsoft Visual
Studio8\VC\redist”目录下,有着所有的提供发布的已经配备相应.manifest的库文件。所以你想要发布一个程序最简单最安全的做法
(不用担心用户电脑是否包含你所需要的库)就是把这个目录下面的相应的库的文件夹和你的可执行文件放在一起发布。
比如在X86平台下如果你的可执行文件用到了CRT库(废话么),那么就拷贝Microsoft Visual Studio8\VC\redist\x86\Microsoft.VC80.CRT这个文件夹到你的程序所在的目录,一起发布,就万事大吉啦!

时间: 2024-10-11 18:58:51

manifest 文件的相关文章

Manifest文件的最新理解

今天看了Manifest文件内容的相关视频,感觉对知识的理解深刻了一些: 首先,先来说说这个文件的作用,这个文件可以说是聚集了很多个标签,其实对于每个主标签,在将来编译的时候,都会被处理成一个类,而标签里的属性也就成为了该类的成员变量,这些类究竟起到一个什么样的作用呢,主要无外乎标注了一些文件的执行顺序,以及一些权限的赋予,起到一个辅助的作用. 先来说说这个Manifest文件的整体结构,在默认的情况下,最外边标签是为了声明此文件为XML文件,以及XML文件的版本问题,接下来包裹的标签就到正题了

Manifest文件

Manifest文件是简单的文本文件,它告知浏览器缓存的内容(或不缓存的内容) Manifest文件可以分为三个部分: 1.CAHCEMANIFEST-在此标题下列出的文件将在首次下载后进行缓存. CACHE MANIFEST(必需的) /style.css /html5logo.png /active.js 上面的manifest文件列出三个资源,第一个是样式文件,第二个是png格式的html5logo图片,第三个是JavaScript文件.当manifest文件加载后,浏览器会从网站的根目录

Manifest文件简介

每个Android项目都包含一个Manifest文件-Android Manifest.xml,它存储在项目层次中的最底层.Manifest可以定义应用程序及其组件和需求的结构和元数据. 它包含了组成应用程序的每一个Activity.Service.Content Provider和Broadcast Receiver的节点,并使用Intent Filter 和权限来确定这些组件之间以及这些组件和其他应用程序是如何交互的. Manifest文件还可以制定应用程序的元数据(如它的图标.版本号或者主

Android应用程序Manifest文件简介

任何一个Android项目都包含一个AndroidManifest.xml文件,它存储在项目层次中的最底层.Manifest可以定义应用程序及其组件和需求的结构和元数据. 它包含了组成应用程序的每一个Activity.Service.Content Provider和Broadcast Receiver的节点,并且使用Intent Filter和权限来确定这些组件之间以及这些组件和其它应用程序是如何交互的. Manifest文件还可以指定应用程序的元数据(如它的图标.版本号或者主题)以及额外的顶

浅析一个Manifest文件

在Android平台的应用程序开发过程中,Manifest文件举足轻重.每一个应用程序都要有一个Manifest文件,他配置了应用程序在Android系统上的基本信息. 下面对AOSP中的一个manifest文件做个简单解析,以期了解manifest文件的大概结构. 例子取自AOSP4.4 源码中的 frameworks/base/packages/SystemUI/AndroidManifest.xml (有删减) <manifestxmlns:android="http://schem

manifest文件详解

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.exe.phone" <?xml version="1.0" encoding="utf-8"?> <manife

android开发学习笔记(一)-Manifest文件

一:概述 所有的app都要在根目录下AndroidManifest.xml文件,这个文件显示了app告诉android系统的基本信息.在app代码运行之前,android系统从这个文件获取基本信息 功能: 给app的java包起名作为这个app的唯一标识符 声明app中要使用的组件 决定哪些进程持有app组件 确定app需要的用户权限 它声明应用程序必须拥有哪些权限以访问API的被保护部分以及与其它应用程序交互 它声明应用程序必须拥有哪些权限以访问API的被保护部分以及与其它应用程序交互 声明a

Android manifest文件中的标签详细介绍

概要 每一个Android应用都应该包含一个manifest文件,即AndroidManifest.xml.它包含了程序运行的一些必备信息,比如: --为Java应用程序指定一个独一无二的名字. --描述程序所包括的成分,如activities, services, broadcast receivers和content providers等内容. --定义哪一个成分是主要的.比如主线程等. --声明程序正常运行所需要的权限.比如,读写SD卡等. --声明该程序的API Level,低于该API

利用manifest文件对程序目录下的dll进行分类

1 背景 对于大部分的券商和机构投资者,只能通过有交易所交易系统接入资质的券商提供的柜台系统来进行现货交易.相对于期货市场,现货市场的柜台系统千差万别,接入协议有明文字符串.二进制数据和FIX协议等,接入方式有TCP连接.COM组件和dll动态库等.要想开发一个覆盖市面上所有的现货柜台的报盘系统,就必须能同时支持这些柜台的所有接入方式.在开发的过程中遇到的关于动态库版本兼容问题有以下几个: 同一柜台系统提供商发布了2套柜台系统,用于对接这2套系统的开发包是一样的,只是由于版本不同不能通用 不同柜