SAFEARRAY与SAFEARRAYBOUND用法

SAFEARRAY与SAFEARRAYBOUND使用方法总结:


SAFEARRAY介绍:

SAFEARRAY的主要目的是用于automation中的数组型参数的传递。因为在网络环境中,数组是不能直接传递的,而必须将其包装成SafeArray。

实质上SafeArray就是将通常的数组增加一个描述符,说明其维数、长度、边界、元素类型等信息。SafeArray也并不单独使用,而是将其再包装到VARIANT类型的变量中,

然后才作为参数传送出去。在VARIANT的vt成员的值如果包含VT_ARRAY|...,那么它所封装的就是一个SafeArray,它的parray成员即是指向SafeArray的指针。

SafeArray中元素的类型可以是VARIANT能封装的任何类型,包括VARIANT类型本身。接下来我们来看看如何使用SafeArray 安全数组(字面翻译哈,别见怪)


使用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),否则会出错的。  

你可能感兴趣的:(用法,SAFEARRAY,SAFEARRAYBOUND)