利用manifest文件对程序目录下的dll进行分类
1 背景
对于大部分的券商和机构投资者,只能通过有交易所交易系统接入资质的券商提供的柜台系统来进行现货交易。相对于期货市场,现货市场的柜台系统千差万别,接入协议有明文字符串、二进制数据和FIX协议等,接入方式有TCP连接、COM组件和dll动态库等。要想开发一个覆盖市面上所有的现货柜台的报盘系统,就必须能同时支持这些柜台的所有接入方式。在开发的过程中遇到的关于动态库版本兼容问题有以下几个:
- 同一柜台系统提供商发布了2套柜台系统,用于对接这2套系统的开发包是一样的,只是由于版本不同不能通用
- 不同柜台系统提供的动态库包含了不同版本的第三方库文件(如libeay32.dll等)
- 部分券商对柜台系统进行了自定义开发,在柜台提供的开发包中加入了自己开发的动态库,以增加对接入授权的控制
当系统中存在同名的且不同版本的动态库时,为了能方便管理和更新程序,只能对这些动态库进行分类整理。具体做法是在程序执行目录下对每个类别的柜台分别建立一个文件夹,用于存放对接该柜台所需要的所有的动态库文件。由于程序采用了静态加载的方式去加载dll,为了能让可执行文件在启动时能找到这些动态库,manifest文件就派上用途了。
2 关于manifest文件
manifest文件是用于组织和描述并行组件或独立应用程序的xml文件。它主要包含了用于绑定和激活COM类、接口和库的相关信息,这些信息以往是存储在系统注册表中的[1]。在xp及以后的windows系统中,系统在执行EXE可执行文件时会首先读取Manifest文件,获得exe文件需要调用的DLL列表(此时获得的,并不直接是DLL文件的本身的位置,而是DLL的manifest),操作系统再根据DLL的Manifest文件提供的信息去寻找对应的DLL ,这样就可以区别不同版本的相同文件名的DLL文件[2]。
微软msdn上的一个配图比较直观地描述了这一过程[3]:

3 组件查找顺序
在windows系统中,如果应用程序指定了组件依赖关系,则程序启动时首先在WinSxS文件夹中查找共享组件,若未找到,则在程序安装目录下查找私有组件。
在大部分的情况下,组件的查找顺序如下所示:
- WinSxS 文件夹
- \\<appdir>\<assemblyname>.DLL
- \\<appdir>\<assemblyname>.manifest
- \\<appdir>\<assemblyname>\<assemblyname>.DLL
- \\<appdir>\<assemblyname>\<assemblyname>.manifest
更详细的描述可以查看msdn中的Assembly Searching Sequence
4 实现
场景一 程序需加载两个不同版本的sample.dll
解决办法:
- 分别建立两个文件夹(dlla,dllb),将两个不同版本的dll分别放入这两个文件夹
- 文件夹下分别新建一个manifest文件,文件名同文件夹名,例dlla.manifest、dllb.manifest
- 编辑manifest文件,内容如下(以dlla为例):
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="dlla" processorArchitecture="x86" version="1.0.0.0" type="win32" /> <-- 这边的name必须为manifest文件所在的文件夹的名字
<file name = "sample.dll"/>
</assembly> - 在需要用到动态库提供的函数的cpp中增加以下预处理指令(以dlla为例):
// 指定加载dll的位置;
#pragma comment(linker,"/manifestdependency:\"type='win32' "\
"name='dlla' "\
"version='1.0.0.0' "\
"processorArchitecture='x86' "\
"language='*' "\
"\"")
重新编译后,程序便能正确找到指定的动态库了。
场景二 程序需加载两个不同版本的sample.dll,且不同版本的sample.dll分别又依赖不同的第三方开发库
解决办法:在场景一的解决办法的基础之上,在manifest文件中增加依赖的第三方库的信息,例:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity name="dlla" processorArchitecture="x86" version="1.0.0.0" type="win32" /> <file name = "sample.dll"/>
<file name = "libeay32.dll"/>
<file name = "ssleay32.dll"/> </assembly>
场景三 程序需加载两个不同版本的sample.dll,但是调用这2个动态库的代码存在某种引用关系。
解决办法:在这种场景下,由于预编译宏会互相覆盖,导致动态库不能正确加载,只能通过LoadLibrary的方式进行动态加载。事实上,通过动态加载可以加载任意路径的动态库,只是在使用方式上没有静态加载方便。
4 总结
利用manifest文件同时加载多版本的同名的动态库的方式是windows系统特有的功能,在平时c++的开发中也很少接触到。这边仅作记录供以后碰到相同问题的时候作为参考。
1. https://msdn.microsoft.com/en-us/library/aa375365(v=vs.85).aspx
2. http://blog.csdn.net/suxinpingtao51/article/details/42870937
3. https://msdn.microsoft.com/en-us/library/ff951640(v=vs.85).aspx
本文为原创内容,若有错误的地方烦请指正
本文地址:http://www.cnblogs.com/morebread/p/4953497.html
利用manifest文件对程序目录下的dll进行分类的更多相关文章
- 可以把一堆dll文件放到程序目录下的一个自建目录里面
窦宁波大哥哥的那篇文章的这种写法还是很有参考价值的. QString strLibPath(QDir::toNativeSeparators(QApplication::applicationDirP ...
- php上传zip文件在线解压文件在指定目录下,CI框架版本
我从网上找的文件php在线解压zip压缩文件 文件为jy.php可以直接执行,但是怎样将其加到CI框架中呢?? jy.php文件 <?php header("content-Type: ...
- 关于解决pyinstaller2.1将.py打包成exe文件在中文目录下不能执行的问题
关于解决pyinstaller2.1将.py打包成exe文件在中文目录下不能执行的问题 这个问题困扰我好久了,今天终于非常偶然的在http://www.v2ex.com/t/113856#reply1 ...
- java利用WatchService实时监控某个目录下的文件变化并按行解析(注:附源代码)
首先说下需求:通过ftp上传约定格式的文件到服务器指定目录下,应用程序能实时监控该目录下文件变化,如果上传的文件格式符合要求,将将按照每一行读取解析再写入到数据库,解析完之后再将文件改名. 一. 一开 ...
- Inno Setup入门(六)——在程序目录下创建文件
创建文件夹可以使用[dirs]段实现,代码如下: [setup] ;全局设置,本段必须 AppName=Test AppVerName=TEST DefaultDirName="E:\TES ...
- Inno Setup入门(六)——在程序目录下创建文件夹
创建文件夹可以使用[dirs]段实现,代码如下: [setup] ;全局设置,本段必须 AppName=Test AppVerName=TEST DefaultDirName="E:\TES ...
- (转)Inno Setup入门(六)——在程序目录下创建文件夹
本文转载自:http://blog.csdn.net/yushanddddfenghailin/article/details/17250789 创建文件夹可以使用[dirs]段实现,代码如下: [s ...
- 利用wget批量下载http目录下文件
原理:下载你需要down的目录页面的index.html,可能名字不是如此!!!之后用wget下载该文件里包含的所有链接! 例如:wget -vE -rLnp -nH --tries=20 --tim ...
- 利用WatchService监控C盘根目录下的文件情况
public static void main(String[] args) throws IOException, InterruptedException { WatchService watch ...
随机推荐
- mysql-1
接触mysql已经一年多了,但是平时很少用到,仅限于安装部署,最近在学习运维开发,需要用到数据库,于是买了一本mysql必知必会,给自己一个两个星期的时间,学完这本书, 写这一系列的博客,就是记录学习 ...
- javascript 基础教程[温故而知新一]
子曰:“温故而知新,可以为师矣.”孔子说:“温习旧知识从而得知新的理解与体会,凭借这一点就可以成为老师了.“ 尤其是咱们搞程序的人,不管是不是全栈工程师,都是集十八般武艺于一身.不过有时候有些知识如果 ...
- MySQL运行状态show status中文详解(转)
要查看MySQL运行状态,要优化MySQL运行效率都少不了要运行show status查看各种状态,下面是参考官方文档及网上资料整理出来的中文详细解释: 状态名 作用域 详细解释 Aborted_cl ...
- 错误 未能找到类型或命名空间名称 (是否缺少 using 指令或程序集引用?)
有时发现,明明引用了,结果却提示未引用, 这时就有可能是两个程序集的目标框架类型不一致导致的(在程序集属性面板里改下即可).
- git pull
今天在服务器上git pull是出现以下错误: error: Your local changes to the following files would be overwritten by mer ...
- 单片机实现60s定时器
单片机573+数码管+按钮 实现60秒的定时器 知识: IE寄存器 TCON寄存器 TMOD 寄存器 /***************** 2个定时中断,2个按钮中断 **************** ...
- Containers Reserved yarn resourcemanager
yarn rm的管理页面中显示了集群的概况,其中有一个指标叫Containers Reserved . 预留的容器,为什么会预留,集群的资源使用饱合,新的app请求的资源一般会进入pending状态, ...
- 报表引擎API开发入门—带参程序数据集
我们今天又来讲讲报表开发的事,上周开的这个系列入门文章也三四天了,浏览量不佳小编甚是悲伤啊,希望大家多多支持我! 一.问题描述 在实际应用中,可能需要根据表名动态地改变数据源,比如在程序数据集中,通过 ...
- MMORPG大型游戏设计与开发(客户端架构 part6 of vegine)
客户端的变量模块部分主要是将一些常用可变的值集中管理,如窗口的大小,是否开启音乐,音量的大小等等.这些变量通常会应该到客户端的操作,一般来说变量改变的时候会调用一个回调进行处理.下面我们就看看该模块的 ...
- Binary Tree: Write a function to return count of nodes in binary tree which has only one child.
June 8, 2015 我最喜欢的一道算法题目, 二行代码. 编程序需要很强的逻辑思维, 严密,我还没有很好训练自己.想一想, 二行代码, 五分钟就可以搞定; 最近这几天网上大家热议的 Homebr ...