Windows10 下64位程序调用32位dll


方法:

64位windows支持64位和32位进程(包括本机或跨机)间进程间通信(RPC)。在64位windows中,一个进程外32位COM服务器能够与64位客户端进行通信,同样一个进程外64位COM服务器也能与32位客户端进行通信。因此,如果你有一个32位COM无法识别的DLL,你可以将它封装到一个进程外COM服务器中并在一个64位进程中用COM配置调用DLL。
原文链接:https://blog.csdn.net/nie2314550441/java/article/details/49867735

使用工具:

VS2017

步骤:

1.Devin已经验证64位exe能调用32位dll,从他手中拿来Demo分析。

一共三个项目:

 

 ATLProject12->COM exe 32位 (64位程序通过COM exe 调用32位dll)

ConsoleApplication-> 64位程序

MFCLibrary3->32位dll

 

问题:项目copy后vs打开,把依赖项路径什么的改了,发现代码中的类或函数都不能直接F12。

原因:.vs这个文件夹没有删除,导致VS打开项目时,是根据之前同事电脑上的配置进行的加载。

 

 .vs文件夹:用来存储当前用户在解决方案中的工作配置,具体包括VS关闭前最后的窗口布局、最后打开的选项卡/操作记录/文件文档、某些自定义配置/开发环境、调试断点等这类设置信息和状态

参考链接:https://shiyousan.com/post/636441130259624698

 

2.

MFCLibrary:32位dll,会导出一个接口供ATLProject项目调用。

ATLProject12

ATL(类型库):类型库是idl文件、COM类文件,.h文件,.cpp文件,.def文件的综合体。类型库里面包含了我们所要用的COM组件(COM类)。我们经常使用的word、excel的COM组件,都是通过他们的类型库导入客户程序的,然后我们才能通过CoCreateInstance()来构建组件对象。类型库就是COM类的容器,里面包含了若干COM类,是一个独立的能被客户程序导入的dll文件,是对COM组件的打包。

ATL作用:

ATL专门用来生成COM组件的,编译后生成dll文件或者exe文件。

com组件和普通的dll文件有什么区别呢?

com组件优点:1.语言无关性;2.便于升级扩展;3.有很好的继承封装多态特性,即面向对象能力强;4.完成进程间,分布式功能;5.接口调用,便于组织。

 

VS创建一个ATL项目(必须要用管理员权限打开,不然最后编译时会报错 error MSB8011: 未能注册输出。PS:报这个错也有可能是依赖项没有全部配好)

 

选择服务(.exe) 。

生成项目后新建项

 

ATL简单对象

 

 

 

ProgID:

是在定义COM类时为类起的别名,方便程序员记住。命名规则为:ProjectName.ClassName.VersionNumber,即:工程名(类型库名称).类名(COM类名称).(版本号)

在这里填一个自己能记住的先。

 

生成ATLSimpleObject.cpp和ATLSimpleObject.h

在.h和.cpp中添加需要导出的接口及实现

 

 

 源文件中有一个idl文件

 

 

 

 在interface里面添加前面写好的需要导出的接口,[in]:表示传入参数,[out]:表示传出参数。基础变量不用改变,string字符串需要用BSTR转。或使用VARIANT变量传递参数

生成,产生一个ATLProject_i.c 和 ATLProject_i.h(.h中有导出的函数的声明)。把这两个文件添加到64位项目下,就能直接调用接口。

 

验证过程中参数传递的问题:

需要传图片进32位dll进行处理,并返回处理后的图片,使用OpenCV3.0

返回Mat。

使用COM组件提供的VARIANT和SAFEARRY(安全数组)进行Mat数据的传递。

VARIANT* matBackData;

SAFEARRAY *pArray1 = nullptr;
HRESULT hr = SafeArrayAllocDescriptor(1, &pArray1);//创建SAFEARRAY结构对象,在栈上
pArray1->cbElements = sizeof(unsigned char); //每个元素占用的字节数
pArray1->rgsabound[0].cElements = 5120 * 5120; //第0维数组元素个数
pArray1->rgsabound[0].lLbound = 0; //第0维数组起始下标
hr = SafeArrayAllocData(pArray1);//在堆上申请内存存放SAFEARRAY

上面这段代码创建了一个5120 * 5120大小的安全数组

memcpy(pArray1->pvData, umatBackData, 5120 * 5120);

//pArray1->pvData = umatBackData;  //不能直接=。

umatBackData为需要放入安全数组的数据。这里umatBackData = mMat.data。mMat是处理后的图片

matBackData->vt = VT_ARRAY | VT_UI1;//VT_VARIANT //SAFEARRAY的类型必须为VT_ARRAY, VT_UI1: 指明数组数据为unsigned char
matBackData->parray = pArray1;

matBackData可以成功返回数据。在调用端使用完后,需要释放安全数组

SafeArrayUnaccessData(matBackData.parray);
SafeArrayDestroy(matBackData.parray);
VariantClear(&matBackData);

总结:

使用COM进行64位32位间的接口相互调用,和普通的32调32,64调64方法基本一样,主要问题在于复杂结构的参数传递,可以使用COM提供的VARIANT和SAFEARRY对参数进行打包,然后传递。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM