通过进程外Com组件实现win764位程序调用32位库+附加demo源码

背景:客户有个功能需要添加到软件中,但软件是64位,客户只能提供32位库。

环境:电脑系统为win764位,编译环境为vs2010.

实现方式:使用进程外Com组件实现。

前言:Com组件有三种模式:进程内组件(dll)、进程外组件(exe)、远程组件(server)。因为32位和64位程序不兼容,进程内组件无法实现;32位库可以在本地调用,所以没有必要选择server;

原理:64位和32位程序不能在同一进程中兼容,所以创建一个32位进程外Com组件,在该组件中加载32库,并创建接口封装32库里的功能,最后通过输入输出参数实现数据交互,64位程序通过调用进程外组件的接口实现调用32库的功能。64位程序和组件分别在不同的进程,所以需要代理/存根Dll进行接口参数的转换传输管理。

主要步骤:实现进程外Com组件调用共有如下4个步骤:

(1)创建进程外Com组件

(2)创建代理/存根(proxy/stub)DLL

(3)注册组件和代理/存根

(4)调用组件接口

注意:因为权限问题,下列项目最好用管理员权限打开VS2010,并且将属性中的UAC执行级别修改为requireAdiminstrator


实现进程外Com组件调用详细步骤如下:

一、创建进程外Com组件

        创建方式:通过ATL项目创建

        步骤如下:

        1、创建ATL项目:创建项目TestComExe;注意选择exe类型,支持代理/存根,如下图所示:

            

        2、添加Alt简单对象:右击项目TestComExe->添加->类->ATL简单对象->添加;在弹出的简单对象向导中有8个编辑框,

             在第一个编辑框中添加类名称:TestClass,其他编辑框会同步命名;最后的ProgID(此为接口标记)必须自己命名

             现命名为:TestComExe.TestClass;最后点完成。弹出窗口是否覆盖选是。

                     

        3、添加接口:在类视图中找到ITestClass,右击->添加->添加方法;在向导界面中添加方法名称和参数:

              注意:参数分为输入参数和输出参数,输入输出参数格式会影响接口使用效果。关于参数传输的方式详见:

                https://blog.csdn.net/wcyoot/article/details/6562620

             普遍来说:普通参数可以直接传递。数组或指针必须要特殊处理。根据测试发现:

                                [in,string]输入输出均正常。

                                一维数组和二维数组在不同位程序中调用中不能实现,只支持同位程序调用,所以没什么意义。

                                VARIANT可以支持不同位程序间的调用,故该测试输入使用字符串,输出使用Variant序列化。

                                

                字符串输入记得标记输入格式:[in,string],位置在TestComExe.idl中的testMothd中修改:

                        

                4、在接口方法testMothd中调用32位库函数或者任意实现其他功能(32位库的调用请自行在TestClass中实现,源码中只测试参数传递)

                    

编译生成TestComExe.exe。进程外组件就创建完成,但想要调用它还必须生成代理/存根(Proxy/Stub)DLL。

二、创建代理/存根(Proxy/Stub)DLL

    1、创建Win32工程TestComExePS:

            (1)选择Win32项目

            

            (2)选择Dll空项目,完成

            

    2、将Com组件中的“TestComExe.idl”文件拷贝到项目根目录中

            我的项目路径是“G:\Work\测试源码\Com组件\TestComExe\TestComExePS”。

    3、用MIDL工具编译IDL文件:

            (1)打开 “Visual Studio 命令提示

                    

            (2)跳转至目标路径,编译idl文件,回车执行

            

            (3)编译完后会生成“dlldata.c”,“TestComExe.h”,“TestComExe_i.c”,“TestComExe_p.c”,“TestComExe.tlb” 五个文件。

              

            (4)新建文件“TestComExePS.def”,输入内容如下:

                

            (5)在项目中添加文件dlldata.c”,“TestComExe.h”,“TestComExe_i.c”,“TestComExe_p.c”,“TestComExePS.def 

                

            (6)在配置属性>C/C++>预处理器中添加“REGISTER_PROXY_DLL”

                

            (7)在配置属性》连接器》输入》附加依赖项中添加“rpcns4.lib”,“rpcrt4.lib”,“uuid.lib”;并将模块定义文件设为:“TestComExePS.def

                

            (8)生成项目“TestComExePS.dll”

三、注册组件和代理/存根DLL

        组件和代理/存根Dll在生成时会自动注册,但是给客户电脑使用需要Release提取出来单独注册。

        

        组件注册命令为: 路径/TestComExe.exe  /regserver

        反注册命令为:    路径/TestComExe.exe /unregserver

        代理/存根Dll注册命令为:regsvr32 路径/TestComExePS.dll

        反注册命令为:    regsvr32 /u 路径/TestComExePS.dll

        注意使用管理员权限执行命令。

       demo中将命令简单编写为Reg.bat

        

四、客户端调用组件接口

       1、创建win32程序TestClient(可设为64位)

       2、将TestComExePS中的“TestComExe.h”,“TestComExe_i.c”文件拷贝到TestClient中

       3、在调用前申明:#include "TestComExe.h" #include "TestComExe_i.c"

       4、初始化

            HRESULT hr=CoInitializeEx(NULL,COINIT_MULTITHREADED);

       5、获取类厂指针

            IClassFactory* p_classfactory;

    hr=CoGetClassObject(CLSID_TestClass,CLSCTX_LOCAL_SERVER,NULL,IID_IClassFactory,(LPVOID*)&p_classfactory);

       6、获取接口

            ITestClass * lv_pTestClass;

            if(hr==S_OK)
    {
hr=p_classfactory->CreateInstance(NULL,IID_ITestClass,(void**)&lv_pTestClass);

    }

       7、调用方法

            lv_pTestClass->testMothd(lv_str,lv_iLen,&varChunk);

       8、反初始化

            CoUninitialize();

       9、测试参数传递代码如下:

	HRESULT hr=CoInitializeEx(NULL,COINIT_MULTITHREADED);
	ITestClass * lv_pTestClass;
	long lv_iLen=100;
	//使用softarrary
	VARIANT varChunk;
// 	SAFEARRAY *psa; //使用数组整理读取的数据
// 	SAFEARRAYBOUND rgsabound[1];
// 	rgsabound[0].cElements =lv_iLen; //设置数组的大小
// 	rgsabound[0].lLbound = 0;
// 	psa = SafeArrayCreate(VT_UI1,1,rgsabound); //创建SafeArray数组
// 	varChunk.vt=VT_ARRAY|VT_UI1;
// 	varChunk.parray=psa;
	//
	char * lv_str=(char*)CoTaskMemAlloc(lv_iLen);
	strcpy(lv_str,"sdfkssafjsadfojasdfosadfsf");
	IClassFactory* p_classfactory;
	hr=CoGetClassObject(CLSID_TestClass,CLSCTX_LOCAL_SERVER,NULL,IID_IClassFactory,(LPVOID*)&p_classfactory);
	if(hr==S_OK)
	{
		hr=p_classfactory->CreateInstance(NULL,IID_ITestClass,(void**)&lv_pTestClass);
		lv_pTestClass->testMothd(lv_str,lv_iLen,&varChunk);
	}
	SAFEARRAY *psa=varChunk.parray;

 	BYTE* lv_pbuf=NULL;
	SafeArrayAccessData(psa,(void**)&lv_pbuf);
	SafeArrayUnaccessData(psa);
	SafeArrayDestroy(psa);

	CoTaskMemFree(lv_str);

	CoUninitialize();

       10、因为.c文件和c++文件编译方式不同,故将TestComExe_i.c设置不使用预编译头,方法:

            在解决方案中右击“TestComExe_i.c”选属性,在C/C++中预编译头中选择不使用预编译头

           

       11、编译时在“TestComExe.h”中会报CLSID_TestClass等参数重编译,在“TestComExe.h”中注销它们

            


附加Demo源码https://download.csdn.net/download/liutao_94520/10503291

        


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值