在COM中使用数组参数-SafeArray[转载/修改] 2011-11-29 15:02

本文深入探讨了SAFEARRAY的概念及其在组件/客户开发中的实践应用,包括如何在栈上和堆上创建一维及二维数组,以及访问数组的方法。同时,文章还阐述了组件/客户中传递SAFEARRAY的原则,提供了实用的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录
何谓SAFEARRAY
创建SAFEARRAY
方法一:使用SafeArrayAllocDescriptor在栈上创建一维数组
方法二:使用SafeArrayAllocDescriptor和SafeArrayAllocData在堆上创建一维数组
方法三:使用SafeArrayAllocDescriptor和SafeArrayAllocData在堆上创建二维数组
方法四:使用SafeArrayCreate在堆上创建一维数组
方法五:使用SafeArrayCreate在堆上创建二维数组
方法六:使用SafeArrayCreateEx创建包含结构的一维数组
访问SAFEARRAY:
方法一:使用SafeArrayAccessData方法
方法二:使用SafeArrayGetElement和SafeArrayPutElemen
组件/客户中传递SAFEARRAY的原则
何谓SAFEARRAY
SAFEARRAY是一个结构,类型定义如下,具体可参考MSDN.
typedef struct tagSAFEARRAY
{
USHORT cDims; //数组维数
USHORT fFeatures; //数组的一些特性
ULONG cbElements;//每一个元素的字节长度
ULONG cLocks; //锁定的字数
PVOID pvData; //具体数据
SAFEARRAYBOUND rgsabound[ 1 ]; // 每一维的信息
} SAFEARRAY;
方法一:使用SafeArrayAllocDescriptor在栈上创建一维数组
//创建SAFEARRAY数组,每个元素为long型,该数组是一维数组
longnData[10]={1,2,3,4,5,6,7,8,9,10};
SAFEARRAY* pArray=NULL;
HRESULT hr=SafeArrayAllocDescriptor(1,&pArray);//创建SAFEARRAY结构的对象
pArray->cbElements=sizeof(nData[0]); //长度应用为字节长度
pArray->rgsabound[0].cElements=10;
pArray->rgsabound[0].lLbound=0;
pArray->pvData=nData;
pArray->fFeatures=FADF_AUTO|FADF_FIXEDSIZE;
  //FADF_AUTO指定在栈上分配数据,并且大小不可以改变(固定为10)
//访问SAFEARRAY数组
long* pValue=NULL;
SafeArrayAccessData(pArray,(void**)&pValue);
longLow(0),High(0);
hr=SafeArrayGetLBound(pArray,1,&Low);//维数索引从1开始
hr=SafeArrayGetUBound(pArray,1,&High);//维数索引从1开始
SafeArrayUnaccessData(pArray);
SafeArrayDestroy(pArray);
  //这种方法释放在栈上分配数组元素所占的空间,即nData数组所用的空间
方法二:使用SafeArrayAllocDescriptorSafeArrayAllocData在堆上创建一维数组
//创建SAFEARRAY数组,每个元素为long型,该数组是一维数组
longnData[10]={1,2,3,4,5,6,7,8,9,10};
SAFEARRAY* pArray=NULL;
HRESULT hr=SafeArrayAllocDescriptor(1,&pArray);//创建SAFEARRAY结构的对象
pArray->cbElements=sizeof(nData[0]);
pArray->rgsabound[0].cElements=10;
pArray->rgsabound[0].lLbound=0;
SafeArrayAllocData(pArray);
long* pData=NULL;
SafeArrayAccessData(pArray,(void**)&pData);
longl(0),h(0);
SafeArrayGetLBound(pArray,1,&l);
SafeArrayGetUBound(pArray,1,&h);
longSize=h-l+1;
SafeArrayAccessData(pArray,(void**)&pData);
for(longIdx=l;Idx<Size;++Idx)
{
pData[Idx]=nData[Idx];
}
SafeArrayUnaccessData(pArray);
//访问SAFEARRAY数组
long* pValue=NULL;
SafeArrayAccessData(pArray,(void**)&pValue);
longLow(0),High(0);
hr=SafeArrayGetLBound(pArray,1,&Low);//维数索引从1开始
hr=SafeArrayGetUBound(pArray,1,&High);//维数索引从1开始
SafeArrayUnaccessData(pArray);
SafeArrayDestroy(pArray);
方法三:使用SafeArrayAllocDescriptorSafeArrayAllocData在堆上创建二维数组
SAFEARRAY* pArray=NULL;
HRESULT hr=SafeArrayAllocDescriptor(2,&pArray);
pArray->rgsabound[0].lLbound=0;
pArray->rgsabound[0].cElements=3;
pArray->rgsabound[1].lLbound=0;
pArray->rgsabound[1].cElements=3;
pArray->cbElements=sizeof(long);
hr=SafeArrayAllocData(pArray);
longlDimension[2];
longx=1;
//为第一行赋值
for(longi=0;i<3;++i)
{
lDimension[1]=0;//行
lDimension[0]=i;//列
SafeArrayPutElement(pArray,lDimension,&x);
x++;
}
//为第二行赋值
for(longi=0;i<3;++i)
{
lDimension[1]=1;//行
lDimension[0]=i;//列
SafeArrayPutElement(pArray,lDimension,&x);
x++;
}
//读取SafeArray中第二行第三列的数据
longy(0);
lDimension[1]=1;
lDimension[0]=2;
SafeArrayGetElement(pArray,lDimension,&y);
SafeArrayDestroy(pArray);
二维SAFEARRAY数组使用的时候下标要注意,这里采用的是列主序的方式,即lDimension[1]代表行,lDimension[0]代表列。
方法四:使用SafeArrayCreate在堆上创建一维数组
SAFEARRAYBOUND Bound[1];
Bound[0].lLbound=0;
Bound[0].cElements=10;
SAFEARRAY* pArray=SafeArrayCreate(VT_I4,1,Bound);
long* pData=NULL;
HRESULT hr=SafeArrayAccessData(pArray,(void**)&pData);
longLow(0),High(0);
SafeArrayGetLBound(pArray,1,&Low);
SafeArrayGetUBound(pArray,1,&High);
longSize=High-Low+1;
for(longIdx=Low;Idx<Size;++Idx)
{
pData[Idx]=Idx;
cout<<pData[Idx]<<endl;
}
SafeArrayUnaccessData(pArray);
SafeArrayDestroy(pArray);
方法五:使用SafeArrayCreate在堆上创建二维数组
SAFEARRAYBOUND Bound[2];
Bound[0].lLbound=0;
Bound[0].cElements=3;
Bound[1].lLbound=0;
Bound[1].cElements=3;
SAFEARRAY* pArray=SafeArrayCreate(VT_I4,2,Bound);
longDemen[2];
for(longi=0;i<3;++i)
{
for(longj=0;j<3;++j)
{
Demen[1]=i;
Demen[0]=j;
longx=i*j;
SafeArrayPutElement(pArray,Demen,&x);
}
}
//访问二维数组
for(longi=0;i<3;++i)
{
for(longj=0;j<3;++j)
{
Demen[1]=i;
Demen[0]=j;
longx(0);
SafeArrayGetElement(pArray,Demen,&x);
cout<<"("<<i<<","<<j<<") "<<x<<endl;
}
}
SafeArrayDestroy(pArray);
方法六:使用SafeArrayCreateEx创建包含结构的一维数组
使用SAFEARRAY传递UDT(自定义结构)是一项常用的技术,MSDN文档描述得比较齐全,要注意的一点是,自定义结构要求有自己的GUID,这必须在IDL文件中定义。同时还必须要使用IRecordInfo接口,该接口将和数组一起传递出去,IRecordInfo接口内部记录了UDT的描述信息。
IDL文件中:
[uuid(810930AA-9229-46e7-B20C-41F6218D0B1A)]
struct_BookMarkSchema
{
BSTR Name;
BSTR Context;
BSTR Time;
};
interfaceIShape : IDispatch
{
[id(6),helpstring("获取属于某用户的书签名称列表")] HRESULT GetBookMarkName([in] BSTR UserID,[out] SAFEARRAY(struct_BookMarkSchema)* pBookMarkNames);
}
librarySarstShapeLib
{
importlib("stdole2.tlb");
[
uuid(DBDCC0F1-38F3-4EB4-A5BD-79A3707BDE9C),
helpstring("Shape Class")
]
coclassShape
{
[default]interfaceIShape;
};
struct_BookMarkSchema;
};
方法的实现为:
STDMETHODIMP CShape::GetBookMarkName(BSTR UserID,SAFEARRAY** pBookMarkNames)
{
//获得GIS库信息
CSarstConfigure Configure;
string Flag("GIS");
string IP,Database,UserName,Key,Context;
Configure.GetDatabaseInfo(Flag,IP,Database,UserName,Key,Context);
//读取图层属性数据
USES_CONVERSION;
string user(CString(UserID).GetBuffer());
string sql("SELECT 书签名,书签描述,时间 FROM 用户书签表 where 用户ID='"+user+"' order by 时间 desc");
FBData data(IP,Database,UserName,Key);
table t=data.GetTable(sql);
if(t.empty())
{
returnS_FALSE;
}
//创建SafeArray
IRecordInfo* pRecordInfo=NULL;
HRESULT hr=::GetRecordInfoFromGuids(LIBID_SarstShapeLib,1,0,GetUserDefaultLCID(),IID_STRUCT_BookMarkSchema,&pRecordInfo);
if(FAILED(hr))
returnE_FAIL;
*pBookMarkNames=::SafeArrayCreateVectorEx(VT_RECORD,0,long(t.size()-1),(void*)pRecordInfo);
_BookMarkSchema* pData=NULL;
hr=::SafeArrayAccessData(*pBookMarkNames,(void**)&pData);
for(inti=0;i<int(t.size()-1);i++)
{
t[i+1].at(0).CopyTo(&pData[i].Name);
t[i+1].at(1).CopyTo(&pData[i].Context);
t[i+1].at(2).ChangeType(VT_BSTR);
t[i+1].at(2).CopyTo(&pData[i].Time);
}
::SafeArrayUnaccessData(*pBookMarkNames);
pRecordInfo->Release();
returnS_OK;
}
访问SAFEARRAY:
这种方法可以参见创建SAFEARRAY之方法一
请注意,访问完后要调用SafeArrayUnaccessData方法,并且调用SafeArrayDestroy销毁数组
这种方式通常用于访问一位数组
这种方法可以参见创建SAFEARRAY之方法五
这种方式在访问多维数组的时候很有用
组件/客户中传递SAFEARRAY的原则:
1) 在堆上创建SAFEARRAY数组
2) 一方创建,一方回收
在这里谢谢原作者和修改的人。知其然还要知其所以然。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值