建立 ATL 工程

步骤2.1:建立一个工作区(WorkSpace)。

步骤2.2:在工作区中,建立一个 ATL 工程(Project)。示例程序叫 Simple1,并选择DLL方式,见图一。

图一、建立 ATL DLL 工程

Dynamic Link Library(DLL) 表示建立一个 DLL 的组件程序。

Executable(EXE) 表示建立一个 EXE 的组件程序。

Service(EXE) 表示建立一个服务程序,系统启动后就会加载并执行的程序。

Allow merging of proxy/stub code 选择该项表示把“代理/存根”代码合并到组件程序中,否则需要单独编译,单独注册代理存根程序。代理/存根,这个是什么概念?还记得我们在上回书中介绍的吗?当调用者调用进程外或远程组件功能的时候,其实是代理/存根负责数据交换的。关于代理/存根的具体变成和操作,以后再说啦......

Support MFC 除非有特殊的原因,我们写 ATL 程序,最好不要选择该项。你可能会说,如果没有MFC的支持,那CString怎么办呀?告诉你个秘密吧,一般人我都不告诉他,我后半辈子就靠着这个秘密活着了:

1、你会STL吗?可以用 STL 中的 string 代替;

2、自己写个 MyString 类,嘿嘿;

3、悄悄地、秘密地、不要告诉别人(特别是别告诉微软),把 MFC 中的 CString 源码拿过来用;

4、使用 CComBSTR 类,至少也能简化我们字符串操作;

5、直接用 API 操作字符串,反正我们大家学习 C 语言的时候,都是从这里干起的。(等于没说,呵呵)

Support MTS 支持事务处理,也就是是否支持 COM+ 功能。COM+ 也许在第 99 回介绍吧。

三、增加 ATL 对象类

步骤3.1:菜单 Insert\New ATL Object...(或者用鼠标右键在 ClassView 卡片中弹出菜单)并选择Object 分类,选中 Simple Object 项目。见图二。

图二、选择建立简单COM对象

Category Object 普通组件。其中可以选择的组件对象类型很多,但本质上,就是让向导帮我们默认加上一些接口。比如我们选 "Simple Object",则向导给我们的组件加上 IUnknown 接口;我们选 "Internet Explorer Object",则向导除了加上 IUnknown 接口外,再增加一个给 IE 所使用的 IObjectWithSite 接口。当然了,我们完全可以手工增加任何接口。

Category Controls ActiveX 控件。其中可以选择的 ActiveX 类型也很多。我们在后续的专门介绍 ActiveX 编程中再讨论。

Category Miscellaneous 辅助杂类组件。

Categroy Data Access 数据库类组件(我最讨厌数据库编程了,所以我也不会)。

步骤3.2:增加自定义类 CFun(接口 IFun) ,见图三。

图三、输入类中的各项名称

其实,我们只需要输入短名(Short Name),其它的项目会自动填写。没什么多说的,只请大家注意一下 ProgID 项,默认的 ProgID 构造方式为“工程名.短名”。

步骤3.3:填写接口属性,见图四。

图四、接口属性

Threading Model 选择组件支持的线程模型。COM 中的线程,我认为是最讨厌,最复杂的部分。COM 线程和公寓的概念,留待后续介绍。现在吗......大家都选 Apartment,它代表什么那?简单地说:当在线程中调用组件函数的时候,这些调用会排队进行。因此,这种模式下,我们可以暂时不用考虑同步的问题。(注1)

Interface 接口基本类型。Dual 表示支持双接口(注2),这个非常 非常重要,非常非常常用,但我们今天不讲。Custom 表示自定义借口。切记!切记!我们的这第一个 COM 程序中,一定要选择它!!!!(如果你选错了,请删除全部内容,重新来过。)

Aggregation 我们写的组件,将来是否允许被别人聚合(注3)使用。Only 表示必须被聚合才能使用,有点类似 C++ 中的纯虚类,你要是总工程师,只负责设计但不亲自写代码的话,才选择它。

Support ISupportErrorInfo 是否支持丰富信息的错误处理接口。以后就讲。

Support Connection Points 是否支持连接点接口(事件、回调)。以后就讲。

Free Threaded Marshaler 以后也不讲,就算打死你,我也不说!(注4)

四、添加接口函数

图五、调出增加接口方法的菜单

图六、增加接口函数 Add

图七、增加接口函数 Cat

请严格按照图六的方式,增加Add()函数;由于图七中增加Cat()函数的参数比较长,我没有适当的输入空格,请大家自己输入的时候注意一下。[in]表示参数方向是输入;[out]表示参数方向是输出;[out,retval]表示参数方向是输出,同时可以作为函数运算结果的返回值。一个函数中,可以有多个[in]、[out],但[retval]只能有一个,并且要和[out]组合后在最后一个位置。(注5)

图八、接口函数定义完成后的图示

我们都知道,要想改变 C++ 中的类函数,需要修改两个地方:一是头文件(.h)中类的函数声明,二是函数体(.cpp)文件的实现处。而我们现在用 ATL 写组件程序,则还要修改一个地方,就是接口定义(IDL)文件。别着急 IDL 下次就要讨论啦。

由于 vc6.0 的BUG,导致大家在增加完接口和接口函数后,可能不会向上图(图八)所表现的样式。解决方法: 

1 关闭工程,然后重新打开 该方法常常有效
2 关闭 IDE,然后重新运行  
3 打开 IDL 文件,检查接口函数是否正确,如不正确请修改  
4 打开 IDL 文件,随便修改一下

(加一个空格,再删除这个空格),然后保存
该方法常常有效
5 打开 h/cpp 文件,检查函数是否存在或是否正确,有则改之 无则嘉勉,不说完这个成语心理别扭
6 删除 IDL/H/CPP 中的接口函数,然后 再来一遍
7 重新建立工程、重新安装vc、重新安装windows、砸计算机 砸!

五、实现接口函数

鼠标双点图八中CFun\IFun\Add(...)就可以开始输入函数实现了:

1.STDMETHODIMP
CFun::Add(
long n1, long n2, long *pVal)
2.{
3.*pVal
= n1 + n2;
4. 
5.return S_OK;
6.}

这个太简单了,不再浪费“口条”。下面我们实现字符串连接的Cat()函数:

01.STDMETHODIMP
CFun::Cat(BSTR s1, BSTR s2, BSTR *pVal)
02.{
03.int nLen1
= ::SysStringLen( s1 );   
//
s1 的字符长度
04.int nLen2
= ::SysStringLen( s2 );   
//
s2 的字符长度
05. 
06.*pVal
= ::SysAllocStringLen( s1, nLen1 + nLen2 );   
//
构造新的 BSTR 同时把 s1 先保存进去
07.if(
nLen2 )
08.{
09.::memcpy(
*pVal + nLen1, s2, nLen2 * 
sizeof(WCHAR)
);   
//
然后把 s2 再连接进去
10.//     
wcscat( *pVal, s2 );
11.}
12. 
13.return S_OK;
14.}

学生:上面的函数实现,完全是调用基本的 API 方式完成的。

老师:是的,说实话,的确比较烦琐。

学生:我们是用memcpy()完成连接第二个字符串功能的,那么为什么不用函数 wcscat()那?

老师:多数情况下可以,但你需要知道:由于BSTR包含有字符串长度,因此实际的BSTR字符串内容中是可以存储L''\0''的,而函数 wcscat() 是以L''\0''作为复制结束标志,因此可能会丢失数据。明白了吗?

学生:明白,明白。我看过《COM 组件设计与应用(三)之数据类型》后就明白了。那么老师,有没有简单一些的方法那?

老师:有呀,你看......

01.STDMETHODIMP
CFun::Cat(BSTR s1, BSTR s2, BSTR *pVal)
02.{
03.CComBSTR
sResult( s1 );
04.sResult.AppendBSTR(
s2 );
05. 
06.*pVal
= sResult.Copy();
07.// 
*pVal = sResult.Detach();
08. 
09.return S_OK;
10.}

学生:哈哈,好!使用了 CComBSTR,这个就简单多了。CComBSTR::Copy()和CComBSTR::Detach()有什么区别?

老师:CComBSTR::Copy() 会制造一个 BSTR 的副本,另外CComBSTR::CopyTo()也有类似功能。而CComBSTR::Detach()是使对象与内部的 BSTR 指针剥离,这个函数由于没有复制过程,因此速度稍微快一点点。但要注意,一但剥离后,就不能再使用该对象啦。

学生:老师,您讲的太牛啦,我对您的敬仰如巍巍泰山,直入云霄......

老师:STOP,STOP!留作业啦......

1、自己先按照今天讲的内容写出这个组件;

2、不管你懂不懂,一定要去观察 IDL 文件,CPP 文件;

3、编译后,看都产生了些什么文件?如果是文本的文件,就打开看看;

4、下载本文的示例程序(vc6.0版本)编译运行,看看效果。然后预习一下示例程序中的调用方法;

学生:知道啦,快下课吧,我要上厕所,我都憋的不行了......

老师:下课!别忘了顶我的帖子呀......

六、小结

本回介绍第一个ATL组件程序的建立步骤,而如何使用该组件,敬请关注《COM 组件设计与应用(七)》。

注1:Apartment,系统通过隐藏的窗口消息来排队组件调用,因此我们可以暂时不考虑同步问题。注意,是暂时哈。

注2:双接口表示在一个接口中,同时支持自定义接口和 IDispatch 接口。以后,以后,以后就讲。因为双接口非常重要,我们以后会天天讲、夜夜讲、常常讲------简称“三讲”:)

注3:组件的重用方法有2个,聚合和包容。

注4:名称的功能很好听,但微软根本就没有实现。

注5:这些都是 IDL 文件中的概念,以后用到什么,就介绍什么。

com学习(四)——用 ATL 写第一个组件的更多相关文章

  1. com学习(四)2——用 ATL 写第一个组件(vs2003)

    步骤2.1:建立一个解决方案. 步骤2.2:在 该解决方案中,新建一个 vc++ 的 ATL 项目.示例程序叫 Simple2,并选择DLL方式,见图一.图二. 图一.新建 ATL 项目 图二.选择非 ...

  2. 【转载】COM 组件设计与应用(六)——用 ATL 写第一个组件

    原文:http://vckbase.com/index.php/wv/1216.html 一.前言 1.与 <COM 组件设计与应用(五)>的内容基本一致.但本回讲解的是在 vc.net ...

  3. 【转载】COM 组件设计与应用(五)——用 ATL 写第一个组件

    原文:http://vckbase.com/index.php/wv/1215.html 一.前言 1.如果你在使用 vc5.0 及以前的版本,请你升级为 vc6.0 或 vc.net 2003: 2 ...

  4. hibernate学习四(关系映射一对一与组件映射)

    一.关系映射简介 在数据库中,表与表的关系,仅有外键.但使用hibernate后,为面向对象的编程,对象与对象的关系多样化:如 一对一,一对多,多对多,并具有单向和双向之分. 开始练习前,复制上一次项 ...

  5. 孤荷凌寒自学python第七十四天开始写Python的第一个爬虫4

    孤荷凌寒自学python第七十四天开始写Python的第一个爬虫4 (完整学习过程屏幕记录视频地址在文末) 今天在上一天的基础上继续完成对我的第一个代码程序的书写. 直接上代码.详细过程见文末屏幕录像 ...

  6. java之jvm学习笔记五(实践写自己的类装载器)

    java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...

  7. (转)SpringMVC学习(四)——Spring、MyBatis和SpringMVC的整合

    http://blog.csdn.net/yerenyuan_pku/article/details/72231763 之前我整合了Spring和MyBatis这两个框架,不会的可以看我的文章MyBa ...

  8. day 83 Vue学习四之过滤器、钩子函数、路由、全家桶等

    Vue学习四之过滤器.钩子函数.路由.全家桶等   本节目录 一 vue过滤器 二 生命周期的钩子函数 三 vue的全家桶 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 Vue的过滤 ...

  9. TweenMax动画库学习(四)

    目录            TweenMax动画库学习(一)            TweenMax动画库学习(二)            TweenMax动画库学习(三)            Tw ...

随机推荐

  1. php安装redis扩展

    1.windows安装redis扩展 php_redis.dll (for windows) 的下载地址:http://windows.php.net/downloads/pecl/snaps/red ...

  2. Saltstack系列6:Saltstack之state

    state功能 state是Saltstack最核心的功能,通过预先定制好的sls(salt state file)文件对被控制主机进行状态管理,支持包括程序包(pkg).文件(file).网络配置( ...

  3. RPM Fusion on CentOS7

    RPM Fusion RPM Fusion provides software that the Fedora Project or Red Hat doesn't want to ship. Tha ...

  4. 黄聪:wordpress自定义post_type,并且自定义固定链接

    <? class zsjh { function init() { add_action( 'init', array($this,'create_zsjh') ); add_filter('p ...

  5. Flink on Yarn运行机制

    从图中可以看出,Yarn的客户端需要获取hadoop的配置信息,连接Yarn的ResourceManager.所以要有设置有 YARN_CONF_DIR或者HADOOP_CONF_DIR或者HADOO ...

  6. Linq常用操作

    http://www.cnblogs.com/knowledgesea/p/3897665.html

  7. linux ps命令(转载)

    来源:http://www.cnblogs.com/peida/archive/2012/12/19/2824418.html Linux中的ps命令是Process Status的缩写.ps命令用来 ...

  8. 有人向我反馈了一个bug

    我是一个前端开发者,但我想这个故事对任何开发者都会引起共鸣的有人向你反馈了一个 bug. “26 楼会议室的灯亮着.它需要被熄灭.”bug 的备注里写道“你应该能在 5 分钟内搞定,只要按一下开关就好 ...

  9. android 技术相关Blog

    android 技术相关 LVXIANGAN的专栏 http://blog.csdn.net/LVXIANGAN/article/category/1101038 Android NFC 开发实例 h ...

  10. 采访ServiceStack的项目领导Demis Bellot——第1部分(转)

    ServiceStack是一个开源的.支持.NET与Mono平台的REST Web Services框架.InfoQ有幸与Demis Bellot深入地讨论了这个项目.在这篇两部分报道的第1部分中,我 ...