COM组件的智能指针(深入浅出)

来源:互联网 发布:绕过js倒计时代码 编辑:程序博客网 时间:2024/04/30 08:31

原帖:http://blog.csdn.net/wangweixing2000/archive/2005/08/03/444861.aspx

 

作者:王卫星  

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;
}

转贴请注明出处,谢谢!