作者:王卫星
csdnid:wangweixing2000
职能指针其实只是为了我们开发者方便使用的东东,但是大多数据开发者总是害怕会有泄漏,以前的字符串的泄漏问题大家都应该知道了。atl7的出现应该让我们放心使用了!职能指针只是对我们的一些类型或者接口的封装,使我不用每次考虑这引用技术的问题!
我们经常用到的职能指针CComPtr,IxxxxPtr,CComBSTR,CComVariant ,_bstr_t。
CComBSTR和_bstr_t的用法:我在csdn整理的帖子已经讲得很细了大家可以去看看:http://community.csdn.net/Expert/topic/3789/3789751.xml?temp=.8534662
这里应该注意的就是接口中返回字符串的处理:
HRESULT CFoo::get_Name(BSTR* name)
{
if (name==NULL) return E_POINTER;
CComBSTR bsName(L"FooBar"); //如果有成员变量如CComBSTR m_name,用m_name替换 L"FooBar"即可CComBSTR bsName(m_name);这里主要是为了引起引用计数+1
*name = bsName.Detach();
}
下来讲讲CComVariant 的用法和一些注意的地方:
// 创建一个类型为 VT_I4 (其实是个long型)
CComVariant vValue(12);
// 转换long到BSTR字符串类型,其他的转换同理
hr = vValue.ChangeType(VT_BSTR);
if (FAILED(hr)) return hr;
要注意的地方:
1、当用CComVariant(VARIANT_TRUE) 创建一个变量时,其实创建的不是boolean (VT_BOOL) 型而是一个VT_I2型(short integer 型),你可用CComVariant(true) 创建一个boolean (VT_BOOL) 型的变量
2、当创建一个CComVariant myVar(ipSmartPointer),如果ipSmartPointer为职能指针,创建的将是一个boolean (VT_BOOL) 型的变量,而不是VT_UNKNOWN型的,解决的办法是:
IUnknownPtr ipUnk = ipSmartPointer;
// 确保我们用IUnknown* 来初始化 CComVariant
CComVariant myVar2(ipUnk.GetInterfacePtr());
下面是一个win32控制台app,写了调用COM组件的客户端例程
// MyTestClient.cpp : 定义控制台应用程序的入口点。
//
//这里主要讲解智能指针的用法
#include "stdafx.h"
//import要调用COM组件的dll,路经一定要给对,
//no_namespace就是去掉命名空间,这样不用每次都加上MyTest::的命名
#import "../MyTest/debug/Mytest.dll" no_namespace
//建议在写完这句代码后编译一遍,这样会在debug目录下生成一个Mytest.tlb文件
//打开Mytest.tlb看看就知道它是多么有用了,你想知道的都在里面!
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);//初始化COM库
Ix1Ptr pIx1 = NULL; //创建一个智能指针的对象,为什么Ix1后面会多出来个Ptr尾巴?
//我们去看看Mytest.tlb就一目了然了,go!
//在Mytest.tlb找到下面一段代码,什么意思呢?继续go!
/*
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(Ix1, __uuidof(Ix1));
*/
//我在comdef.h找到该宏的源代码,look!
/*
#if !defined(_COM_SMARTPTR)
#if !defined(_INC_COMIP)
#include <comip.h>
#endif
#define _COM_SMARTPTR _com_ptr_t
#define _COM_SMARTPTR_LEVEL2 _com_IIID
#endif
#if defined(_COM_SMARTPTR)
#if !defined(_COM_SMARTPTR_TYPEDEF)
#if defined(_COM_SMARTPTR_LEVEL2)
#define _COM_SMARTPTR_TYPEDEF(Interface, IID) typedef _COM_SMARTPTR<_COM_SMARTPTR_LEVEL2<Interface, &IID> > Interface ## Ptr //这里就是家尾巴的地方,宏我这里就不多说了
#else
#define _COM_SMARTPTR_TYPEDEF(Interface, IID) typedef _COM_SMARTPTR<Interface, &IID> Interface ## Ptr //这里就是家尾巴的地方
#endif
#endif
#endif
*/
//_COM_SMARTPTR_TYPEDEF(Ix1, __uuidof(Ix1));展开的代码就应该是
//typedef _com_ptr_t< _com_IIID<Ix1, __uuidof(Ix1)> > Ix1Ptr;
//终于找到了Ix1Ptr了
HRESULT hr = S_OK;
hr = pIx1.CreateInstance(__uuidof(Cx1));//为啥这么简单只要一个参数?
//原因在于其他两个都有默认值,我偷懒了!这里就不废话了!
//肯定有人要问__uuidof()是干啥用的?主要用来获取guid,参数可是是类型名,
//接口名,接口实现类名等msdn看看,当我想要iid和clsid最好选择!当然你也可以用CLSID_x1来代替hoho!
//剩下的就是掉用Ix1的方法了
//用完后只要设置为NULL
pIx1 = NULL; //职能指针会做相应的善后处理,我们就不用操心了!
//这里我再说说atl中给我提供的智能指针的模板用法,go on!
//注意要用atl的东西记着把加入相应的头文件!
/*ATL7的写法
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将为显式的
#include <atlbase.h>
*/
CComPtr<Ix1> pAtlIx1 = NULL;
hr = pAtlIx1.CoCreateInstance(__uuidof(Cx1)); //用法和前面相同只不过方法前多了"Co",不管它
//.....
pAtlIx1 = NULL;
CoUninitialize(); //释放COM库
system("PAUSE");
return 0;
}
如果在组件中返回接口指针?
STDMETHODIMP Cx1::get_Font(IFontDisp** pVal)
{
if(pVal == NULL)
return E_POINTER; //提示错误指针
//创建一个局部职能指针通过类成员职能指针,
//引起AddRef 是引用计数+1
CComPtr<IFontDisp> pFont(m_pFont);
*pVal = pFont.Detach();//分离清除局部职能指针pFont传递给[out]属性的*pVal
/*还有一种做法就是:
*pVal = m_pFont;
if(*pVal != NULL)
{
*pVal->AddRef(); //也使其应用计数加1
}
*/
return S_OK;
}
转贴请注明出处,谢谢!