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目录 ...
随机推荐
- 【SqlServer】SqlServer中的计算列
计算列区别于需要我们手动或者程序给予赋值的列,它的值来源于该表中其它列的计算值.比如,一个表中包含有数量列Number与单价列Price,我们就可以创建计算列金额Amount来表示数量*单价的结果值, ...
- Kafka技术内幕 读书笔记之(二) 生产者——新生产者客户端
消息系统通常由生产者(producer ). 消费者( consumer )和消息代理( broker ) 三大部分组成,生产者会将消息写入消息代理,消费者会从消息代理中读取消息 . 对于消息代理而言 ...
- 关于Mysql的高级查询的操作
前言:作为一名后端的程序员操作数据库的能力是我们基本的技能,而连表查询是我们的这个技能的关键点所在.注意这里顾明思义是对数据的查询的操作 (一).联合查询(关键字union/union all) 什么 ...
- spring MVC页面的重定向
如图,一个jsp页面跳转到下一个jsp页面通常需要上一个页面发出带有参数得请求,我们都知道spring MVC是不能直接跳页面的. 需要配置视图解析器,通过返回视图名再跳转到相应得JSP页面. 即使这 ...
- BBS总结
表设计 from django.db import models from django.contrib.auth.models import AbstractUser # Create your m ...
- ZOJ - 3450 Doraemon's Railgun (dp)
https://vjudge.net/problem/ZOJ-3450 题意 一座位落(X0,Y0)的城市将遭受n个敌人的摧残.现在我们手上有某科学的超电磁炮,每次攻击都是一条射线,对于共线的敌人,必 ...
- Python复习笔记(六)网络编程(udp/tcp)
一.网络-udp(用户数据报协议) 用户数据报协议 类似写信,不安全,数据有可能丢 1.1 ip地址 注意: IP地址127.0.0.1 ~ 127.255.255.255 用于回路测试 私有ip地址 ...
- Win32程序框架
// WinMsg.cpp : 定义应用程序的入口点. // #include "stdafx.h" #include <stdio.h> #include " ...
- Error:Failed to resolve: com.android.support:recyclerview-v7:26.1.0
修改gradle allprojects { repositories { maven { url "https://maven.google.com" } jcenter() } ...
- JavaScript之正则表达式[应用实例]
1. 获取信息 "水资源利用与保护周三第9,10,11节{第1-6周}施浩然3B-302多媒体教室152座信息检索周三第9,10节{第9-12周}谭长拥4A-207多媒体160座{第12周} ...