VARIANT变量是COM组件之间互相通信的重要的参数变量之一,它可以容纳多种不同的类型,如short、long、double等,包括各类指针和数组。组件之间的互相调用是比较耗时的,尤其带当组件位于不同进程中时,因此,减少传递次数是提高效率的一种有效方法。其中,Excel表格的操作就可能涉及到大量数据,一次传递一个二维数组是提高对Excel表的操作效率。下面以两种不同方式来实现VARIANT二维数组的操作。
1、使用SAFEARRAY实现二维数组
SAFEARRAY安全数组可以实现多维数组,SAFEARRAY实现的步骤可以大致分为三步。
(1)创建SAFEARRAY安全数组,包括设置数组元素的类型、数据的维数,大小等。
(2)对SAFEARRAY数组赋值,既可通过SafeArrayPutElement函数逐个元素进行负责,也可通过指针来获得SAFEARRAY的数据地址,然后对指针指向的值进行赋值操作。其中,如果SAFEARRAY中的数组时多维数组,即可以把多维数组转换为一维数组,也可以通过获得指向数组的指针方式来操作数组中的元素。
(3)使用VARIANT变量把SAFEARRAY进行包装。
使用SAFEARRAR实现二维数组的源代码如下:
VARTYPE vt = VT_I4; /*数组元素的类型,long*/ SAFEARRAYBOUND sab[2]; /*用于定义数组的维数和下标的起始值*/ sab[0].cElements = 2; sab[0].lLbound = 0; sab[1].cElements = 2; sab[1].lLbound = 0; /*创建一个2*2的类型为long的二维数组*/ SAFEARRAY* psa = SafeArrayCreate(vt, sizeof(sab)/sizeof(SAFEARRAYBOUND), sab); if (NULL == psa) { throw; }
/*通过指向数组的指针来对二维数组的元素进行间接赋值*/
long (*pArray)[2]= NULL;
HRESULT hRet = SafeArrayAccessData(psa, (void**)&pArray);
if (FAILED(hRet))
{
throw;
}
memset(pArray, 0,2*2*sizeof(long));
/*释放指向数组的指针*/
SafeArrayUnaccessData(psa);
pArray = NULL;
/*对二维数组的元素进行逐个赋值*/
long index[2]= {0,0};
long lFirstLBound= 0;
long lFirstUBound= 0;
long lSecondLBound= 0;
long lSecondUBound= 0;
SafeArrayGetLBound(psa, 1,&lFirstLBound);
SafeArrayGetUBound(psa, 1,&lFirstUBound);
SafeArrayGetLBound(psa, 2,&lSecondLBound);
SafeArrayGetUBound(psa, 2,&lSecondUBound);
for (long i= lFirstLBound; i<= lFirstUBound; i++)
{
index[0]= i;
for (long j= lSecondLBound; j<= lSecondUBound; j++)
{
index[1]= j;
long lElement= i * sab[1].cElements+ j;
HRESULT hRet = SafeArrayPutElement(psa, index,&lElement);
if (FAILED(hRet))
{
throw;
}
}
}
/*把SAFEARRAY转换为VARIANT*/
VARIANT var;
var.vt = VT_ARRAY| vt; /*vt必须和psa的数据类型保持一致*/
var.parray = psa;
SafeArrayDestroy(psa);
psa = NULL;
2、使用COleSafeArray实现二维数组
COleSafeArray继承于VARIANT,是MFC的自动化类,因此,只有在使用MFC类库时才能使用该类。COleSafeArray封装操作相关的函数,可通过MSDN查询该类的成员函数来了解与安全数组相关的函数。COleSafeArray还可以直接转换为VARIANT。因此,相对于SAFEARRAY,COleSafeArray的使用更方便。COleSafeArray和SAFEARRAY之间的关系就是MFC类库和Win32 SDK的关系,使用步骤类似。
使用COleSafeArray实现二维数组的源代码如下所示:
VARTYPE vt = VT_I4; /*数组元素的类型,long*/ SAFEARRAYBOUND sab[2]; /*用于定义数组的维数和下标的起始值*/ sab[0].cElements = 2; sab[0].lLbound = 0; sab[1].cElements = 2; sab[1].lLbound = 0; COleSafeArray olesa; olesa.Create(vt, sizeof(sab)/sizeof(SAFEARRAYBOUND), sab);
/*通过指向数组的指针来对二维数组的元素进行间接赋值*/
long (*pArray)[2]= NULL;
olesa.AccessData((void**)&pArray);
memset(pArray, 0,2*2*sizeof(long));
/*释放指向数组的指针*/
olesa.UnaccessData();
pArray = NULL;
/*对二维数组的元素进行逐个赋值*/
long index[2]= {0,0};
long lFirstLBound= 0;
long lFirstUBound= 0;
long lSecondLBound= 0;
long lSecondUBound= 0;
olesa.GetLBound(1,&lFirstLBound);
olesa.GetUBound(1,&lFirstUBound);
olesa.GetLBound(2,&lSecondLBound);
olesa.GetUBound(2,&lSecondUBound);
for (long i= lFirstLBound; i<= lFirstUBound; i++)
{
index[0]= i;
for (long j= lSecondLBound; j<= lSecondUBound; j++)
{
index[1]= j;
long lElement= i * sab[1].cElements+ j;
olesa.PutElement(index, &lElement);
}
}
/*把COleSafeArray变量转换为VARIANT*/ VARIANT var = (VARIANT)olesa;
参考资料
http://blog.sina.com.cn/s/blog_74f586a50100rv6t.html
http://hfp0601.blog.163.com/blog/static/228483522011031104718762/
如何使用COleSafeArray实现二维数组将字符串写入excel
// VARTYPE vt = VT_BSTR ; /*数组元素的类型,string*/VARTYPE vt = VT_I4; /*数组元素的类型,long*/
SAFEARRAYBOUND sabWrite[2]; /*用于定义数组的维数和下标的起始值*/
sabWrite[0].cElements = 1;
sabWrite[0].lLbound = 0;
sabWrite[1].cElements = 3;
sabWrite[1].lLbound = 0;
COleSafeArray olesaWrite;
olesaWrite.Create(vt, sizeof(sabWrite)/sizeof(SAFEARRAYBOUND), sabWrite);
/*通过指向数组的指针来对二维数组的元素进行间接赋值*/
long (*pArray)[2] = NULL;
olesaWrite.AccessData((void **)&pArray);
memset(pArray, 0, sabWrite[0].cElements * sabWrite[1].cElements * sizeof(long));
/*释放指向数组的指针*/
olesaWrite.UnaccessData();
pArray = NULL;
/*对二维数组的元素进行逐个赋值*/
long index[2] = {0, 0};
long lFirstLBound = 0;
long lFirstUBound = 0;
long lSecondLBound = 0;
long lSecondUBound = 0;
olesaWrite.GetLBound(1, &lFirstLBound);
olesaWrite.GetUBound(1, &lFirstUBound);
olesaWrite.GetLBound(2, &lSecondLBound);
olesaWrite.GetUBound(2, &lSecondUBound);
for (long i = lFirstLBound; i <= lFirstUBound; i++)
{
index[0] = i ;
for (long j = lSecondLBound; j <= lSecondUBound; j++)
{
index[1] = j;
long lElement = str[j];
//CString lElement = ch;
olesaWrite.PutElement(index, &lElement);
}
}
/*把ColesaWritefeArray变量转换为VARIANT,并写入到Excel表格中*/
VARIANT varWrite = (VARIANT)olesaWrite;
range.put_Value2(varWrite);
这样能将输入的整形写入excel,当变成VT_BSTR报内存不足,求指导如何修改
------解决方案--------------------
可以通过另外一种写法,
CRange write_range = start_range.get_Offset(COleVariant((long)7),COleVariant((long)j)) ;
write_range.put_Value2((COleVariant)(str[j]));