C++ com编程学习详解

 更新时间:2021年09月22日 16:35:56   作者:不会写代码的丝丽  
这篇文章主要介绍了C++ COM编程的学习过程,在C++中,可以使用抽象基类来实现COM接口,需要的朋友可以参考下,希望能够给你带来帮助

COM简介

COM全程为component object model ,是一个二进制标准可以用于跨语言调用dll模块或者实现组件化以及复用。com不仅可以用在单个操作系统也可以用在跨服务上,在很多大型软件如wps,office你都会看到它的身影。

比如java中调用规范如下:

JAVA COM编程

你可能会在电脑出现缺少dll情况,一种修复方式下载dll然后调用regsvr32.exe xxx.dll即可修复。

在这里插入图片描述

上面便是COM组件的注册,本质是把这个dll信息注册到注册表中,以便其他系统软件可以加载。

flutter也提供相关接口封装flutter相关文档链接

本文主要介绍c++下使用com规范编程。

为什么需要COM?仅仅是为调用dll何必引用一个如此复杂的概念?

1.假设某个exe升级其中一个dll想要仅发布dll而不是是发布主体文件,在大多数情况下是没有任何问题的。但是在不同编译器编译(或者同编译器不同版本)出的主体exe和dll是有可能出现内存布局上的差异引起的奔溃。startoverflow上的一个经典问题

2.跨语言调用,比如c语言以\0结束,但是不是所有语言字符串定义都是如此。

3.跨进程或者跨服务上调度dll函数

4.dll代码复用 与共享

COM 规范

com使用idl文件去定义dll函数或者接口,之后用midl编译器生产对应的头文件,开发者再利用其去实现接口。

接口有自己的标识符号IID 防止与其他人的接口在名字上冲突.

在这里插入图片描述

编译后的某个头文件你会看到IID_XXXXX 如下所示

在这里插入图片描述

如果说IID是为了标识一个接口,那么应该还有一个ID去用于标识实现类,这个实现类的id我们称为CLSID,CLSID会在注册表映射一个dll信息,也就是我们可以用个这个CLSID可以在注册表中寻找到dll文件信息。

s在这里插入图片描述

tip:一个实现类可能会包含多个接口

更多idl语法可以参阅官方指南:

https://docs.microsoft.com/en-us/windows/win32/com/defining-com-interfaces

https://bbs.csdn.net/topics/30094944?list=34484

使用ATL编写一个com共享dll库 使用管理员权限运行vs(编译dll会自动调用regsvr32注册到注册表,但是需要权限)

首先创建一个ATL工程,创建后你会看到一个idl文件

在这里插入图片描述

新建一个接口如下:

在这里插入图片描述

在这里插入图片描述

上面ProgId一个可选项,它的作用是提供了另一种方式寻找注册过的dll。

在这里插入图片描述

完成后我们的IDL会自动产生相关语法到文件中

s在这里插入图片描述

同时会创建对应的头文件和c文件如下

在这里插入图片描述

此时我们到类视图添加一个接口方法

在这里插入图片描述

添加后idl同样会如下图所示生产对应的语法

在这里插入图片描述

对应的c文件自行实现接口(最后一个参数作为返回参数)

在这里插入图片描述

编译后会产生 工程名_i.c和工程名.h文件,并且自动会将dll注册注册表中。

将上诉两个文件拷贝其他使用工程中(注意我们并没有拷贝dll)如下图所示:

在这里插入图片描述

然后再调代码如下所示调用:

#include <iostream>
#include"FMYALTFOUR_i.h"
int main()
{
	//初始化
	CoInitialize(NULL);
	IClassFactory *pFactory = NULL;
	//通过CLSID从注册表中查到dll位置并加载 然后返回一个类工厂
	HRESULT hr = CoGetClassObject(CLSID_IfmyMathHelper,CLSCTX_INPROC_SERVER,
		NULL,
		IID_IClassFactory, (void**)&pFactory
		);
	//利用类工厂得到一个接口实例化对象
	IIfmyMathHelper * pSuperMath = NULL;
	pFactory->CreateInstance(NULL, IID_IIfmyMathHelper, (void**)&pSuperMath);
	long ret;
	pSuperMath->add(1, 2, &ret);
	//反初始化
	CoUninitialize();
}

当然这是其中一种调用方式,还有一种是预留给vb这类语言调用的实现这种方式你不需要拷贝上诉两个文件,但是创建接口必须勾选接口双重。

int main()
{
	//初始化
	CoInitialize(NULL);
	HRESULT hr;
	GUID clsid;
	IUnknown FAR* punk;
	IDispatch FAR* pdisp = (IDispatch FAR*)NULL;
	//通过progId反向查找出clsid 去加载dll
	hr = CLSIDFromProgID(OLESTR("progIdfmyMathHelper.1"), &clsid);
	IDispatch* pDispatch = NULL;
	hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDispatch, (void**)&pDispatch);
	LPOLESTR szMember[1] = { (LPOLESTR)OLESTR("add") };
	DISPID dipid[1] = { 0 };
	hr=pDispatch->GetIDsOfNames(IID_NULL, szMember, 1, LOCALE_USER_DEFAULT, dipid);
	CComVariant vars[2];
	DISPPARAMS args = { NULL,NULL,0,0 };
	vars[0] = 2;
	vars[1] = 1;
	args.cArgs = 2;
	args.rgvarg = vars;
	CComVariant Ret;
	hr=pDispatch->Invoke(dipid[0], IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD,
		&args, &Ret,NULL,NULL
		);
	std::cout << "Hello World!\n" << Ret.lVal;
	//反初始化
	CoUninitialize();
}

COM 原理学习

regsvr32.exe xxx.dll 本质作用会加载dll然后调用如下几个函数,dll应该根据规范在对应函数中实现对应的逻辑(比如DllRegisterServer中应当实现注册信息到注册表中)

在这里插入图片描述

上面几个函数在你创建atl工程的def文件可以看到.

我们接下来看看注册表中的信息,dll首先会利用CLSID的数值在如下注册表路径创建对应的信息
计算机\HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{xxxxxxxxxxx}

在这里插入图片描述

在这里插入图片描述

如果ProgId会在如下图位置创建额外的信息,主要用于提供其他方式寻找到dll信息。

在这里插入图片描述

其中32位系统和64系统可能路径有所不同可以参考如下链接所示

How to use the Regsvr32 tool and troubleshoot Regsvr32 error messages

自己模拟atl的实现代码: https://github.com/Zjvngvn/studyCom.git

ActiveX

ActiveX也是基于Com实现的一个UI组件库。你可以在ATL下轻松的创建对应控件,然后在其他工程插入即可

在这里插入图片描述

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

相关文章

  • C++11原子操作详解

    C++11原子操作详解

    这篇文章主要为大家介绍了C++的原子操作,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-11-11
  • C++实现STL迭代器萃取的示例代码

    C++实现STL迭代器萃取的示例代码

    迭代器是一种抽象的设计概念,它提供了一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表述方式。本文主要介了STL迭代器萃取的方法,需要的可以参考一下
    2022-11-11
  • C++简单五子棋的AI设计实现

    C++简单五子棋的AI设计实现

    这篇文章主要为大家详细介绍了C++简单五子棋的AI设计实现,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-09-09
  • C语言数组全面总结梳理

    C语言数组全面总结梳理

    在C语言和C++等语言中,数组元素全为指针变量的数组称为指针数组,指针数组中的元素都必须具有相同的存储类型、指向相同数据类型的指针变量。指针数组比较适合用来指向若干个字符串,使字符串处理更加方便、灵活
    2022-02-02
  • Matlab实现读写txt文件数据与进制转换

    Matlab实现读写txt文件数据与进制转换

    这篇文章主要为大家详细介绍了Matlab实现读写txt文件数据与进制转换的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-12-12
  • C++排序算法之选择排序解析

    C++排序算法之选择排序解析

    这篇文章主要介绍了C++排序算法之选择排序解析,遍历数组选择找到最大值,记录最大值下标maxindax,然后将最大值与最后一个值交换, 在剩下的待排序数组中,重新找到最大值,重复第一步,循环操作,直至数组排序完成,需要的朋友可以参考下
    2023-10-10
  • C语言实现随机生成6位数密码

    C语言实现随机生成6位数密码

    这篇文章主要为大家详细介绍了如何使用C语言实现一个简单而实用的随机密码生成器,该生成器将生成包含字母、数字和特殊字符的随机密码,有需要的小伙伴可以参考下
    2023-11-11
  • Qt编写地图实现闪烁点图的示例代码

    Qt编写地图实现闪烁点图的示例代码

    闪烁点图的核心有三个要素,城市的名称、城市的经纬度、对应值的大小,当值越大闪烁点也就越大,本文就来实现一下地图闪烁点图,具有一定的参考价值,感兴趣的可以了解一下
    2021-12-12
  • C语言基础 strlen 函数

    C语言基础 strlen 函数

    这篇文章主要介绍了C语言基础 strlen 函数,在C 语言中,char 字符串也是一种非常重要的数据类型,我们可以使用 strlen 函数获取字符串长度,这就是C语言strlen 函数的作用,下面我们来简单介绍该内容,需要的朋友可以参考以下
    2021-10-10
  • C++ 轻量级对象JSON序列化实现详情

    C++ 轻量级对象JSON序列化实现详情

    本文以jsoncpp库为基础,设计这样一个可以支持一个函数 可以一行代码 unmarshal /marshal 对象,需要的朋友小伙伴可以参考以下
    2021-09-09

最新评论