COM编程_第一讲_深入COM框架以及实现简单的COM

一丶我们要理解COM是什么(为什么理解)

现在很多人会用com(也就是ALT)但是不知道原理,如果改一点东西,那么整体的框架重来,因为你不懂改哪里,如果懂了,那么遇到问题,那么就会知道我要怎么做,是什么问题了

二丶什么是COM

COM是微软公司为了计算机工业的软件生产更加符合人类的行为方式开发的一种新的软件开发技术。在COM构架下,人们可以开发出各种各样的功能专一的组件,然后将它们按照需要组合起来,构成复杂的应用系统。由此带来的好处是多方面的:可以将系统中的组件用新的替换掉,以便随时进行系统的升级和定制;可以在多个应用系统中重复利用同一个组件;可以方便的将应用系统扩展到网络环境下;COM与语言,平台无关的特性使所有的程序员均可充分发挥自己的才智与专长编写组件模块;等等。 COM是开发软件组件的一种方法。组件实际上是一些小的二进制可执行程序,它们可以给应用程序,操作系统以及其他组件提供服务。开发自定义的COM组件就如同开发动态的,面向对象的API。多个COM对象可以连接起来形成应用程序或组件系统。并且组件可以在运行时刻,在不被重新链接或编译应用程序的情况下被卸下或替换掉。Microsoft的许多技术,如ActiveX, DirectX以及OLE等都是基于COM而建立起来的。并且Microsoft的开发人员也大量使用COM组件来定制他们的应用程序及操作系统。

好,这是百度的答案,很多人看了懵逼,简单来说

总结:

  1.COM是一种框架,我们可以利用这个框架,实现跨平台开发,比如你开发了一个COM,那么别的程序一样使用

  2.COM其实是二进制下的可执行的程序,可以给其他的程序使用

实现简单的COM从接口设计模式开始

什么是接口模式

1.接口模式就是我们不知道,但是当用户用的时候,才知道是什么类型,所以可以是已知的,规范一下接口即可.

简单来说:

  接口模式就是类似于U盘 插入到电脑上,中间的USB的那个接口,只要是支持这个接口的,都可以插入到电脑上

比如硬盘等等.

2.插件模式: 插件模式是未知的,比如用户怎么写你都是不知道的,所以定义好规范,让用户一一的实现你的插件的接口即可.

简单来说:

  简单来说就是为你的程序提供的扩展,如果用户实现了你自定义的接口,那么你的应用程序就可以支持这个功能了.所以插件和接口不要搞混

实现简单的COM以及思路

1.按照上面所说的,我们要实现COM那么就要有一个接口,这里我用C++来写了,

2.在写的过程中,我会依次的把为什么这样写,不能怎么写都会说清楚,最后开发一个跨语言使用的ATL(也就是COM)组件

3.下面的内容可能有点多,最后我会写总结,可以看下.虽然函数不多,就一个类,但是从底层讲起,为什么这么做所以比较多.

1.定义接口类

class IUnKnow
{
    public:
        virtual HRESULT QueryInterFace(const GUID& riid,void **ppObject) = 0;
        virtual ULONG AddRef() = 0;
        virtual ULONG Release() = 0;
}

首先将第一个接口中的函数

QueryInterFace,这个函数是查找我们的接口,根据查找的接口通过第二个OUT参数接受查询接口的实现类的对象

什么意思?(GUID下面讲解)

  其实就是我定义了一个新的接口类,继承了IUnKnow,这个新的接口类中有自己新添加的功能,而有一个类是实现了这个接口类,通过这个函数,可以找到实现类的对象,进而可以调用里面的方法(下面讲解)

为什么要这样写返回值,以及参数要这样写:

  想一下,如果我们返回值是void *的话是不是不需要第二个参数了,是不需要第二个参数了,但你保证所有的语言

  都会这样返回吗,显然是不会的,所以要统一接口,统一返回值(HRESULT)参数由第二个传出

AddRef() 引用计数 这个必须加,因为你想,如果我们每次查询是否存在就new一个对象,那样是不是太浪费了

所以搞个引用计数

Release();大家可能不同了,为什么释放资源要单独写一个Release()释放,这里请看下面讲解

接口的设计原则

1.接口一旦是定义好的,你的函数的顺序不能改变 为什么?

  因为接口的设计都是用的指针,都是虚表去查(虚表是什么,可以补一下C++的基础,简单来说就是通过虚函数来调用的)如果一单你的接口的顺序改变了,那么对应的虚表就会改变,

举个例子:

  比如你的插件(也就是咱们现在写的这个)有一个功能是Add(int n1,int n2,long *Result) (两个数相加)

你编译好了你的插件了,我的Client程序就可以使用了,使用的时候正常调用Add,返回的结果也就正确了,

如果有一天你有一个减法,正好放在的Add的前边,那么你的Client就会调用减法了,因为以前的那个位置是输入Add的这样就会出错了.

2.参数不能改变

  参数也是不能改变的,接口一点定义了,就不要动了.

3.兼容性

  什么是兼容性

  比如你的Client是老版本,用你编写的新插件,你的Add函数没有变,还是会依次调用你的函数,不影响使用.

但是你要反过来想,当你的Client是新版本的时候,调用你的旧的插件怎么办,比如你的旧的插件没有Sub函数

而你调用了是不是就出错了.

所以为了保证兼容,我们会新定义一个接口类,让以前的实现类继承新的接口类,而新的接口类继承以前的接口类

伪代码:

  新版本的插件要这样写

class InterFaceMathOld : IUnKnow
{
     virtual Add(...)     = 0;
}
class InterFaceMathNew : pulic InterFaceOld
{
    virtual Sub(....) = 0;
}
class CMath : public interfaceMathNew
{
    Query....(){}
    AddRef(){}
    Release(){}
    Add(...){}
    Sub(...){}
}

老版本的插件是这样写

class InterFaceMathOld : IUnKnow
{
     virtual Add(...)     = 0;
}

class CMath : public InterFaceOld
{
    Query....(){}
    AddRef(){}
    Release(){}
    Add(...){}
}

这些代码我都会写好,发到云盘中下载研究,如果连接过时了,请评论告知,或者QQ2510908331 这地方一定要细看,

我会一步步的吧Com从基本到高级的源码写出来,这样能熟悉一下COM的框架

接口设计的细节问题 (解决为什么要用Release)

1名称粉碎

.我们想一下,C语言的函数,看一下二进制或者DLL,是不是都是原本什么样子就是什么样子

C++的函数有一个语法支持重载了,内部怎么支持的重载,这就是一个问题

C++为了支持重载,会对你定义的函数做一个名称粉碎,也就是加了一些额外的符号,比如我们调试中都会遇到一种错误叫做,找不到外部符号  例如[email protected]当然我写的不准确,下面有一个帖子专门介绍,可以看看

http://www.cnblogs.com/zhugehq/p/5959360.html

不同的编译器它的名称粉碎是不一样的,这个是没有标准的,你说有重载,这个是标准可以,但是怎么实现的,没有标准

所以我们为什么要定义为纯虚函数,这样你要调用函数就直接通过虚表,去查找了,而不是找你的实现了,所以我们的接口没有重载,不能写任何重载的函数

从逆向角度说一下,为什么不支持重载,因为VC++6.0编译器,在建立虚表的时候,会根据函数的类型排序,上面的接口原则说了,不能影响顺序问题,所以不能写

2.多重继承问题

  a.多重继承会影响虚表的,一旦影响了虚表,就改变的接口的不变原则,(虚继承也是一样).

  b.不能有虚析构,如果你调用虚析构,VC++6.0会传入一个1,或者一个0(后台传入的,逆向角度)这个根据这个状态值去释放内存.

  而GCC是不一样的,他可以用数组的方式,反正都可以实现,那么这样也违反了接口的设计原则了.

总结:

  1.不能用多重继承(父类没有虚函数可以多重继承,不影响子类的虚表即可)

  2.不能用虚析构,如果释放内存,则用纯虚方法的Release()来释放内存

  3.不能有重载,重载会影响虚表

GUID简介

GUID是一种数据结构,在Windwos系统中可以通过guidgen命令来打开GUID,也可以通过API coCreateguid(查一下MSDN)我都是用windows自带的

作用: 我们第一个查找接口的函数中定义了Guid,这是为了我们查询接口准备的,每一个接口都会有一个GUID,guid是保证不重复的.

总结:

  说了怎么多,我们发现其实定义一个COM的接口很容易,就是2个接口,(IUnknow(顶级的接口类),Ixxx(你自己的接口类))和一个实现的接口类,我们就要说怎么多细节.当然这也是为了我们更加的理解COM的设计.

如有问题QQ:2510908331 论坛:www.w1x8.com 如果说的有错误,请指出,如果你有更好的建议,请评论说明,因为COM组件很老的,很多人会用,但是不懂,因为我们是逆向工程,所以需要熟悉COM框架,为了谁让更多人熟悉COM框架,请欢迎指出

时间: 2024-08-06 03:23:36

COM编程_第一讲_深入COM框架以及实现简单的COM的相关文章

ArcGIS for Desktop入门教程_第一章_引言 - ArcGIS知乎-新一代ArcGIS问答社区

原文:ArcGIS for Desktop入门教程_第一章_引言 - ArcGIS知乎-新一代ArcGIS问答社区 1 引言 1.1 读者定位 我们假设用户在阅读本指南前应已具备以下知识: · 熟悉Windows的基本操作 · 接触过地理信息系统的概念 · 理解地理数据的特点 1.2 预期效果 我们期望用户在阅读完本指南后对以下知识有一定的了解: · 了解ArcGIS for Desktop的组成与功能 · 熟悉使用ArcGIS for Desktop进行数据编辑.整饰和输出的流程 · 如何使用

C语言_第一讲_C语言入门

1.C语言是一个标准,而执行标准的时候产生的自动化程序则是编译器2.了解:1983年美国国家标准化歇会(ANSI)制定了C语言标准.C语言的特点:3.代码的可移植性(理想状态是代码可以不加修改,就可以移植,前提是不包括任何平台相关库)4.写代码的时候最好把业务逻辑层和UI层分开.这样便于代码的移植5.结构化编程(可以把问题分解成一个一个的函数去执行)6.丰富的数据类型(相对于汇编而言是丰富的)7.简洁高效的代码(这得看人,不是编译器的或者语言的特性,如果算法写的不好,一样执行速度慢,和语言无关.

算法第一讲_动态规划

转自follow your hearthttp://www.cnblogs.com/kkgreen/archive/2011/06/26/2090702.html 转载:http://blog.csdn.net/woshioosm/article/details/7438834{思考动态规划的第一点----最优子结构思考动态规划的第二点----子问题重叠思考动态规划的第三点----边界思考动态规划的第四点----子问题独立思考动态规划的第五点----做备忘录思考动态规划的第六点----时间分析步

Python笔记_第一篇_童子功_0.内存详解(含位运算)

Python的很多教材中并没有讲内存方面的知识,但是内存的知识非常重要,对于计算机工作原理和方便理解编程语言是非常重要的,尤其是小白,因此需要把这一方面加上,能够更加深入的理解编程语言.这里引用了C语言关于内容的详细讲解,其实很多知识都是相同的. 第一部分:程序(计算机运行)为什么需要内存? 对于内存的理解是对编程语言直接相关的,如果没有对内存有很深的认识的话,对于编程语言也就是没有根本的认识,编程语言跟内存有千丝万缕的联系. 1.1 计算机程序运行的目的 计算机为什么需要编程?编程已经编了那么

C语言_第二讲_规范以及常用数据类型

一丶编码规范基本数据类型 编码规范 任何程序员,都应该有良好的的编码习惯,便于以后的代码可读性和维护 常见了编码规范有 匈牙利命名法 驼峰式大小写 匈牙利命名法: 是电脑程序设计中的一种变量命名规则,此命名法又可细分为:系统匈牙利命名法和匈牙利应用命名法. 匈牙利命名法具备语言独立的特性,并且首次在BCPL语言中被大量使用.由于BCPL只有机器字这一种数据类型,因此这种语言本身无法帮助程序员来记住变量的类型.匈牙利命名法通过明确每个变量的数据类型来解决这个问题. 在匈牙利命名法中,一个变量名由一

构建之法_第一章_概论

刚拿到这本书时,我对于软件工程这个概念的理解是十分模糊的.敲代码,整合,发布,仅此而已.看完了本书的第一章,对于自己的天真与无知实在无法忍受.重新审视完自己,希望能借助邹欣老师的这本书真正走进软件设计这个领域,去完成一些富有挑战性和成就感的事情.摆脱学校的空洞知识,去看看这个真实世界是如何运转的. 第一章从整个体系组成上向我们展示了软件工程与软件,与程序的关系.异同: 程序 = 数据 + 算法: 软件 = 程序 + 软件工程: 软件企业 = 软件 + 商业模式. 软件工程一说在此区别于实际的代码

Python笔记_第一篇_童子功_5.Python数据类型之列表类型(list)

Python中序列是最基本的数据结构.序列中的每个元素都分配一个数字(他的位置或者索引),第一个索引是0,第二个索引是1,依次类推.Python的列表数据类型类似于C语言中的数组,但是不同之处在于列表数据类型可以包含任何类型的元素.列表示Python最常用的数据类型之一,他可以以作为一个方括号内的逗号分割值出现.像字符串一样也具有增删改查的操作.因此列表是一个有序集合. 注意:如果列表当中只有一个元素的时候,比如[12, ],需要加一个逗号.目的是一面误解成数学计算意义上的括号. 1.   列表

web前端_正式开发之路_第一周_总结

2016.11.07正式入职xx企业(暂时保密),岗位:web前端开发工程师. 作为从一个设计.美工转战到web前端开发岗位,当然,现在还处于试用期阶段,三个月的时间,不短吧,不知道是不是能顺利的通过这段时期,希望吧. 作为一个转行的人,可以说我的转行是历经曲折,经历了八九个月的时间,其中五味杂陈,只有自己知道自己经历了多么痛苦的时光,不过,还好吧,自己的选择,自己的兴趣,苦点累点倒不是很重要,重要的是现在自己进入了开发角色,无所谓薪水.工作时间等,只要是开发的工作就好,不要单纯的做个codin

读书笔记_深入理解计算机系统_第一章_计算机系统漫游

hello.c #incude <stdio.h> int main() { printf("Hello,world\n"); } 1.1信息就是位+上下文 系统所有的信息,都是由一串位表示的. 在不同的上下文中(可以理解为程序,或者运算),一个同样的字节序列可能表示一个整数,浮点数,字符串或者机器指令. 2.2程序被其他程序翻译成不同的格式 如Hello程序,从源文件hello.c中的每条C语句,需被其他程序转换为一系列低级语言(汇编)指令,然后将这些指令按照一种称为可执