ATL Internals 2ed复习.chapter 3.CComVariant

来源:互联网 发布:算法pdf第四版下载 编辑:程序博客网 时间:2024/06/05 03:42

在使用COM时,有时候用户不知道函数的输入参数,输出参数的具体类型。例如用户传入long类型,函数会把用户传入的long转换成自己想要的参数类型例如BSTR。其中起到关键作用的就是VARIANT类型

VARIANT.vt==当前存储的数据类型

VARIANT.(bVal,iVal,...,pvarVal,byref)==当前存储的数据

 

正确使用VARIANT需要注意:

需要使用VariantInit来初始化

需要使用VariantCopy来复制

需要使用VariantClear来释放资源

VARIANT只能作为单层指针

可以通过VariantChangeType[Ex]来做类型转换

 

The CComVariant Class

class CComVariant: public tagVARIANT { ...};

CComVariant直接继承VARIANT,表示可以直接将CComVariant代替VARIANT做参数传递

 

Constructors and Destructor

23种构造函数

CComVariant() {             ::VariantInit(this);}                                               ~CComVariant() {            Clear();            }                       

CComVariant(BYTE nSrc) {                               vt = VT_UI1;                                       bVal = nSrc;                                   }                                                  CComVariant(short nSrc) {                              vt = VT_I2;                                        iVal = nSrc;                                   }                                                  CComVariant(long nSrc, VARTYPE vtSrc = VT_I4) {        ATLASSERT(vtSrc == VT_I4 || vtSrc == VT_ERROR);    vt = vtSrc;                                        lVal = nSrc;                                   }                                                  CComVariant( float fltSrc) {                           vt = VT_R4;                                        fltVal = fltSrc;                               }                                                  


为了区分易于混淆的参数,定义了第二个参数加以区分

CComVariant(long nSrc, VARTYPE vtSrc = VT_I4) ;

VARIANT使用VARIANT_TRUE,VARIANT_FALSE来定义bool变量

CComVariant接受IDispatch*,IUnknown;并作相应的AddRef操作

CComVariant(const VARIANT& varSrc) {                               vt = VT_EMPTY; InternalCopy (&varSrc);                     }                                                              CComVariant(const CComVariant& varSrc); { /* Same as above */ }

 

void InternalCopy(const VARIANT* pSrc) {    HRESULT hr = Copy(pSrc);                if (FAILED(hr)) {                           vt = VT_ERROR;                          scode = hr;                     #ifndef _ATL_NO_VARIANT_THROW                   AtlThrow(hr);                   #endif                                      }                                   }                                       

当Copy失败,vt=VT_ERROR,也可以定义_ATL_NO_VARIANT_THROW使其throw

要注意不要将未初始化的VARIANT作为参数传给构造函数如下代码将总是发生错误

void func () {       // The following code is incorrect  VARIANT v;         // Uninitialized stack garbage in vt member  CComVariant sv(v); // Indeterminate state}

对于传入字符串,CComVariant内部总是以BSTR复制储存,只有传入CComBSTR时,才会正确处理夹在中间的Nul

 

Assignment

CComVariant定义了33个函数,所有都有如下步骤

释放当前资源

设置新的vt

储存数据

 

对于=(long*),vt=VT_I4 | VT_BYREF

对于=(const SAFEARRAY *pSrc),vt=VT_ARRAY | 元素类型

 

template< typename T >                  void SetByRef( T* pT ) {                    Clear();                                vt = CVarTypeInfo< T >::VT|VT_BYREF;    byref = pT;                         }                                       

用于产生一个原始数据的引用

 

CVarTypeInfo在ATL8中不被使用

CComVariant Operations

HRESULT Clear() { return ::VariantClear(this); }
HRESULT Copy(const VARIANT* pSrc)                                        { return ::VariantCopy(this, const_cast<VARIANT*>(pSrc)); }例如:
STDMETHODIMP SomeClass::put_Option (const VARIANT* pOption) {    // Option saved in member m_Option of type CComVariant    return m_varOption.Copy (pOption) ;}
 
HRESULT Detach(VARIANT* pDest);

不要在[out]中使用Detach,因为操作会对pDest先做Clear操作,而[out]参数是未分配类型的,这时将导致数据异常

STDMETHODIMP SomeClass::get_Option (VARIANT* pOption) {    CComVariant varOption ;    ... Initialize the variant with the output data    // Wrong! The following code can generate an exception,    // corrupt your heap, and give at least seven years bad luck!    return varOption.Detach (pOption);}

Before detaching into an [out] VARIANT argument, be sure to initialize the output argument:

// Special care taken to initialize [out] VARIANT::VariantInit (pOption) ;// orpOption->vt = VT_EMPTY ;return vOption.Detach (pOption); // Now we can Detach safely.

 

HRESULT Attach(VARIANT* pSrc);

用于转移所有权

STDMETHODIMP SomeClass::get_Option (VARIANT* pOption);void VerboseGetOption () {    VARIANT v;    pObj->get_Option (&v) ;    CComVariant cv;    cv.Attach (&v);   // Destructor now releases the VARIANT}
void FragileGetOption() {    CComVariant v;          // This is fragile code!!    pObj->get_Option (&v) ; // Directly update the contained                            // VARIANT. Destructor now releases                            // the VARIANT.}

下述代码,因为get_Option并不会释放[out]参数原有资源

void LeakyGetOption() {    CComVariant v (OLESTR ("This string leaks!")) ;    pObj->get_Option (&v) ; // Directly updates the contained                            // VARIANT. Destructor now releases                            // the VARIANT.}


 

HRESULT ChangeType(VARTYPE vtNew, const VARIANT* pSrc = NULL);


可以转换数据类型

 

ComVariant Comparison Operators

bool operator==(const VARIANT& varSrc) const ;bool operator!=(const VARIANT& varSrc) const ;

当不同类型,上述操作返回false,当同一类型使用VarCmp API进行比较

bool operator<(const VARIANT& varSrc) const ;bool operator>(const VARIANT& varSrc) const ;


CComVariant Persistence Support

HRESULT WriteToStream(IStream* pStream); HRESULT ReadFromStream(IStream* pStream);ULONG GetSize() const;                   


 

原创粉丝点击