关于微软的Manifest的那些事
什么是Manifest?
在Windows中,manifest(清单)是一个XML文件,根据清单类型不同,可以分为四种:
Manifest | 描述 |
---|---|
程序集清单 | 描述名称、版本、资源、依赖的side-by-side程序集 |
应用程序清单 | 描述共享的side-by-side的程序集版本和名称,可能包含私有side-by-side的程序集元数据 |
应用程序配置文件 | 重定向每一个应用程序依赖的程序集版本 |
发布者配置文件 | 使用发布者配置重定向一整块的程序集版本 |
程序集清单
要想理解程序集清单,首先要了解什么是程序集?
百度百科上说的程序集的概念是:
经由编译器编译得到的,供CLR进一步编译执行的那个中间产物,在WINDOWS系统中,它一般表现为·dll或者是·exe的格式,但是要注意,它们跟普通意义上的WIN32可执行程序是完全不同的东西,程序集必须依靠CLR才能顺利执行。
但CLR是.net平台才有的,那么C++编译出来的程序是程序集吗?
根据微软官方的解释:
An assembly is a fundamental unit for naming, binding, versioning, deploying, or configuring a block of programming code.
程序集是用于命名、绑定、版本控制、部署或配置程序代码块的基本单元
Applications with common functionality may run shared blocks of programming code which are referred to as modules or code assemblies.
应用程序具有通用部分的功能并且可以共享运行的程序代码块被称为模块或代码集
These code assemblies may be placed in DLLs or COM assemblies.
这些代码集通常集成在dll或com集中
The infrastructure for the safe sharing of assemblies is referred to as side-by-side assembly sharing.
用于安全共享程序集的基础结构成为并行(side-by-side)程序集共享
从上面的话,我们可以把程序集理解成组件,主要以dll、com形式表现出来。
最后一句话,则提出来并行(side-by-side)程序集的概念。
Side-by-side assemblies are code assemblies described by manifests and authored so that multiple versions may run at the same time without conflicting with each other.
并行程序集是带有清单描述的程序集,以便多个版本同时运行而不会互相冲突
我们现在电脑通常安装了几个Visual C++运行库,有2008、2010、2005,它们就是并行程序集,当电脑的程序运行时需要2008的组件就会调用2008的。
程序集又可以分为共享和私有两种,我们画个图来理解这个概念
我们可以看一下程序集清单的组成结构:
元素 | 属性 | 是否必须 | 说明 |
---|---|---|---|
assembly | yes | xml的根节点 | |
manifestVersion | 固定为:1.0 | ||
noInheritable | No | 多线程不继承清单,如果没有则默认继承。会被应用清单覆盖 | |
assemblyIdentity | Yes | 程序集唯一标识 | |
type | Yes | 该值必须是win32 | |
name | Yes | 程序集的唯一名称 | |
language | No | 标识程序集的语言 | |
processorArchitecture | No | 处理器架构,x86或ia64 | |
version | Yes | 指定程序集版本,格式如:mmmmm.nnnnn.ooooo.ppppp,数值范围0-65535(含) | |
publicKeyToken | No | 16个字符的十六进制字符串,表示对程序集签名的公共密钥sha-1哈希的最后8个字节,对于共享的并行程序集是必须的 | |
dependency | No | 包含至少一个dependentAssembly子元素 | |
dependentAssembly | No | 第一个子元素必须为assemblyIdentity,描述该程序集依赖哪些程序集 | |
file | No | 该程序集使用的文件 | |
name | Yes | 文件名称,例如,Conctl32.dll | |
hashalg | No | 文件的hash算法,该值为SHA1 | |
hash | No | 文件的hash值 | |
comClass | No | COM组件 | |
description | No | class名称 | |
clsid | Yes | 唯一标识类的GUID | |
threadingModel | No | 进程内COM类使用的线程模型 | |
tlbid | No | 此COM组件的GUID | |
progid | No | 此COM组件的ProgID | |
miscStatus | No | 和COM组件有关,具体可以参考OLEMISC枚举 | |
miscStatusIcon | No | 和COM组件有关,具体可以参考OLEMISC枚举 | |
miscStatusContent | No | 和COM组件有关,具体可以参考OLEMISC枚举 | |
miscStatusDocPrint | No | 和COM组件有关,具体可以参考OLEMISC枚举 | |
miscStatusThumbnail | No | 和COM组件有关,具体可以参考OLEMISC枚举 | |
typelib | No | 类型库 | |
tlbid | Yes | 类型库的唯一ID | |
version | Yes | 版本 | |
helpdir | Yes | 帮助目录 | |
resourceid | No | 资源ID | |
flags | No | 标志 | |
comInterfaceExternalProxyStub | No | com接口扩展代理存根 | |
iid | Yes | 代理接口的IID | |
baseInterface | No | 基类的IID | |
numMethods | No | 接口实现的方法数 | |
name | No | 接口名称 | |
tlbid | No | 类型库 | |
proxyStubClsid32 | No | 将IID映射到32位代理DLL中的CLISID | |
comInterfaceProxyStub | No | com接口代理存根 | |
iid | Yes | 代理接口的IID | |
name | Yes | 接口名称 | |
tlbid | No | 类型库 | |
baseInterface | No | 基类接口IID | |
numMethods | No | 接口实现的方法数 | |
proxyStubClsid32 | No | 代理存根32位CLISID | |
threadingModel | No | 进程内COM使用的线程模型 | |
windowClass | No | 版本化的Windows类 | |
versioned | No | 版本,默认yes |
清单示例:
1 |
|
共享程序集
我们先从共享讨论,分别从共享的并行程序集和共享的非并行程序集
在xp以前都是使用的是非并行的程序集,在同一台电脑上是这样的:
后来使用并行程序集,在同一台电脑上就可以这样:
这种方式解决了不同应用程序使用的共享dll版本不一样的问题
共享的并行程序集
共享的并行程序集安装在C:\Windows\winsxs中,程序集清单位置是C:\Windows\winsxs\Manifests。
我们随便找了一个文件,文件名为:
x86_microsoft.windows.gdiplus_6595b64144ccf1df_1.0.7601.24542_none_6cb5a8e3070802c6.manifest
内容为:
1 |
|
共享的非并行程序集
不讨论
私有程序集
私有程序集可以分为带清单的程序集(并行程序集)和不带清单的程序集(非并行程序集)。
私有的并行程序集
带清单的私有程序集很少见,且绝大多数都只是规定了运行等级。
我在AcroRd32.dll里面找到了一个,内容如下:
1 |
|
私有的非并行程序集
暂不讨论
程序集的搜索顺序
具体可以参照微软文档
程序集清单的嵌入和非嵌入
程序集清单嵌入就没有什么好讲的,用ResourceHacker就可以查看嵌入的清单。
微软文档上建议都使用嵌入式清单,但是有一种情况,你使用的是第三方的com组件,它并没有清单文件,你可以使用非内嵌的方式。
文档上提:如果采取非嵌入式清单,则程序集的名称与清单的名称不能和dll名称一样,非嵌入式清单的搜索顺序参考程序集搜索顺序
应用清单
应用清单就会非常少了,下面界面组成应用清单的xml结构:
元素 | 属性 | 必须 | 说明 |
---|---|---|---|
assembly | Yes | xml的根节点 | |
manifestVersion | Yes | 固定为:1.0 | |
noInherit | No | 多线程不继承清单,如果没有则默认继承。一般默认继承,和激活上下文有关。 | |
assemblyIdentity | Yes | 唯一标识应用程序 | |
type | Yes | 指定应用程序或程序集类型,该值必须为win32 | |
name | Yes | 唯一命名 | |
language | No | 标识应用程序或程序集的语言 | |
processorArchitecture | No | 处理器架构,x86、amd64、arm、arm64 | |
version | Yes | 指定应用程序或程序集的版本,使用四部分版本格式。 | |
publicKeyToken | No | 对应用程序集签名的公钥密钥的SHA-1的最后8个字节,所有共享的并行组件均必须 | |
compatibility | No | 兼容性节点 | |
application | No | 应用节点 | |
supportedOS | Id | No | 应用下面的支持操作系统,详细请参考supportedOS |
maxversiontested | Id | No | 支持windows的最高版本 |
dependency | No | 依赖节点 | |
dependentAssembly | No | 依赖的程序集节点,子节点为assemblyIdentity | |
file | No | 指定应用程序专用的文件,如Comctl32.dll。应用程序会在启动的时候就加载进来 | |
name | No | 文件名 | |
hashalg | No | 文件的hash算法 | |
hash | No | 文件的hash值 | |
activeCodePage | No | 强制进程使用UTF-8作为进程代码页 | |
autoElevate | No | 指定是否启用自动提升权限,TRUE代表已启用 | |
disableTheming | No | 是否禁用UI使用主题 | |
disableWindowFiltering | No | 是否禁用窗口过滤 | |
dpiAware | No | 是否支持dpi,有几个选项。详看dpiAware | |
dpiAwareness | No | 详看dpiAware | |
gdiScaling | No | 是否启用GDI缩放,最低位Windows 10版本1703,Windows7就别想了 | |
highResolutionScrollingAware | No | 是否启用高分辨率滚动感知 | |
longPathAware | No | 启用长度超过MAX_PATH的长路径,Windows 10 1607版本以上才支持 | |
printerDriverIsolation | No | 是否启用打印机驱动程序隔离 | |
ultraHighResolutionScrollingAware | No | 是否启用超高分辨率滚动感知 | |
msix | No | 看文档 | |
heapType | No | 覆盖Win32堆的默认实现,通常可减少内存使用,Windows10 2004版以上支持(鸡肋) |
结尾
理论终于讲完了,至于应用程序配置文件和发布者配置文件,我目前用不上,不看了,看的头大。接下来另起一篇,讲讲怎么利用清单调用免注册COM组件的。下一篇链接地址:使用清单Manifest免注册调用COM组件