64位进程调用32位dll的解决方法 / 程序64位化带来的问题和思考
最近做在Windows XP X64,VS2005环境下做32位程序编译为64位程序的工作,遇到了一些64位编程中可能遇到的问题:如内联汇编(解决方法改为C/C++代码),long类型的变化,最关键的遇到了64位进程需要调用32位dll的问题。由于有一些32位dll没有源代码,无法重新编译为64位dll,所以只能想办法解决64位进程调用32位dll问题,这个问题让我很是挠头了几天。
相关资料:
微软公司的官方网站针对这个问题描述如下:
在64位的windows系统中,一个64位进程不能加载一个32位dll,同理一个32位进程也不能加载一个64位dll。但是,64位windows支持64位和32位进程(包括本机或跨机)间进程间通信(RPC)。在64位windows中,一个进程外32位COM服务器能够与64位客户端进行通信,同样一个进程外64位COM服务器也能与32位客户端进行通信。因此,如果你有一个32位COM无法识别的DLL,你可以将它封装到一个进程外COM服务器中并在一个64位进程中用COM配置调用DLL。(最后一句我也看不太懂!!哈哈哈)
验证:
工作流程:
1.创建一个进程外COM服务器(EXE)。
2.将32位dll的接口函数封装为COM服务器的相关接口。
3.注册COM服务器*.exe /regserver (注销 *.exe /unregserver)。
4.64位进程调用32位COM服务器接口,成功。从而曲线实现了64位进程调用32位dll。
具体步骤:
我首先创建了一个简单的dll工程,只输出一个函数int c = add(int a,int b); 生成lib和dll
然后创建一个进程外COM(EXE类型),内部链接dll,添加方法Method: Add(long *c)
{ *c = add(1,2);}编译生成。
然后注册COM,*.exe /regserver
最创建一个64位WIN32工程验证64位环境下方法调用是否正确,经验证正确!!!
结论:以上方法可以解决64位进程调用32位dll的问题
32位进程调用64位dll应该也可以通过这种方法解决,原因64位windows系统下安装了32位和64位两套COM系统
程序64位化带来的问题和思考
1. 指针和long的转换
这是最基本的处理部分,由于32位系统下地址是32位,所以很多代码里都会存在这样的转换:
void* pData;
LONG lData;
lData = (LONG)pData;
现在地址是64位了,所以原来的这种转换就会导致地址高4Byte丢弃的问题.
这种转换向来被认为不安全,但还是大量出现,实际程序员代码的时候只要用一个指针保留就可以,完全没有必要用一个long保留,同样的问题也会出现在函数指针的保留.
思考:
所谓的存在即合理的思维在作怪吧,很多程序员认为这么做程序运行的好好的,所以不管是否有风险还照样这么写,实际上改成安全写法代码多不了多少.
当然不排除很多程序员对16位、32位、64位完全没有概念的.
还有一点可能是微软的windows消息给人以误导,消息的WPARAM和LPARAM中常会夹带数据指针,然后强制类型转换,但是看一下它们的定义,其中隔了一层,虽然只是语法上的小小手脚,但是绝对是有先见之明, 而很多人只会依样画葫芦而未明白期间的巧妙.
2. PE Import和Export Table的变化
程序中用到了PE hack,由于之前有人发现vista 32下原来所需要替换的一个import table中的函数找不到了,结果竟然去修改了export table, 姑且不谈修改export table的危险吧,结果vista 64的时候发现PE格式有了小小的变更.
MS将Import table中的地址转成了64bit,但是export table却还是32bit,估计其认为代码不可能大于4GB吧,这样就会发现更改export table变得很难,因为不同的dll会被load在不同的地址段,其间差距会大于4GB,所以只有将自己的dll强制定义在和目标dll相同的4GB范围内.
回头来说这种更改是极其危险的,因为对于export table OS会尽量保持全局唯一,所以一旦你的dll退出未能正确恢复原有的值,会造成其他所有使用到这个dll的程序crash.
最终我发现需要hack的那个函数放在了delayload import table中,简单的修改就解决了问题.
如果这个问题最终找不到而还是采用修改export table的方法,那么就会很惨,测试部门已经发现了经常性的系统crash.
思考:
这里出现了弯路,这个弯路项目的时间压迫难辞其咎,但是程序员未能自己去分析问题是更大的问题,vista在很多方面都保留了很好的兼容性,去分析下windows的目录就会发现基本和xp区别不大,所以很多基础dll的功能也没有变化(这一点让我感觉到vista并未如其发表的那样70%代码重写),在分析dll的时候只要稍微仔细点就会找到问题很简单.
另一个问题就是MS在定义PE格式的时候的确有很高的前瞻性,很好的保持了松耦合的能力,其实PE格式在2001年后就基本没有什么大的更改,那时大家还基本没有64位的概念,这一点是需要学习的,但是同样对于export table没有扩展到64bit我还是保留意见,难道真的认为4GB不会超过?当年盖茨大叔不是宣称640KB就够了吗^.^
3. DelayLoad的问题
DelayLoad这个特性在VC6开始出现,一般大家不会去接触,包括我自己,要不是这次机会也不会去看.
推荐一篇文章
http://www.microsoft.com/msj/0200/hood/hood0200.aspx
有详细的阐述,有兴趣可以自己看一下,其实其原理很简单,主要是在使用到某个dll的接口的时候再去load这个dll,这样可以节约空间,因为有些dll中的接口可能在程序周期中永远不会用到, 而且如果某个dll没有,如果没有用到,那么整个程序也能继续执行.
这真的是一个巧妙的设定, 虽然在第一次呼叫的时候会有小小的性能损失,并且代码也会稍微大一点,但是可能会带来更大的空间节省.
但是随即带来的思考, 为什么这么好的一个东西会那么生疏呢?个人考虑有以下原因:
1. 这种技术显然对于很多人来说过于底层了,有多少人在意编译出来的程序是怎么样存放,又是如何被加载运行的呢?
2. DelayLoad带来的好处对很多人不可见,只要我的程序编译通过,并且可以正确执行就可以了,节省了那么些空间或者扩展兼容有必要考虑吗?
3. 现在的硬件太好了,何必要去做这种优化呢?内存消耗多了,没什么嘛去买1GB内存插上不久解决了?
4. 编译系统不够智能,可能Visual Studio做的更加智能些,自动去分析然后产生delay load会更好吧?
64位进程调用32位dll的解决方法 / 程序64位化带来的问题和思考的更多相关文章
- 64位进程调用32位dll的解决方法
64位进程调用32位dll的解决方法 最近做在Windows XP X64,VS2005环境下做32位程序编译为64位程序的工作,遇到了一些64位编程中可能遇到的问题:如内联汇编(解决方法改为C/ ...
- JAVA判断32位还是64位,调用不同的DLL(转)
源:JAVA判断32位还是64位,调用不同的DLL 通过获取sun.arch.data.model可判断是32还是64的JAVA 将32或者64位的DLL放不同的目录,实现自适应调用DLL Prope ...
- CLR调试报错“Visual Studio远程调试监视器 (MSVSMON.EXE) 的 64 位版本无法调试 32 位进程或 32 位转储。请改用 32 位版本”的解决
Win7 64位电脑上进行visual studio的数据库项目的CLR存储过程进行调试时,报错: ---------------------------Microsoft Visual Studio ...
- WAMP安装提示缺少 msvcr100.dll文件解决方法
WAMP安装提示缺少wamp msvcr100.dll文件解决方法 因为wamp基于vs c++2010开发,需要提前安装这个组件才可以正常运行 微软官方组件下载地址: 32位:http://www. ...
- 在启动php时,无法启动此程序,由于计算机中丢失MSVCR110.dll的解决方法
在启动php时,运行RunHiddenconsole.exe php-cgi.exe -b 127.0.0.1:9000 -c时,出现错误:无法启动此程序,由于计算机中丢失MSVCR110.dll 方 ...
- vmware 传输(vmdb)错误-32:pipe:read failed 解决方法
摘自: http://www.myzhenai.com.cn/post/1088.html 传输(vmdb)错误-32:pipe:read failed 解决方法 原创内容,转载请注明出处:htt ...
- vc的环境变量配置和缺少mspdb60.dll的解决方法
vc的编译器是cl.exe,我们如果在vc中编译就不用配置环境,但是如果要在任何位置用命令提示符打开编译器cl.exe来编译程序,那么就要配置环境了. 下面我就讲讲vc的环境变量配置和缺少mspdb6 ...
- 64位.net调用32位com服务(c++)
说明: 因64位.net无法调用32位dll,才采用调用进程外com形式. 该项目必须为release时编译才不会报错. 项目调用时,添加引用->com中找到该com服务,添加即可. 部署: 启 ...
- Win10 64位系统ADO方式操作数据库失败解决方法
VC操作Access数据库一般通过ODBC.ADO.DAO等方式,但在我的Win10 64位操作系统中,通过ADO方式操作数据库会失败,无法读取数据.解决方法:1.首先确保Win10操作系统ado目录 ...
随机推荐
- Sidekiq定时任务时间设置
minutely(2) #每2分钟执行一次 hourly.minute_of_hour(27) #每小时的27分钟执行 dail ...
- OPCServer:使用KEPServer
实际OPCServer使用(450M,中文,破解时间限制):KEPServer V6,百度网盘 ,密码: ykj2 本文为Java实现OPC通信的一部分 KEPServer中文官网 KEPServer ...
- ArcGis Python脚本——批量对影像、要素类定义投影
这一段是批量定义要素类(FeatureClasses)投影的ArcPy代码: 把要处理的要素类塞进一个文件夹(工作空间,workspace),然后将代码开头的路径换成这个“文件夹”的路径,处理完后再做 ...
- C# web IIS服务器 DateTime 带中文解决
C# Web应用在某些电脑IIS上部署运行,读取当前时间带有中文,比如2018-5-1 星期一 上午 12:00:00,虽然使用Format转换可以解决,但代码量较大难免遗漏,会引发问题,为了解决该问 ...
- 【五】服务熔断、降级 —— Hystrix(豪猪)
分布式系统面临的问题 复杂分布式体系结构中的应用程序有数十个依赖,每个依赖关系将在某些时候将不可避免地失败. 服务雪崩 多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务 B和微服务 ...
- GCC编译器原理(一)------交叉编译器制作和GCC组件及命令
1.1 交叉编译器制作 默认安装的 GCC 编译系统所产生的代码适用于本机,即运行 GCC 的机器,但也可将 GCC 安装成能够生成其他的机器代码.安装一些必须的模块,就可产生多种目标机器代码,而且可 ...
- 卷积中的full、same、valid
通常用外部api进行卷积的时候,会面临mode选择. 本文清晰展示三种模式的不同之处,其实这三种不同模式是对卷积核移动范围的不同限制. 设 image的大小是7x7,filter的大小是3x3 ...
- Java SE之正则表达式三:替换
/** * * @author Zen Johnny * @date 2018年4月29日 下午4:31:07 * */ package demo.regex; public class RegexR ...
- Coursera, Deep Learning 4, Convolutional Neural Networks, week3, Object detection
学习目标 Understand the challenges of Object Localization, Object Detection and Landmark Finding Underst ...
- Leetcode#118. Pascal's Triangle(杨辉三角)
题目描述 给定一个非负整数 numRows,生成杨辉三角的前 numRows 行. 在杨辉三角中,每个数是它左上方和右上方的数的和. 示例: 输入: 5 输出: [ [1], [1,1], [1,2, ...