ATL Internals 2ed复习.chapter 3.CComVariant

在使用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) ;
// or
pOption->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;                   


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值