您的位置:首页 > Web前端

ATL Internals 2ed复习.chapter 3.CComSafeArray

2012-10-01 19:05 351 查看
template<typenameT,
VARTYPE_vartype=_ATL_AutomationType<T>::type>
classCComSafeArray{
...
public:
LPSAFEARRAYm_psa;
}


m_psa是CComSafeArray唯一的state



#defineDEFINE_AUTOMATION_TYPE_FUNCTION(ctype,
typewrapper,oleautomationtype)\
template<>\
struct_ATL_AutomationType<ctype>{\
typedeftypewrapper_typewrapper;\
enum{type=oleautomationtype};\
staticvoid*GetT(constT&t){\
return(void*)&t;\
}\
};


DEFINE_AUTOMATION_TYPE_FUNCTION用于将C++类型转换成VARTYPE

DEFINE_AUTOMATION_TYPE_FUNCTION(CHAR,CHAR,VT_I1)
DEFINE_AUTOMATION_TYPE_FUNCTION(SHORT,SHORT,VT_I2)
DEFINE_AUTOMATION_TYPE_FUNCTION(INT,INT,VT_I4)
DEFINE_AUTOMATION_TYPE_FUNCTION(LONG,LONG,VT_I4)
DEFINE_AUTOMATION_TYPE_FUNCTION(LONGLONG,LONGLONG,VT_I8)
DEFINE_AUTOMATION_TYPE_FUNCTION(BYTE,BYTE,VT_UI1)
DEFINE_AUTOMATION_TYPE_FUNCTION(USHORT,USHORT,VT_UI2)
DEFINE_AUTOMATION_TYPE_FUNCTION(UINT,UINT,VT_UI4
DEFINE_AUTOMATION_TYPE_FUNCTION(ULONG,ULONG,VT_UI4)
DEFINE_AUTOMATION_TYPE_FUNCTION(ULONGLONG,ULONGLONG,VT_UI8)
DEFINE_AUTOMATION_TYPE_FUNCTION(FLOAT,FLOAT,VT_R4)
DEFINE_AUTOMATION_TYPE_FUNCTION(DOUBLE,DOUBLE,VT_R8)
DEFINE_AUTOMATION_TYPE_FUNCTION(DECIMAL,DECIMAL,VT_DECIMAL)
DEFINE_AUTOMATION_TYPE_FUNCTION(VARIANT,CComVariant,VT_VARIANT)
DEFINE_AUTOMATION_TYPE_FUNCTION(CY,CY,VT_CY)


于是_ATL_Automation_Type<long>::type=VT_I4



ConstructorsandDestructor

template只是确定array的元素类型,还需要确定维数和各维的size


有7个不同的构造函数用于这个工作,除了第一个Default无参构造函数外(m_psa=NULL),其余的函数都将使用到CComSafeArrayBound用于确定这些细节:


classCComSafeArrayBound:publicSAFEARRAYBOUND{
CComSafeArrayBound(ULONGulCount=0,LONGlLowerBound=0)
{...}
CComSafeArrayBound&
operator=(constCComSafeArrayBound&bound)
{...}
CComSafeArrayBound&operator=(ULONGulCount){...}
ULONGGetCount()const{...}
ULONGSetCount(ULONGulCount){...}
LONGGetLowerBound()const{...}
LONGSetLowerBound(LONGlLowerBound){...}
LONGGetUpperBound()const{...}
};


例如:

explicitCComSafeArray(ULONGulCount,LONGlLBound=0)
:m_psa(NULL){
CComSafeArrayBoundbound(ulCount,lLBound);
HRESULThRes=Create(&bound);
if(FAILED(hRes))
AtlThrow(hRes);
}


Create是一层API的helper:

HRESULTCreate(constSAFEARRAYBOUND*pBound,UINTuDims=1){
ATLASSERT(m_psa==NULL);
ATLASSERT(uDims>0);
HRESULThRes=S_OK;
m_psa=SafeArrayCreate(_vartype,uDims,
const_cast<LPSAFEARRAYBOUND>(pBound));
if(NULL==m_psa)
hRes=E_OUTOFMEMORY;
else
hRes=Lock();
returnhRes;
}


建立1维数组的例子:

//createa1-Dzero-basedSAFEARRAYoflongwith10elements
CComSafeArray<long>sa(10);

//createa1-Done-basedSAFEARRAYofdoublewith5elements
CComSafeArray<double>sa(5,1);




也可以使用这个来建立1D数组:

explicitCComSafeArray(constSAFEARRAYBOUND&bound);


这个例子就不如上述例子简洁:


CComSafeArrayBoundbound(5,1);//1-Done-basedarray
CComSafeArray<long>sa(bound);




使用下面的函数来建立多维数组:

explicitCComSafeArray(constSAFEARRAYBOUND*pBound,UINTuDims=1);


例子:

//3-Darraywithalldimensions
//left-mostdimensionhas3elements
CComSafeArrayBoundbound1(3);
//middledimensionhas4elements
CComSafeArrayBoundbound2(4);
//right-mostdimensionhas5elements
CComSafeArrayBoundbound3(5);

//equivalentC-stylearrayindiceswouldbe[3][4][5]
CComSafeArrayBoundrgBounds[]={bound1,bound2,bound3};
CComSafeArray<int>sa(rgBounds,3);




从已有数组:

CComSafeArray(constSAFEARRAY*psaSrc):m_psa(NULL);
CComSafeArray(constSAFEARRAY&saSrc):m_psa(NULL);
CComSafeArray(constCComSafeArray&saSrc):m_psa(NULL);


例子:

CComSafeArray<int>saSrc(5);//sourceis1-Darrayof5ints
//allocatestoragefor1-Darrayof5ints
//andcopycontentsofsource
CComSafeArray<int>saDest(saSrc);




析构函数调用Detroy():

HRESULTDestroy(){
HRESULThRes=S_OK;
if(m_psa!=NULL){
hRes=Unlock();
if(SUCCEEDED(hRes)){
hRes=SafeArrayDestroy(m_psa);
if(SUCCEEDED(hRes))
m_psa=NULL;
}
}
returnhRes;
}


请注意Unlock()函数,用于释放SAFEARRAY的计数



Assignment

CComSafeArray<T>&operator=(constCComSafeArray&saSrc){
*this=saSrc.m_psa;
return*this;
}
CComSafeArray<T>&operator=(constSAFEARRAY*psaSrc){
ATLASSERT(psaSrc!=NULL);
HRESULThRes=CopyFrom(psaSrc);
if(FAILED(hRes))
AtlThrow(hRes);
return*this;
}


CopyFrom会先释放内部m_psa
例子:

CComSafeArray<long>sa1(10);
//dosomethinginterestingwithsa1
CComSafeArray<long>sa2(5);

//freecontentsofsa1,duplicatecontents
//ofsa2andputintosa1
sa1=sa2;




TheDetachandAttachMethods

HRESULTAttach(constSAFEARRAY*psaSrc){
ATLENSURE_THROW(psaSrc!=NULL,E_INVALIDARG);

VARTYPEvt;
HRESULThRes=::ATL::AtlSafeArrayGetActualVartype(
const_cast<LPSAFEARRAY>(psaSrc),&vt);
ATLENSURE_SUCCEEDED(hRes);
ATLENSURE_THROW(vt==GetType(),E_INVALIDARG);
hRes=Destroy();
m_psa=const_cast<LPSAFEARRAY>(psaSrc);
hRes=Lock();
returnhRes;
}

LPSAFEARRAYDetach(){
Unlock();
LPSAFEARRAYpTemp=m_psa;
m_psa=NULL;
returnpTemp;
}

注意Destroy()也用到Unlock()方法,这个属于Win16的遗留
例如以下代码是错误的:

SAFEARRAY*psa=::SafeArrayCreateVector(VT_I4,0,10);
//BAD-thispointermaynotbevalid!
int*pData=reinterpret_cast<int*>(pda->pvData);
//BOOM(maybe)
pData[0]=5;


应该使用Lock:

SAFEARRAY*psa=::SafeArrayCreateVector(VT_I4,0,10);
//GOOD-thiswillallocatetheactualstorageforthedata
::SafeArrayLock(psa);
//Nowthepointerisvalid
int*pData=(int*)(pda->pvData);
pData[0]=5;
//Unlockafterwe'redone
::SafeArrayUnlock(psa);


实际上Lock为SAFEARRAY分配存储空间,并且设置pvData。CComSafeArrayy构造函数调用Lock(),析构函数调用Destroy(),后者调用Unlock()。
Attach用于处理[in]SAFEARRAY,例如:

STDMETHODIMPSomeClass::AverageArray(/*[in]*/SAFEARRAY*psa,
/*[out]*/LONG*plAvg){
if(!plAvg)returnE_POINTER;
CComSafeArray<long>sa;//Note:notypecheckisdone
//againstpsatype
sa.Attach(psa);//we'repointingatthesame
//memoryaspsa

...performsomecalculations

sa.Detach();//Mustdetachhereorriskacrash
returnS_OK;
}


Detach用于处理[out]SAFEARRAY,例如:

STDMETHODIMPSomeClass::get_Array(/*[out]*/SAFEARRAY**ppsa){
if(!ppsa)returnE_POINTER;
CComSafeArray<long>sa(10);

...populatesainstance

//noresourcesreleasedwhenweleavescope
//andnocopyingperformed
*ppsa=sa.Detach();
returnS_OK;
}


Attach/Detach不会做数据的Copy,下边的代码是错误的:

STDMETHODIMPSomeClass::DontDoThis(SAFEARRAY*psa){
//Wehavetworeferencestothesafearray
CComSafeArray<long>sa1,sa2;
sa1.Attach(psa);
sa2.Attach(psa);

//manipulatethearrayhere
//BUG:Don'tdothis
sa2.Destroy();
}


千万不要对同一SAFEARRAY采用多个Attach

CComSafeArrayOperations

LONGGetLowerBound(UINTuDim=0)const;
LONGGetUpperBound(UINTuDim=0)const;
ULONGGetCount(UINTuDim=0)const;
UINTGetDimensions()const;
VARTYPEGetType()const;
boolIsSizable()const;

其中类成员fFeatures控制IsSizable(),默认应该=TRUE

LPSAFEARRAY*GetSafeArrayPtr(){
return&m_psa;
}


HRESULTResize(ULONGulCount,LONGlLBound=0);
HRESULTResize(constSAFEARRAYBOUND*pBound);


HRESULTResize(constSAFEARRAYBOUND*pBound){
ATLASSUME(m_psa!=NULL);
ATLASSERT(pBound!=NULL);
if(!IsSizable()){
returnE_FAIL;
}
HRESULThRes=Unlock();
if(SUCCEEDED(hRes)){
hRes=SafeArrayRedim(m_psa,const_cast<LPSAFEARRAYBOUND>(pBound));
if(SUCCEEDED(hRes)){
hRes=Lock();
}
}
returnhRes;
}


这个函数有bug,应该检查返回的HRESULT

HRESULTAdd(constT&t,BOOLbCopy=TRUE);
HRESULTAdd(ULONGulCount,constT*pT,BOOLbCopy=TRUE);
HRESULTAdd(constSAFEARRAY*psaSrc);


Add流程:Create,Resize,SetAt

CComSafeArrayElementAccessors

consttypename_ATL_AutomationType<T>::_typewrapper&
GetAt(LONGlIndex)const{
ATLASSUME(m_psa!=NULL);
if(m_psa==NULL)
AtlThrow(E_FAIL);
LONGlLBound=GetLowerBound();
ATLASSERT(lIndex>=lLBound);
ATLASSERT(lIndex<=GetUpperBound());
if((lIndex<lLBound)||(lIndex>GetUpperBound()))
AtlThrow(E_INVALIDARG);

return((_ATL_AutomationType<T>::_typewrapper*)
m_psa->pvData)[lIndex-lLBound];
}

_ATL_AutomationType<T>::_typewrapper&GetAt(LONGlIndex){
//codeidenticaltoconstversion
}


HRESULTSetAt(LONGlIndex,constT&t,BOOLbCopy=TRUE){
bCopy;
ATLASSERT(m_psa!=NULL);
LONGlLBound=GetLowerBound();
ATLASSERT(lIndex>=lLBound);
ATLASSERT(lIndex<=GetUpperBound());
((T*)m_psa->pvData)[lIndex-lLBound]=t;
returnS_OK;
}


例子:

CComSafeArray<long>sa(5);
longlNewVal=14;
//replacethe4thelementwiththevalue14
sa.SetAt(3,lNewVal);


template<>
HRESULTCComSafeArray<BSTR>::SetAt(LONGlIndex,
constBSTR&strData,BOOLbCopy){
//validationcodeomittedforclarity

BSTRstrOrg=((BSTR*)m_psa->pvData)[lIndex-lLBound];
if(strOrg)
::SysFreeString(strOrg);

if(bCopy){
BSTRstrTemp=::SysAllocString(strData);
if(NULL==strTemp)
returnE_OUTOFMEMORY;
((BSTR*)m_psa->pvData)[lIndex-lLBound]=strTemp;
}
else
((BSTR*)m_psa->pvData)[lIndex-lLBound]=strData;
returnS_OK;
}


例子:

BSTRbstr1=::SysAllocString(OLESTR("GoLonghorns!"));
BSTRbstr2=::SysAllocString(OLESTR("ATLRocks!"));

CComSafeArray<BSTR>sa(5);
sa.SetAt(2,bstr1,true);//sageneratesitsowncopyofbstr1
sa.SetAt(3,bstr2,false);//saassignselementtobstr2
::SysFreeString(bstr1);//ok,sastillhasacopy
::SysFreeString(bstr2);//wrong!!!wedon'townbstr2


例子:

IUnknown*pUnk1,pUnk2;
//assignbothpointerstorefertoanobject
CComSafeArray<IUnknown*>sa(5);
sa.SetAt(2,pUnk1,true);//sacallsAddRefonpUnk1
sa.SetAt(3,pUnk2,false);//saassignselementtopUnk2
//withoutAddRefing
pUnk1->Release();//ok,refcountnon-zerobecause
//ofsaAddRef
pUnk2->Release();//wrong!!!wedon'townpUnk2


HRESULTMultiDimGetAt(constLONG*alIndex,T&t){
ATLASSERT(m_psa!=NULL);
returnSafeArrayGetElement(m_psa,
const_cast<LONG*>(alIndex),&t);
}
HRESULTMultiDimSetAt(constLONG*alIndex,constT&t){
ATLASSERT(m_psa!=NULL);
returnSafeArrayPutElement(m_psa,const_cast<LONG*>(alIndex),
_ATL_AutomationType<T>::GetT(t));
}


例子:

//2-Darraywithalldimensions
//left-mostdimensionhas3elements
CComSafeArrayBoundbound1(3);
//right-mostdimensionhas4elements
CComSafeArrayBoundbound2(4);

//equivalentC-stylearrayindiceswouldbe[3][4]
CComSafeArrayBoundrgBounds[]={bound1,bound2};
CComSafeArray<int>sa(rgBounds,2);

intrgIndElement1[]={0,1};//accesselementatsa[1][0]
intrgIndElement2[]={3,2};//accesselementatsa[2][3]

longlVal=0;
//retrievevalueatsa[1][0]
sa.MultiDimGetAt(rgIndElement1,lVal);

//multiplyvalueby2andstoreit
//inelementlocatedatsa[2][3]
sa.MultiDimSetAt(rgIndElement2,lVal*=2);




CComSafeArrayOperators

consttypename
_ATL_AutomationType<T>::_typewrapper&
operator[](intnIndex)const{
returnGetAt(nIndex);
}
typename
_ATL_AutomationType<T>::_typewrapper&
operator[](intnIndex){
returnGetAt(nIndex);
}
consttypename
_ATL_AutomationType<T>::_typewrapper&
operator[](LONGnIndex)
const{
returnGetAt(nIndex);
}
typename
_ATL_AutomationType<T>::_typewrapper&
operator[](LONGnIndex){
returnGetAt(nIndex);
}


例子:

CComSafeArray<int>sa(5);
ATLASSERT(sa[2]==0);
sa[2]=17;
ATLASSERT(sa[2]==17);


operatorconstSAFEARRAY*()const{
returnm_psa;
}
operatorLPSAFEARRAY(){
returnm_psa;
}


CComSafeArray并未定义operator&(),所以下面的代码会发生编译错误:

HRESULTCreateANewSafeArray(SAFEARRAY**ppsa){
*ppsa=SafeArrayCreateVector(VT_I4,1,15);
returnS_OK;
}
HRESULTUseCreatedSafeArray(){
CComSafeArray<int>sa;
HRESULThr=CreateANewSafeArray(&sa);
}


可以使用:

HRESULTUseCreatedSafeArray(){
SAFEARRAY*psa=null;
HRESULThr=CreateANewSafeArray(&psa);
CComSafeArray<int>sa;
sa.Attach(psa);
}


也可以:

HRESULTUseCreatedSafeArray(){
CComSafeArray<int>sa;
HRESULThr=CreateANewSafeArray(sa.GetSafeArrayPtr());
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: