if(0==m_cRef)
{
deletethis;
return0;
}
returnm_cRef;
}
//创建实例函数
IUnknown*CreateInstance()
{
IUnknown*pinte=static_cast(newCompA);
pinte->AddRef();
returnpinte;
}
//IIDs
constIIDIID_InteX=
{0x32bb832c,0xb41a,0x11cf,
{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}};
constIIDIID_InteY=
{0x32bb832d,0xb41a,0x11cf,
{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}};
constIIDIID_InteZ=
{0x32bb832e,0xb41a,0x11cf,
{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}};
//客户程序
intmain()
{
HRESULThr;
trace("客户:
获得IUnknown的一个指针");
IUnknown*piunknown=CreateInstance();
trace("客户:
获得InteX的接口");
InteX*pintex=NULL;
hr=piunknown->QueryInterface(IID_InteX,(void**)&pintex);
if(SUCCEEDED(hr))
{
trace("客户成功获得组件InteX");
pintex->Fx();
pintex->Release();
}
trace("客户:
获得InteY的接口");
InteY*pintey=NULL;
hr=piunknown->QueryInterface(IID_InteY,(void**)&pintey);
if(SUCCEEDED(hr))
{
trace("客户成功获得组件InteY");
pintey->Fy();
pintey->Release();
}
trace("客户尝试获得不支持的InteZ组件接口");
InteZ*pintez=NULL;
hr=piunknown->QueryInterface(IID_InteZ,(void**)&pintez);
if(SUCCEEDED(hr))
{
trace("客户成功获得组件InteZ");
pintez->Fz();
pintez->Release();
}
else
{
trace("客户不能成功获得组件InteZ");
}
trace("客户释放IUnknown借口");
piunknown->Release();
return0;
}
1.3.ATL——活动模板库(TheActiveTemplateLibrary)
在ATL产生以前,开发COM组件的方法主要有两种:
一是使用COMSDK直接开发COM组件,另一种方式是通过MFC提供的COM支持来实现。
使用ATL开发COM应用是一件非常简单的事情,但是在ATL简单易用的界面后面却包含着复杂的技术。
这些技术包含以下一些方面:
∙COM技术
∙C++模板类技术(Template)
∙C++多继承技术(Multi-Inheritance)
其中,COM技术本文开头有所描述。
C++模板类技术(Template)、C++多继承技术(Multi-Inheritance)在C++理论课中已有详尽描述。
这里最主要的是介绍使用ATL怎么生成一个自己的COM组件以及怎么使用该组件。
1.建立一个ATL工程:
图11-1
2.选择创建的COM类型:
图11-2
该步骤中的一些选项说明:
动态连接库(DynamicLinkingLibrary)最终产生一个动态连接库(DLL)形式的COM服务程序;
应用程序(Executableapplication)最终产生一个可执行程序类型(EXE)的COM服务程序;
NT服务(NTService)产生一个以NT服务方式运行的COM服务程序。
允许嵌入Proxy/Stub代码。
由Microsoft提供的MIDL编译IDL文件以后,将产生用于对象调度(Marshaling)的Proxy/Stub的代码。
在传统方式下,这部分代码与COM服务程序的代码是分离的,但是由于新的COM标准支持多线程环境下的COM对象服务,因此在动态连接库的COM服务程序中也要有Proxy/Stub的支持。
为了支持在网络上的传输,ATL允许用户选择将Proxy/Stub的代码包括在生成的DLL代码中。
这个选项在EXE和NT服务类型的COM应用条件下不可选。
●允许支持MFC。
由于ATL对除COM以外的基本的Windows编程方面的支持极为有限,同时许多程序员对MFC又非常熟悉,因此在ATL的工程设置中允许在ATL工程内部支持使用MFC,即可以使用MFC定义的类。
这一特点给开发人员提供了许多方便,特别对于习惯使用MFC的人来说,能够使用MFC提供的各种功能强大的类的支持,而不必直接使用WindowsSDK。
从另一个方面来看,在ATL工程中使用MFC同时就丧失了ATL代码轻量级的特点。
●支持MTS。
MTS是MicrosoftTransactionServer的缩写,它是Microsoft在COM技术方面的一个新的分支,这里不做详细说明。
----完成上面的设置以后,可以选择Finish完成工程的设置,ATL将创建相应的工程。
3.向工程中加入一个新的ATL类:
首先通过集成环境的"Insert"菜单下的"NewATLObject..."命令进入"ATLObjectWizard"对话框。
如下图所示:
图11-3
对话框的左边部分说明了待创建对象的基本类型,这里主要有以下几种类型:
●对象(Object)基本的COM对象类型;
●控制(Control)ActiveXControl类型的ATL对象;
●其他(Miscellaneous)辅助功能,如对话框的生成等;
●数据访问(DataAccess)数据访问,支持MTS等。
对于一般的COM服务程序,选择 对象(Object),点击下一步继续:
3.输入引入的类名:
图11-4
4.切换到Attributes(属性)标签页:
图11-5
对象的属性设置是ATL对象创建过程中最复杂的部分,包括以下几个主要部分:
∙对象的线程模型(ThreadModel):
对象的线程模型是COM对象在多线程环境下被访问时对访问方式的控制,缺省情况下在ATL中采用的是套间模型Apartment,由系统通过消息队列方式提供并发控制。
∙对象的接口模型(Interface):
COM对象的接口可以是双接口(DualInterface)。
双接口不同于普通接口(CustomInterface)之处在于双接口是从Automation基本接口IDispatch继承的,而普通接口是从IUnknown接口直接继承来的。
缺省的接口模型是双接口。
∙对象的聚合模型(Aggregate):
COM规范不允许对象的实现继承,但是可以通过聚合方式重用其他的COM对象。
ATL对象属性设置中的聚合模型可以指定待创建的COM对象是否支持聚合模型。
缺省的选项是支持对象的聚合。
∙对象对错误处理的支持(SupportISupportErrorInfo):
选取这个选项可以在对象的运行过程中支持错误处理。
缺省情况下这个选项不被选中。
∙对象对连接点的支持(SupportConnectionPoints):
连接点是COM对象的事件机制。
选中这个选项可以使待创建的COM对象具有发出事件的能力。
缺省情况下该选项不被选中。
∙对象对自由线程调度的支持(FreeThreadMarshaller,简称FTM):
对象的自由线程调度是对象在处于自由线程模型状态下,为了简化对象的访问过程而采用的一种优化策略。
缺省情况下该选项不被选中。
5.给引入的类添加方法:
图11-6
图11-7
给添加的方法加入如下代码:
图11-8
CComBSTRstrSource=InData;
CComBSTRtempSource=InData;
boolbNeedToUpper=true;
intj=(int)strSource.Length()-1;
//实现字符串到大写字母的转换并进行逆序转换
for(inti=0;i<(int)strSource.Length();i++)
{
if(strSource[i]>='a'&&strSource[i]<='z'&&bNeedToUpper)
{
strSource[i]=strSource[i]-32;
bNeedToUpper=true;
}
if(strSource[i]=='')bNeedToUpper=false;
tempSource[j]=strSource[i];
j=j-1;
}
*OutData=tempSource;
return*result;
6.添加工程到当前工程中:
图11-9
7.添加类到当前工程中:
图11-10
8.设计如下对话框界面:
图11-11
关联如下变量:
图11-12
对“字符串转换”按钮添加如下响应代码:
voidCMyComClientDlg:
:
OnTransfer()
{
ICMyStrm_MyString;
//创建COM对象
if(!
m_MyString.CreateDispatch("AtlComSample.cmystr.1"))
MessageBox("CreateUserInfoerror");
//得到源字符串放到m_SourceString中
UpdateData(true);
//调用COM接口
BSTRbstrDestStr=SysAllocString(L"");
m_MyString.StringTransfer(m_SourceString,&bstrDestStr);
//得到转换后结果字符串
m_DestString=bstrDestStr;
//将结果字符串显示到编辑框中
UpdateData(false);
}
运行结果如下:
图11-13
练习:
使用同样ATL的方法,建立自己的COM组件并在客户程序中进行使用。