来新公司学习接手新项目,拿到代码打开解决方案看到里面竟然有40几个工程,有点吃惊。具体看代码也有很多之前没见过的写法,上了几天火。
有件事就没太搞明白,按照文档的说法上层很多软件都要调用IO服务器,但看程序安装目录,IO服务器其实是一个exe程序,按照我之前的印象,能被别的程序调用的也得是动态库、静态库或者服务。实在想不通exe程序怎么作为接口被别的程序调用的。
结果昨天研究了一天,想通了,这个IO服务器其实就是COM组件。
按照网上的说法:COM component(COM组件)是微软公司为了计算机工业的软件生产更加符合人类的行为方式开发的一种新的软件开发技术。在COM构架下,人们可以开发出各种各样的功能专一的组件,然后将它们按照需要组合起来,构成复杂的应用系统。由此带来的好处是多方面的:可以将系统中的组件用新的替换掉,以便随时进行系统的升级和定制;可以在多个应用系统中重复利用同一个组件;可以方便的将应用系统扩展到网络环境下;COM与语言,平台无关的特性使所有的程序员均可充分发挥自己的才智与专长编写组件模块。
COM组件可以是dll或者exe或者服务的形式。
按照这个思路,代码就看懂了不少,之所以解决方案里有那么多工程,也不过是因为划分了很多动态库和COM组件。
又花了些时间,写了个小程序来实现最简单的exe形式COM组件的生成与调用,如下:
首先建立一个ALT工程:
在类视图里,为工程添加ALT的类,和接口:
这里定义了类,和对应的接口(Interface),注意ProgID要写,待会程序调用com接口时,要通过ProgID找com组件
之后项目目录如下,在.idl文件里有com接口(interface),里面还定义了com组件的id等等不赘述了,实现类在ATLTest.cpp里,其对应关系都是vs自动搭建的。
接下来还是在类视图里具体添加方法(接口和实现):
方法内部写程序,逻辑是两数求和:
STDMETHODIMP CCATLTest::ATLTestFunc0(SHORT num1, SHORT num2, SCODE* pRetNum) { *pRetNum = num1 + num2; return S_OK; }
然后编译会出错,那是因为执行com组件注册命令时候,缺乏管理员权限,
重新启动vs,以管理员权限运行即可。
接下来建一个mfc项目,这不是今天主题就不赘述了,
在界面上简单填个按钮和输入框,写个两数求和的图形界面demo,
具体的求和的方法要调用com组件。
mfc项目里添加com接口,在类向导里选择添加类,选atl,选TypeLib中的MFC类:
之后可以选取前面定义的Lib:
加入COM接口文件后,就可以调用了,注意我下面的写法:
void CATLMfcClientDlg::OnBnClickedGetRetButton() { CoInitialize(NULL); CATLTest myCom; if (!myCom.CreateDispatch(_T("ATLTest.math.1"))) { MessageBox(L"组件注册失败"); return; } CString strNum1,strNum2; // 获取用户输入的数字 this->numInput1.GetWindowTextW(strNum1); this->numInput2.GetWindowTextW(strNum2); // 调用COM接口,两数求和 short ret = myCom.ATLTestFunc0(_wtoi(strNum1),_wtoi(strNum2)); WCHAR buf[50]; _itow(ret,buf,10); // 显示结果 this->numRet.SetWindowTextW(buf); CoUninitialize(); return; }
运行效果:
上面有说的简略的地方,具体可以看我上传git的源码:
https://github.com/SonnAdolf/MyAtlExeComDemo
额外内容:
动态链接库和COM组件的区别
1动态链接库的表现形式只能是dll[变态该名的除外], COM组件的表现形式可以是dll也可以是exe。
注:其实字体、驱动等也算是动态链接库的一种,这里略去...
2 动态链接库的生成和编译器及系统相关,在Windows/Linux下系统,需要分别编译才能使用。
COM组件是二进制编码,在Windows和Linux下可以直接使用,不需要重新编译。
3 COM组件是按照COM规范实现的dll或者exe;动态链接库是一个可以导出函数的函数集合。
4 动态链接库只能在本机被调用,COM组件支持分布式使用。