C++ com编程学习详解

目录
  • COM简介
  • COM 规范
  • 首先创建一个ATL工程,创建后你会看到一个idl文件
  • COM 原理学习
  • ActiveX
  • 总结

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文件信息。

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会自动产生相关语法到文件中

同时会创建对应的头文件和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下轻松的创建对应控件,然后在其他工程插入即可

总结

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

(0)

相关推荐

  • C++ COM编程之QueryInterface函数(一)

    前言 组件对外公布的是接口:一个组件可以实现多个接口,也就是说可以对外公布多个接口,之前也总结过了,你很少会100%的去完全了解一个组件的所有接口,就像你去学习编程一样,你几乎不可能去成为编程中的全才.那么,既然我们不能去完全的了解一个组件提供的所有接口,那么我们在实际开发中,如何去判断一个组件是否提供对应的接口呢?看文档?是的,是个好主意,在文档的海洋,找到一个知识点,真的很难,浪费时间和精力:其实,组件本身就提供对自己查询的一个接口,让客户去询问组件,问它是否支持某个接口,在经过多次的这种询

  • C++ COM编程之QueryInterface函数(二)

    前言 在COM编程--认识组件中也总结了,COM是一个说明如何建立可动态互变组件的规范,它提供了为保证能够互操作,客户和组件应遵循的一些标准.而在实现和使用QueryInterface时,就需要去遵守一些规则,只有遵守了这些规则,才能是一个正确的COM组件:只有了解了这些规则,才能会真正的了解COM开发. QueryInterface的实现规则 实现QueryInterface需要遵从以下五条规则: 1.QueryInterface总是返回同一IUnknown指针 组件的实例只有一个IUnkno

  • C++ COM编程之什么是组件?

    什么是组件? 一个组件同一个微型应用程序类似,即都是已经编译.链接好并可以使用的了,应用程序就是由多个这样的组件打包而得到的.各定制的组件可以在运行时同其他组件连接起来以构成某个应用程序.在需要对应用程序进行修改或改进时,只需要将构成此应用程序的组件中的某个用新的版本替换掉即可. COM组件 COM,即组件对象模型,是一个说明如何建立可动态互变组件的规范,它提供了为保证能够互操作,客户和组件应遵循的一些标准. COM组件是以Win32动态链接库(DLLs)或可执行文件(EXEs)的形式发布的可执

  • C++ COM编程之什么是接口?

    什么是接口? 说到COM,就不得不说接口了:在进行COM开发的过程中,可以说,我一直都在和各种各样的接口打交道.那接口是什么?对于COM来说,接口是一个包含一个函数指针数组的内存结构,每一个数组元素包含的是一个由组件所实现的函数的地址:所以,对于COM,接口就是这样的一个内存结构,其它东西都是一些COM并不关心的实现细节. 在C++中,可以使用抽象基类来实现COM接口.由于一个COM组件可以支持任意数目的接口,因此对于组件,可以使用抽象基类的多重继承来实现它. 接口的好处 接口提供了两个不同对象

  • 详解C++元编程之Parser Combinator

    引子 前不久在CppCon上看到一个Talk:[constexpr All the things](https://www.youtube.com/watch?v=PJwd4JLYJJY),这个演讲技术令我非常震惊,在编译期解析json字符串,进而提出了编译期构造正则表达式(编译期构建FSM),现场掌声一片,而背后依靠的是C++强大的constexpr特性,从而大大提高了编译期计算威力. 早在C++11的时候就有constexpr特性,那时候约束比较多,只能有一条return语句,能做的事情只有

  • C++ COM编程之接口背后的虚函数表

    前言 学习C++的人,肯定都知道多态机制:多态就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.对于多态机制是如何实现的,你有没有想过呢?而COM中的接口就将这一机制运用到了极致,所以,不知道多态机制的人,是永运无法明白COM的.所以,在总结COM时,是非常有必要专门总结一下C++的多态机制是如何实现的. 多态 什么是多态?上面也说了,多态就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.现在通过代码,让大家切身的体会一下多态: 复制代

  • C++ com编程学习详解

    目录 COM简介 COM 规范 首先创建一个ATL工程,创建后你会看到一个idl文件 COM 原理学习 ActiveX 总结 COM简介 COM全程为component object model ,是一个二进制标准可以用于跨语言调用dll模块或者实现组件化以及复用.com不仅可以用在单个操作系统也可以用在跨服务上,在很多大型软件如wps,office你都会看到它的身影. 比如java中调用规范如下: JAVA COM编程 你可能会在电脑出现缺少dll情况,一种修复方式下载dll然后调用regsv

  • C语言如何与ARM汇编语言混合编程示例详解

    目录 一.ARM汇编语言简介 二.C语言调用汇编语言 1.无参数调用 2.有参数调用 三.汇编语言调用C语言 四.总结 五.参考文献 主要使用软件:keiL μVision5 一.ARM汇编语言简介 什么是汇编语言?汇编语言是任何一种适用于电子计算机.微处理器或其他可编程器件的低级语言.虽然被称为"低级语言",但是并不是说汇编语言真的"低级".特定的汇编语言和特定的机器语言指令集是一一对应的,不同平台之间不可直接移植.汇编语言主要包括传送指令.逻辑运算.移位指令.位

  • linux下的C\C++多进程多线程编程实例详解

    linux下的C\C++多进程多线程编程实例详解 1.多进程编程 #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main() { pid_t child_pid; /* 创建一个子进程 */ child_pid = fork(); if(child_pid == 0) { printf("child pid\n"); exit(0); } else { print

  • 基于php编程规范(详解)

    今天写这个是为了 提醒自己 编程过程 不仅要有逻辑 思想 还有要规范 代码 这样可读性 1.PHP 编程规范与编码习惯最主要的有以下几点: 1 文件说明 2 function 函数体说明 3 代码缩进 4 if省略 5 变量规范 6 命名规范 7 十行一注释 8 注释风格 9 开放关闭原则 2.文件说明 个人代码 -规范如下: <? /* +---------------------------------------------------------------------- + Title

  • C++中Socket网络编程实例详解

    C++中Socket网络编程实例详解 现在几乎所有C/C++的后台程序都需要进行网络通讯,其实现方法无非有两种:使用系统底层socket或者使用已有的封装好的网络库.本文对两种方式进行总结,并介绍一个轻量级的网络通讯库ZeroMQ.  1.基本的Scoket编程 关于基本的scoket编程网络上已有很多资料,作者在这里引用一篇文章中的内容进行简要说明. 基于socket编程,基本上就是以下6个步骤: 1.socket()函数 2.bind()函数 3.listen().connect()函数 4

  • java多线程编程技术详解和实例代码

     java多线程编程技术详解和实例代码 1.   Java和他的API都可以使用并发. 可以指定程序包含不同的执行线程,每个线程都具有自己的方法调用堆栈和程序计数器,使得线程在与其他线程并发地执行能够共享程序范围内的资源,比如共享内存,这种能力被称为多线程编程(multithreading),在核心的C和C++语言中并不具备这种能力,尽管他们影响了JAVA的设计. 2.   线程的生命周期 新线程的生命周期从"新生"状态开始.程序启动线程前,线程一直是"新生"状态:

  • C++ 中 socket编程实例详解

    C++ 中 socket编程实例详解 sockets(套接字)编程有三种,流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW):基于TCP的socket编程是采用的流式套接字.在这个程序中,将两个工程添加到一个工作区.要链接一个ws2_32.lib的库文件. 服务器端编程的步骤: 1:加载套接字库,创建套接字(WSAStartup()/socket()): 2:绑定套接字到一个IP地址和一个端口上(bind()): 3:将套接字设置为监听模式

  • nodejs中的异步编程知识点详解

    简介 因为javascript默认情况下是单线程的,这意味着代码不能创建新的线程来并行执行.但是对于最开始在浏览器中运行的javascript来说,单线程的同步执行环境显然无法满足页面点击,鼠标移动这些响应用户的功能.于是浏览器实现了一组API,可以让javascript以回调的方式来异步响应页面的请求事件. 更进一步,nodejs引入了非阻塞的 I/O ,从而将异步的概念扩展到了文件访问.网络调用等. 今天,我们将会深入的探讨一下各种异步编程的优缺点和发展趋势. 同步异步和阻塞非阻塞 在讨论n

  • Java并发编程之详解CyclicBarrier线程同步

    CyclicBarrier线程同步 java.util.concurrent.CyclicBarrier提供了一种多线程彼此等待的同步机制,可以把它理解成一个障碍,所有先到达这个障碍的线程都将将处于等待状态,直到所有线程都到达这个障碍处,所有线程才能继续执行. 举个例子:CyclicBarrier的同步方式有点像朋友们约好了去旅游,在景点入口处集合,这个景点入口就是一个Barrier障碍,等待大家都到了才一起进入景点游览参观. 进入景点后大家去爬山,有的人爬得快,有的人爬的慢,大家约好了山顶集合

  • Java并发编程之详解ConcurrentHashMap类

    前言 由于Java程序员常用的HashMap的操作方法不是同步的,所以在多线程环境下会导致存取操作数据不一致的问题,Map接口的另一个实现类Hashtable 虽然是线程安全的,但是在多线程下执行效率很低.为了解决这个问题,在java 1.5版本中引入了线程安全的集合类ConcurrentMap. java.util.concurrent.ConcurrentMap接口是Java集合类框架提供的线程安全的map,这意味着多线程同时访问它,不会影响map中每一条数据的一致性.ConcurrentM

随机推荐