使用进程外COM服务在64位应用中调用32位DLL
创始人
2024-10-22 06:11:40
0

最近做一个项目,需要在64位的VS2022 c++项目中调用32位的动态库,实现导出docx文件的功能,开始在网上找了一些解决方案,基本都是:创建32位COM组件 -- 注册32位COM组件 -- 64位程序调用32位COM组件,但是按照这些方法封装COM组件后,发现不能调用,客户端使用CoCreateInstance创建对象提示创建COM服务器接口的实例时出现类未注册错误(REGDB_E_CLASSNOTREG Class not registered,查看注册表,计算机\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Classes\CLSID\{**********},发现COM组件成功注册,但就是不能调用,百思不得其解!最后经过几天的摸索,找到解决办法,在这里分享一下。

一、COM组件有in-process和out-of-process两种

运行in-process的COM客户端和COM服务器需要以相同的位元运行,因此在x86中都是如此,或者在x64中都是这样。因此:

  • 如果COM客户端以x86运行,它会与注册表的x86侧进行通信,因此COM服务器必须在注册表的x86侧注册(regsvr32、regasm、自定义reg代码等必须以x86方式运行)。
  • 如果COM客户端以x64运行,它将与注册表的x64侧进行通信,因此COM服务器必须在注册表的x64侧注册(regsvr32、regasm、自定义reg代码等必须以x64方式运行)。

对于out-of-process通信,x86客户端或服务器可以与x64服务器或客户端进行通信。这是COM的一个好处。也是解决64位软件调用32位DLL的关键所在!笔者的问题就是封装了in-process的COM组件,导致无法在64位进程内调用32位DLL。后面创建out-of-process类型的COM组件,问题得到解决!

二、创建out-of-process类型的COM组件的流程

1.建一个ATL项目

2.选择可执行文件,注意:应用程序类型这里选择exe,表示创建out-of-process COM组件;如果选择DLL,则是in-process,切记不要选错

3.添加ATL简单对象

4.在IDL文件中添加 show([in] BSTR a);接口

import "oaidl.idl"; import "ocidl.idl";  [ 	object, 	uuid(93e14b15-e9de-44c0-9fa1-12f5ba1265fd), 	dual, 	nonextensible, 	pointer_default(unique) ] interface IATLSimpleObject : IDispatch { 	[id(1)] HRESULT show([in] BSTR a); }; [ 	uuid(74fa1274-a76d-4392-b2b1-f841db7be581), 	version(1.0), ] library ATLProject1Lib { 	importlib("stdole2.tlb"); 	[ 		uuid(d9049425-0435-4727-85bb-853d81368b19) 	] 	coclass ATLSimpleObject 	{ 		[default] interface IATLSimpleObject; 	}; };  import "shobjidl.idl";

5.在实现类中添加C++函数,实现在IDL新增的接口,此时可以调用x86的DLL,实现自己想要的功能

char* wchartoGBK(LPCWSTR wideStr) {     int wideStrLen = wcslen(wideStr);      int multiByteLen = WideCharToMultiByte(CP_ACP, 0, wideStr, wideStrLen, NULL, 0, NULL, NULL);     if (multiByteLen == 0) {         //std::cerr << "Error converting wide char to multi byte: " << GetLastError() << std::endl;         return "";     }      char* multiByteStr = new char[multiByteLen + 1];     if (!WideCharToMultiByte(CP_ACP, 0, wideStr, wideStrLen, multiByteStr, multiByteLen, NULL, NULL)) {        // std::cerr << "Error converting wide char to multi byte: " << GetLastError() << std::endl;         delete[] multiByteStr;         return "";     }     multiByteStr[multiByteLen] = '\0';       //delete[] multiByteStr;     return multiByteStr; }  STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::show(BSTR a) {     auto str = wchartoGBK(a);     ::MessageBoxA(NULL, str, "test", MB_OK);     delete[] str;     return S_OK; }  

6.编译选项选X86,编译,生成ATLProject1.exe文件

7.打开cmd窗口,cd生成目录,注册COM组件:ATLProject1.exe /regserver(反注册:ATLProject1.exe /unregserver),VS编译后会自动注册,次步可以省略

8.64位客户端调用:创建测试项目,Project1,编译选项选择x64,包含ATLProject1_i.h和ATLProject1_i.c文件,CoCreateInstance的第三个测试填CLSCTX_LOCAL_SERVER,运行弹出测试窗口,成功!收工下班(2024.7.26 18:29)

#include "../../ATLProject1/ATLProject1/ATLProject1_i.h"  #include   using namespace ATL;  int main() { 	HRESULT hr_ini = ::CoInitialize(NULL);  	IATLSimpleObject* Isimple = nullptr; 	HRESULT hr1 = S_OK; 	hr1 = ::CoCreateInstance(CLSID_ATLSimpleObject, NULL, CLSCTX_LOCAL_SERVER, IID_IATLSimpleObject, (LPVOID*)&Isimple); 	if (SUCCEEDED(hr1)) { 		BSTR bstr = ::SysAllocString(L"进程外调用!"); 		Isimple->show(bstr); 		Isimple->Release(); 	}  	::CoUninitialize(); }

输出结果:

参考连接:

VS2022使用进程外Com服务让64位应用调用32位DLL

裸写一个进程外 COM 组件

创建COM服务器接口的实例时出现类未注册错误

相关内容

热门资讯

推荐一下!青橙竞技卡五星辅助,... 推荐一下!青橙竞技卡五星辅助,新518互游脚本下载,好像是真的有挂(哔哩哔哩)青橙竞技卡五星辅助透视...
总结一下!老友广东麻将辅助,杭... 总结一下!老友广东麻将辅助,杭州都莱辅助,切实真的是有挂(哔哩哔哩)1、在老友广东麻将辅助插件功能辅...
解迷一下!创思维激k怎么开挂,... 解迷一下!创思维激k怎么开挂,创思维辅助软件,切实真的有挂(哔哩哔哩)1、创思维激k怎么开挂辅助器安...
辅助一下!微信微乐游戏辅助脚本... 辅助一下!微信微乐游戏辅助脚本,拱趴大菠萝有辅助吗,总是有挂(哔哩哔哩)辅助一下!微信微乐游戏辅助脚...
辅助一下!时光互娱房卡辅助,新... 辅助一下!时光互娱房卡辅助,新漫游免费辅助器,本来真的有挂(哔哩哔哩)1、让任何用户在无需时光互娱房...
关于一下!多乐跑得快私人房间作... 关于一下!多乐跑得快私人房间作弊视频,来来拼十辅助,都是真的有挂(哔哩哔哩)1、打开软件启动之后找到...
教你一下!卡五星游戏源码,决战... 教你一下!卡五星游戏源码,决战卡五星辅助器,其实是有挂(哔哩哔哩)1)决战卡五星辅助器辅助插件:进一...
普及一下!同乡游有辅助软件码,... 普及一下!同乡游有辅助软件码,老友广东辅助器,总是是有挂(哔哩哔哩)1、上手简单,内置详细流程视频教...
曝光一下!创思维激k有辅助器吗... 曝光一下!创思维激k有辅助器吗,hhpoker辅助是真的吗,好像存在有挂(哔哩哔哩)创思维激k有辅助...
总结一下!边锋干瞪眼小程序辅助... 总结一下!边锋干瞪眼小程序辅助,心悦踢辅助软件,真是存在有挂(哔哩哔哩)1、这是跨平台的边锋干瞪眼小...