12.1.7 使用智能指针创建COM对象
1.问题阐述
利用COM的API创建COM对象,一切的处理工作都要程序员手动完成,比如接口指针最后的释放,这样如果在任务繁重的情况下,很容易出现忘记释放指针的情况,为了解决这个问题,COM能够提供一种自动释放的机制,于是引入了智能指针。
2.实现技巧
使用COM中的智能指针,使对象的创建工作更加简单化。而且它提供自动销毁生成的 COM的对象机制,使程序的精力转移到其他的方面。下面看一下ATL提供的两个智能指针—CcomPtr和CComQIPtr。
CcomPtr类实现客户端基本的COM引用计数模型,CComPtr有一个数据成员,它是一个未经过任何加工的COM接口指针。其类型被作为模板参数传递。
CComPtr<IUnknown> spUnk; CComPtr<IFun> spFun; |
默认的构造函数将这个原始指针数据成员初始化为NULL。
智能指针的参数要么是原始指针,要么是相同类型的智能参数。不论哪种情况,智能指针都调用AddRef控制引用。CComPtr的赋值操作符既可以处理原始指针,也可以处理智能指针,并且在调用新分配指针的AddRef之前自动释放保存的指针。最重要的是,CComPtr的析构函数释放保存的接口(如果非空)。
CComQIPtr对于CComPtr只增加了两个成员函数,CComQIPtr有两个模板参数:一个是被操纵的指针类型,另一个是对应于这个指针类型的GUID。例如,下列代码声明了操纵IDataObject和IPersist接口的智能指针:
CComQIPtr<IFun, &IID_IFun> spUnk; CCom |
CComQIPtr的优点是它有重载的构造函数和赋值操作符。同类版本(例如,接收相同类型的接口)仅仅进行AddRef右边的赋值/初始化操作,这实际上就是CComPtr的功能。异类版本(接收类型不一致的接口)正确调用QueryInterface来决定是否这个对象确实支持所请求的接口:
void f(IFun* spUnk) { CComQIPtr<IFun, &IID_IFun> p; // 同类赋值 - AddRef''s p = spUnk; CComQIPtr<IDataObject, &IID_IDataObject> do; // 异类赋值 - QueryInterface''s do = spUnk; } |
3.实例代码
本实例的目的借助于智能指针创建COM对象,建立一个基于对话框的工程。首先初始化应用工程的COM库,在CXXXXApp的InitInstance()中添加初始化语句:
if(AfxOleInit()==FALSE) { AfxMessageBox("初始化环境COM库失败!"); return FALSE; }
|
引入智能指针类,引入组件的CLSID、接口的ID及接口函数集:
#include "..\Object\Object.h" #include "..\Object\Object_i.c" #include <atlbase.h>
|
智能指针操作代码如下:
void CExample2Dlg::OnExeBtn() { UpdateData(TRUE); CComPtr<IUnknown> spUnk; //定义IUnknown的智能指针 CComPtr<IFun> spFun; //定义IFun的智能指针 try { HRESULT hr = spUnk.CoCreateInstance(CLSID_Fun,NULL, CLSCTX_INPROC_SERVER); //启动组件 if(FAILED(hr)) { MessageBox("组件没有注册!"); return ; } hr = spUnk.QueryInterface(&spFun); //查找IFun的接口 if(FAILED(hr)) { MessageBox("没有接口IFun"); return; } spFun->Add(m_add1,m_add2,&m_add3); CComBSTR s1(m_str1); CComBSTR s2(m_str2); CComBSTR s3; spFun->CatString(s1,s2,&s3); m_str3 = convert(s3.m_str); //将BSTR转换为CString 同上 } catch(LPCTSTR str) { MessageBox(str); } UpdateData(FALSE); }
|
上面的代码演示了使用CcomPtr智能指针,下面的代码演示了CComQIPtr的用法:
void CExample2Dlg::OnComqiBtn() { UpdateData(TRUE); CComPtr<IUnknown> spUnk; //定义IUnknown的智能指针 CComQIPtr<IFun> spFun; //定义IFun的智能指针 try { HRESULT hr = spUnk.CoCreateInstance(CLSID_Fun,NULL, CLSCTX_INPROC_SERVER); //启动组件 if(FAILED(hr)) { MessageBox("组件没有注册!"); return ; } spFun = spUnk; //会自动调用QueryInterface查找接口 if(spFun == NULL) { MessageBox("没有接口!"); return; } spFun->Add(m_add1,m_add2,&m_add3); CComBSTR s1(m_str1); CComBSTR s2(m_str2); CComBSTR s3; spFun->CatString(s1,s2,&s3); m_str3 = convert(s3.m_str); } catch(LPCTSTR str) { MessageBox(str); } UpdateData(FALSE); } |
【责任编辑:
夏书 TEL:(010)68476606】