在COM1 的小例子中,,我们大概知道什么是组件类 ,什么是接口了。这小节呢,我们来实现一下由一个组件类去实现两个接口的过程。
新建项目:
我们的 解决方案的 名字是 ComDemoCode ,项目名字是 MathToolKit 这表示 我们的 项目 自动 生成的 DLL 的名字就是 MathToolKit(数学工具包)。
我们的继承关系 有必要 给大家 先 列出来,让大家 看看
在这里面,IPrimerMath接口 提供 + - * / % 五个基本运算方法,IAdvanceMath接口提供求阶乘方法。
由 CMathTool 去实现 上面的 六个方法 。
点击下一步,
默认选中的就是 动态链接库,我们直接点击 Finish。
项目创建完后,我们可以看到出现了两个项目,其中带有 PS 字样的 项目 我们暂时用不到,所以直接在它上面右击,选择 Remove 即可。
然后我们的项目就变成下面这个样子啦。
然后我们将视频切换到类视图。
在类视图的 项目 名字上 右击 选择添加 类
选择 ATL Simple Object ,点击 Add ,弹出如下所示向导。
然后在 Short name 里写上 MathTool ,然后我们就会发现其它编辑框的内容都同时发生了变化,见下图。下图所示上半部分比较好理解,就是我们用C++的类方式来实现一个组件类,然后这个C++对应的类的名字就是 Class里面的名字,一般就是 Short name 前面加上一个 C,.h file 和 .cpp file 就是针对 这个类所需要的 头文件和源文件的文件名。下半部分中的 Coclass 就是用来指定我们的组件类的名字,叫MathTool,右边两个我们暂时不关心,如果想要明白,大家把我的这个例子做个 10 遍,每次都重新开始,然后再去看 COM 本质论 等理论书 就容易点啦,右边的东西也就明白啦。Interface 在下面介绍。
Interface用来指定我们的组件需要实现什么接口,上面我们已经说了要实现 IPrimerMath和IAdvanceMath,所以先将第一个接口改为 IPrimerMath
然后点击 Next。
此图中的 Interface 一定要选择 Custom ,暂时不要问为什么。一切都要从简单起步。
然后点击Finish ,可以看到 类视图如下图
这样,我们就定义了一个接口,只是这个接口没有定义方法而以,下面我们为这个接口添加方法。
在类视图中的 IPrimerMath 接口上 右击 ,选择 Add --> Add Method,然后弹出下图。
然后,我们可以看到这里面,有Method name, 就是 函数名啦。
Parameter attributes: 参数属性
in 表示 是 输入参数
out 表示是 输出参数
retval 表示 是返回参数 (Out 和 retval 默认是不可以用的,只有将 Parameter type 修改为 某种类型的指针时才可以 启用它们,因为只能用指针往外带数据,而且选中 retval 后,out就会自动选中)。
添加第一个参数,in LONG n1
添加第二个参数 in LONG n2
添加第三个参数: retval & out LONG * nResult
然后点击 Next
一切默认即可,然后点击 Finish
然后我们打开项目中唯一的 .IDL 的文件,或者 直接在 类视图中 双击 IPrimerMath 接口 ,
我们可以看到一段语句,我们先从 结构上 下手,我们要 知道 ,上图中选中部分才是一个整体。
[] 内是 一部分,下面是 另一部分。其中下半部分定义了一个 Add 方法。所以,如果我们想要继续添加方法,可以直接复制这一行的数据,然后粘贴,只要改改函数名字及参数就可以了哦。
好了,其实这就是一个 接口的 描述啦。然后再打开 MathTool.h ,我们再看一下 我们的 Add 函数的声明,如下图 :
好,下面我们继续为这个接口添加更多的 接口函数,如下图:
好,我们又添加了四个函数,然后在 我们的 C++ 类中 对 四个新添加的 函数 进行 函数声明。
好,函数也声明了,下面去实现这五个函数(当然是在源文件里啦),为了 布局,我没有进行 算法异常检测。
这样就将 IPrimerMath 这个接口 提供的五个 函数 实现 了。。
下面,我们要 回忆一下我们前面的 要求,我们是要 用一个 COM组件类 ,实现 多个 接口 。
所以,我们下一步的 工作 就是 为这个 组件类 添加 多个接口。
1、接口描述
直接在 IDL 文件中 将 IPrimerMath 这个接口的内容 复制,然后 粘贴,进行修改就行了,如下图
我们可以看到,我修改了接口名字,添加了注释说明,还 对接口提供的 函数 进行了 增删改操作,更重要的一点是,uuid() 里面的值要进行修改,这个值可以 直接 利用 Tools 菜单下的 Create GUID 工具进行获取,如下图,选择 4号,然后点击 New GUID,然后点击 Copy,再把数据 粘贴到 uuid()里面,然后进行稍微的修改就可以了。
是不是这样就可以了呢?答案是肯定不行的,最起码我们得让 我们的 C++类 去继承 我们新提供的这个接口,并对新接口提供的方法 进行声明 及 实现。
1、继承前
2、继承后
下面是 函数声明 及 实现
声明部分:
实现部分:
那么是不是上面的东东都搞定了就OK了呢?还不行呢,哈哈,还有两个步骤,就可以成功了。
1、我们要先去看看 我们的组件类的 描述 是怎么描述的
我们很明显的可以看到 47 -- 50 行,是描述我们的 组件类的,,这里面只有一个 IPrimerMath,其实我们这个组件类是实现了 两个接口哦,所以这里要再添加一个接口
好,OK了,,那么还有哪一步呢?最后一步就更简单了,先说一下,它的功能,它的功能是帮我们自动完成 接口查询 及 引用计数等 麻烦事项的,也就是说,我们可以利用 IPrimerMath 这个 接口通过查询函数 获取 IAdvanceMath 接口,反过来也就一样的,我们后面会有Demo 程序的。。
那么怎么完成这个功能呢?在 组件类的 头文件中,有一个 映射宏
然后我们要再添加上我们的 IAdvanceMath 接口的映射,就完成了所有的功能啦。
好了,现在点击生成吧,,然后 大家可以 找到 下图所示的程序
然后点击下图所示图标
然后我们打开我们项目生成的 DLL,可以看到里面有一个组件类 MathTool,有两个接口 IPrimerMath和 IAdvanceMath。
然后展开节点,查看更多信息,可以看到跟我们设计前的想法是一样的。
下面,我们就为当前解决方案添加新的项目,
这里只要选中 Active Accessibility 即可,它主要是完成对 COM 库的 初始化 及收尾工作。
然后为对话框添加一个按钮,并响应
一个解决方案只有一个项目的时候,当我们点击运行时,它会自动调用我们的项目程序,但是当有多个项目时,这个时候VS就不知道要调用哪一个啦,我们需要给它指定一个,通过下图,我们可以看到 一个项目字体是粗黑体,意思就是说 当我们点击 调试或者运行的时候就会启动这个程序,我们可以在项目上右击,来更改启动项目 ,这个不难,自己摸摸吧。
改好后,如下图。
程序运行效果如下图
点击按钮,弹出对话框,我们可以看到都算对啦。
这就证明我们的组件是可以的哦。
如果你会C#,你也可以用C#来调用哦。
然后我们这个时候再看这个继承图是不是很容易理解啦
这里我要讲解一下 我们的 CODE 啊,不然大家还是不明白啊。
再把 CODE 贴一次吧
好,组件类 提供的 方法 并不能直接 通过 组件类 来进行调用 ,必须要使用 接口去调用 ,也就是说如果我们调用 Add 方法 就必须 要 先获取 IPrimerMath 接口,那么怎么获取这些接口呢?
就是创建一个组件类 实例, 98 行的函数 就是 这个功能,创建一个组件类的 实例,第一个参数 是我们的 组件类的 唯一标识(CLSID),它是非常有规律的哦,CLSID_组件类的名字,第二三参数需要大家看COM原理方面的书来理解,第四个参数,就是指定接口ID,最后就是用来接收接口指针的啦。然后我们就可以调用这个接口的方法啦,然后这个接口还可以通过 106行的 函数来获取 同一个 COM组件类提供的 其它的 接口指针,以用来调用其它接口提供的方法,最后我们要将获取的接口 释放,调用的是接口的 Release() 方法,116行的 代码是 指,如果某个组件类中的实例所提供的接口已经都被释放了,则将这个DLL 卸载出 进程的 地址空间。
关于接口ID及组件类ID的定义,我们可以查看 DLL 项目 中的
用这个例子,大家就可以练手啦,然后COM原理等书 看着也不是很难啦。
下面再说一些话。
很多人再给别人发一些源代码的时候 ,都是搞的 很大,几十M,甚至 上百M,其实这里的文件很多并没有用。
我先将我们这个解决方案的目录层次发上来吧。
这是我们的最顶层目录。
这是第二层目录
这是MathToolKit目录
这里面有许多文件都是跟用户相关,或者保存一些信息,在发源码时不需要发这些东西,比如:
所有的 Debug 目录下所有文件及此目录 ,所有的 Release 目录下所有文件及此目录 ,*.aps,*.ncb,
这里面显示的 VS2010图标的 文件,我们可以将鼠标放在它们上面,会有提示信息,一般是 写着与 User 有关,这些文件都是可以删除的。如果大家不放心,可以自己做实验,就是先把所有文件都压缩后做一个备份,然后一个一个的试。
其实这个小项目,压缩完成后,大小才 几十K,如下图
好了。结束。
代码我们上传的。