一、原理
XP以上的操作系统支持COM免注册技术,操作系统在加载EXE时会自动扫描是否包含配套的manifest信息,若有则读取manifest内容加载组件,否则读取注册表。
manifest描述了EXE里面引用了哪个DLL库、DLL里面提供了什么接口等信息,只要给EXE、DLL加上配套manifest即可完成免注册工作。
二、Manifest清单文件
Windows XP开始,系统通过XML文件来实现这一功能,这些XML文件保存了有关应用程序配置的元数据,这里所说的XML文件,就是Manifest清单文件。
Manifest事实上就是一个以.manifest为后缀的XML文件,用于组织和描述隔离应用程序及并行组件,其内部的信息如元素则标识着一个唯一的程序集,和其他信息一起,他们用于COM类、接口及库的绑定和激活,而这些信息,以往都是存储在注册表中的。另外,Manifests也制定了组成程序集的文件及Windows类。
与执行Name.exe配套的Manifest文件的文件名,Name.exe.Manifest。
三、Manifest清单机制
这是Windows的Assembly Manifest机制,其功能就是为了解决以前windows上的“Dll hend”(“Dll 地狱”)问题,建立的一种DLL管理解决方案。
Dll是动态加载共享库,同一个Dll可能被多个程序所使用,而所谓“Dll 地狱”就是当不通程序依赖的Dll相同,但版本不同时,由于系统不能分辨到底哪个是哪个,所以加载错了Dll版本,然后就挂了。windows对EXE文件,配套一个程序集清单的文件。让每个程序都有一个清单,列出其所需要的所有依赖,这儿所列出的依赖可不是简单地靠文件明来区分的,而是根据一种叫做“强文件名”的东西区分的,那么什么是强文件明呢?我们来看一下这个.manifest文件便知道了
四、manifest结构
1、在Windows中,manifest(清单)是一个XML文件,根据清单类型不同,可以分为以下几种:
| mainfest 功能 | |
| Manifest | 描述 |
| 程序集清单 | 描述名称、版本、资源、依赖的side-by-side程序集 |
| 应用程序清单 | 描述共享的side-by-side的程序集版本和名称,可能包含私有side-by-side的程序集元数据 |
| 应用程序配置文件 | 重定向每一个应用程序依赖的程序集版本 |
| 发布者配置文件 | 使用发布者配置重定向一整块的程序集版本 |
2、Manifest文件XML内部结构
| MXL结构 | |||
| 元素 | 属性 | 是否必须 | 说明 |
| 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 | |
四、Manifest使用方式
1、嵌入EXE,通过将资源文件嵌入EXE文件中。
2、在执行文件,同一目录中建立同名的清单文件。
程序(执行)文件:MyName.exe,清单文件MyName.exe.manifest
或Dll文件,MyName.dll,清单文件MyName.dll.manifest
五、Manifest实现
使用通行的编译程序,如C、C++、Delphi等,编译项目组(创建EXE执行文件)时:
- 创建Mainfest文件
- 编译生成EXE文件相同目录中
- 编译EXE文件
其它:
- 锐浪报表 Grid++Report 免注册DLL C/S报表开发(一)
- 锐浪报表 Grid++Report 免注册DLL C/S报表开发(二)清单文件manifest分析



