如何将SafeArray转换为一维数组
SAFEARRAY的主要目的是用于automation中的数组型参数的传递。因为在网络环境中,数组是不能直接传递的,而必须将其包装成SafeArray。实质上SafeArray就是将通常的数组增加一个描述符,说明其维数、长度、边界、元 素类型等信息。SafeArray也并不单独使用,而是将其再包装到VARIANT类型的变量中,然后才作为参数传送出去。在VARIANT的vt成员的 值如果包含VT_ARRAY|...,那么它所封装的就是一个SafeArray,它的parray成员即是指向SafeArray的指针。 SafeArray中元素的类型可以是VARIANT能封装的任何类型,包括VARIANT类型本身。Delphi中com组件或外部调用需要传递一个对象或者数组,这个时候可以考虑使用SafeArray。比如三层架构中通常需要将使用的ClientDataSet数据集传出,那么就可以将DataSet转换为SafeArray,再由其他模块转换接收。 ===============================================================================
代码块: pSafeArray是一个结构体,其定义在ActiveX单元中,相关定义如下:
PSafeArray = ^TSafeArray; {$EXTERNALSYM tagSAFEARRAY} tagSAFEARRAY = record cDims: Word;//数组的维数 fFeatures: Word;//用来描述数组如何分配和如何被释放的标志 cbElements: Longint;//数组元素的大小 cLocks: Longint;//一个计数器,用来跟踪该数组被锁定的次数 pvData: Pointer;//指向数据缓冲的指针 rgsabound: array[0..0] of TSafeArrayBound;//描述数组每维的数组结构,该数组的大小是可变的 end; TSafeArray = tagSAFEARRAY; {$EXTERNALSYM SAFEARRAY} SAFEARRAY = TSafeArray; =============================================================================== 一维数组的传递: //一维数组传递 procedure TForm1.ArrayToSafeArray(DataArray: array of string); var VarBound: TVarArrayBound; psa: PSafeArray; i: Integer; AV1: OleVariant; begin //初始化OleValue VariantInit(OleValue); VarBound.LowBound := 0; VarBound.ElementCount := High(DataArray) + 1;
psa := SafeArrayCreate(VT_BSTR, 1, VarBound);//创建SafeArray对象 //将数组元素放到SafeArray中 for i := Low(DataArray) to High(DataArray) do begin AV1 := DataArray[i]; SafeArrayPutElement(psa, i, TVarData(AV1).VPointer^); end; //封装到Varaint变量中 TVarData(OleValue).VType := VT_ARRAY or VT_BSTR; TVarData(OleValue).VArray := pVarArray(psa); end;
读取一维safeArray的步骤: //使用SafeArrayGetLBound、SafeArrayGetUBound方法获取safeArray数组上下限 function TForm1.SafeArrayToText(OleValue: OleVariant): string; var RVarData: TVarData; RBound: TVarArrayBound; j, UCount: Integer; aValue: WideString; begin Result := ''; //获取OleVaraint对象指针 RVarData := FindVarData(OleValue)^; if RVarData.VArray = nil then Exit; VarResultCheck((SafeArrayGetLBound(pSafeArray(RVarData.VArray), 1, RBound.LowBound))); VarResultCheck(SafeArrayGetUBound(pSafearray(RVarData.VArray), 1, UCount)); RBound.ElementCount := UCount - RBound.LowBound; for j := RBound.LowBound to RBound.ElementCount do begin VarResultCheck(SafeArrayGetElement(PSafeArray(RVarData.VArray), j, aValue)); if Result = '' then Result := Result + aValue else Result := Result + ',' + aValue; end; end;
//另外附上将DataSet通过SafeArray传递的方法,其实为多维数组的传递: procedure TForm1.DataSetToSafeArray(ClientData: TClientDataSet); var DataArray: TDoubleArray; VarBound: array[0..1] of TVarArrayBound; Demen: array[0..1] of DWORD; psa: PSafeArray; i, j, k, Count: Integer; AV1: OleVariant; begin SetLength(DataArray, ClientData.FieldCount + 1, ClientData.RecordCount + 1); Count := 0; ClientData.First; while not ClientData.Eof do begin for i := 0 to ClientData.FieldCount - 1 do begin if Count = 0 then DataArray[i][Count] := ClientData.Fields[i].FieldName else DataArray[i][Count] := ClientData.Fields[i].Value; end; if Count > 0 then ClientData.Next; inc(Count); end; //--------开始转换为SafeArray----------- //初始化OleValue VariantInit(OleValue); VarBound[0].LowBound := 0; VarBound[0].ElementCount := ClientData.FieldCount + 1; VarBound[1].LowBound := 0; VarBound[1].ElementCount := ClientData.RecordCount + 1;
psa := SafeArrayCreate(VT_BSTR, 2, VarBound); for i := Low(DataArray) to High(DataArray) do begin Demen[0] := i; for j := Low(DataArray[i]) to High(DataArray[i]) do begin Demen[1] := j; AV1 := DataArray[i][j]; SafeArrayPutElement(psa, Demen, TVarData(AV1).VPointer^); end; end;
TVarData(OleValue).VType := VT_ARRAY or VT_BSTR; TVarData(OleValue).VArray := pVarArray(psa); end;
//读多维数组,读出后再转换为想要的格式: function TForm1.SafeArrayToDataSet(oleValue: OleVariant): string; var RVarData: TVarData; RBound: array[0..1] of TVarArrayBound; Demen: array[0..1] of DWORD; i, j, DCount, UCount, iCount: Integer; aValue: WideString; begin Result := ''; RVarData := FindVarData(OleValue)^; if RVarData.VArray = nil then Exit; DCount := RVarData.Varray^.DimCount; //取维数 for i := 0 to DCount - 1 do begin VarResultCheck((SafeArrayGetLBound(pSafeArray(RVarData.VArray), i + 1, RBound[i].LowBound))); VarResultCheck(SafeArrayGetUBound(pSafearray(RVarData.VArray), i + 1, UCount)); RBound[i].ElementCount := UCount - RBound[i].LowBound; end; for j := RBound[1].LowBound to RBound[1].ElementCount do begin Demen[1] := j; for iCount := RBound[0].LowBound to RBound[0].ElementCount do begin Demen[0] := iCount; VarResultCheck(SafeArrayGetElement(PSafeArray(RVarData.VArray), demen, aValue)); if Result = '' then Result := Result + aValue else Result := Result + ',' + aValue; end; end; end;
希望对你有点作用!