本文摘自:http://www.vckbase.net/index.php/wv/1215
步骤2.1:建立一个工作区(WorkSpace)。
步骤2.2:在工作区中,建立一个 ATL 工程(Project)。示例程序叫 Simple1,并选择DLL方式,见图一。
图一、建立 ATL DLL 工程
步骤3.1:菜单 Insert\New ATL Object...(或者用鼠标右键在 ClassView 卡片中弹出菜单)并选择Object 分类,选中 Simple Object 项目。见图二。
图二、选择建立简单COM对象
步骤3.2:增加自定义类 CFun(接口 IFun) ,见图三。
图三、输入类中的各项名称
其实,我们只需要输入短名(Short Name),其它的项目会自动填写。没什么多说的,只请大家注意一下 ProgID 项,默认的 ProgID 构造方式为“工程名.短名”。
步骤3.3:填写接口属性,见图四。
图四、接口属性
图五、调出增加接口方法的菜单
图六、增加接口函数 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 组件设计与应用(七)》。