SAFEARRAY与SAFEARRAYBOUND使用方法总结:
SAFEARRAY介绍:
SAFEARRAY的主要目的是用于automation中的数组型参数的传递。因为在网络环境中,数组是不能直接传递的,而必须将其包装成SafeArray。
实质上SafeArray就是将通常的数组增加一个描述符,说明其维数、长度、边界、元素类型等信息。SafeArray也并不单独使用,而是将其再包装到VARIANT类型的变量中,
然后才作为参数传送出去。在VARIANT的vt成员的值如果包含VT_ARRAY|...,那么它所封装的就是一个SafeArray,它的parray成员即是指向SafeArray的指针。
SafeArray中元素的类型可以是VARIANT能封装的任何类型,包括VARIANT类型本身。接下来我们来看看如何使用SafeArray 安全数组(字面翻译哈,别见怪)
方法一,包装一个SafeArray
(1). 定义变量,如:
VARIANT varChunk;SAFEARRAY *psa;
SAFEARRAYBOUND rgsabound[1];
(2). 创建SafeArray描述符:
uIsRead=f.Read(bVal,ChunkSize);//read array from a file. 写的比较简短,大意就是定义一文件对象,然后从中读取数据等。
if(uIsRead==0)break;rgsabound[0].cElements =uIsRead;
rgsabound[0].lLbound = 0;
psa = SafeArrayCreate(VT_UI1,1,rgsabound);
(3). 放置数据元素到SafeArray:for(long index=0;index<uIsRead;index++)
{
if(FAILED(SafeArrayPutElement(psa,&index,&bVal))) //一个一个地放,挺麻烦的。
::MessageBox(NULL,"出毛病了。","提示",MB_OK | MB_ICONWARNING);}
(4). 封装到VARIANT内:
varChunk.vt = VT_ARRAY|VT_UI1;
varChunk.parray = psa;
这样就可以将varChunk作为参数传送出去了。
(5).销毁创建的SafeArray 安全数组
SafeArrayDestroyData(safeArray);
SafeArrayDestroy(safeArray);
//例子代码如下:
/*
* this function read local file to blob fileds.
*/
_COMMON_API_ BOOL WINAPI ReadPathFileToBlob(_RecordsetPtr& rs,LPCTSTR sField,LPCTSTR lpFilePath)
{
BOOL bFlag = TRUE;
CFile file;
if (file.Open(lpFilePath,CFile::modeRead | CFile::typeBinary))
{
long lLen = file.GetLength();
if (lLen > 0)
{
byte* lpFileBuffer = new byte[lLen+1];
ASSERT(lpFileBuffer != NULL);
memset(lpFileBuffer,0,lLen+1);
file.Read(lpFileBuffer,lLen);
file.Close();
SAFEARRAYBOUND sArrayBound[1];
sArrayBound[0].lLbound = 0;
sArrayBound[0].cElements= lLen;
SAFEARRAY *safeArray = NULL;
safeArray = SafeArrayCreate(VT_UI1, 1, sArrayBound);
ASSERT(safeArray != NULL);
for (long i = 0; i < lLen; i++)
SafeArrayPutElement(safeArray, &i, lpFileBuffer++);
VARIANT varBLOB;
varBLOB.vt = VT_ARRAY | VT_UI1;
varBLOB.parray = safeArray;
rs->GetFields()->GetItem(sField)->AppendChunk(varBLOB);
SafeArrayDestroyData(safeArray);
SafeArrayDestroy(safeArray);
}
}
else
{
bFlag = FALSE;
}
return bFlag;
}
读取SafeArray中的数据的步骤:
(1). 用SafeArrayGetElement一个一个地读BYTE buf[lIsRead];
for(long index=0;index<lIsRead;index++)
{
::SafeArrayGetElement(varChunk.parray,&index,buf+index); //就读到缓冲区buf里了。
}
方法二
用SafeArrayAccessData直接读写SafeArray缓冲区:
(1). 读缓冲区:BYTE *buf;
SafeArrayAccessData(varChunk.parray, (void **)&buf);
f.Write(buf,lIsRead);
SafeArrayUnaccessData(varChunk.parray);
//例子代码如下:
/**
* this fucntion read database blob fileds to local file.
*/
_COMMON_API_ BOOL WINAPI ReadBlobToLocalFile(_RecordsetPtr& rs,LPCTSTR sField,LPCTSTR lpFilePath)
{
BOOL bFlag = TRUE;
long lDataSize = rs->GetFields()->GetItem(sField)->ActualSize;
if (lDataSize > 0)
{
_variant_t varBLOB = rs->GetFields()->GetItem(sField)->GetChunk(lDataSize);
if ((VT_ARRAY | VT_UI1) == varBLOB.vt)
{
/*
BYTE lpFileBuffer[lDataSize+1];
memset(lpFileBuffer,0,lDataSize+1);
for (long l = 0 ; l < lDataSize ; l++)
SafeArrayGetElement(varBLOB.parray,&l,lpFileBuffer++);
*/
char* buffer = NULL;
SafeArrayAccessData(varBLOB.parray,(void **)&buffer);
::DeleteFile(lpFilePath);
CFile file;
if (file.Open(lpFilePath,CFile::modeCreate | CFile::modeWrite | CFile::typeBinary))
{
file.Write(buffer,lDataSize);
file.Close();
}
else
{
bFlag = FALSE;
}
SafeArrayUnaccessData(varBLOB.parray);
}
else
{
bFlag = FALSE;
}
}
else
{
bFlag = FALSE;
}
return bFlag;
}
这种方法读写SafeArray都可以,它直接操纵SafeArray的数据缓冲区,比用SafeArrayGetElement和 SafeArrayPutElement速度快。
特别适合于读取数据。但用完之后不要忘了调用::SafeArrayUnaccessData (psa),否则会出错的。