Socket怎样传递OLEVariant的多维数组

webwx (2006-07-06 17:41:00) 
比如:
var
tempVr: OleVariant;
begin
tempVr := VarArrayCreate([1..2], varOleStr);
tempVr[1] := VarArrayOf([1, 2, 3, 4, 5]);
tempVr[2] := VarArrayOf([6, 7, 8, 9, 10]);
end;
象上面的OleVariant的tempVr万能变量就是一个多位数据,怎样能通过Socket传递呢?
而且还要是TCP的,因为要保证这个万能变量能够正确传递。
能不能一起讨论一下关于对象传递呢? 呵呵 小弟直接是不懂WinSock编程。只是原理
比较模糊啊,想练练手。
蓝叶菱 (2006-07-07 09:18:52) 
var
tempVr: OleVariant;
begin
tempVr := VarArrayCreate([1,5,1,2], varinteger);//创建一个5列2行的数组
tempvr[1,1]:=xxxxx;
tempvr[2,1]:=xxxx;
tempvr[3,1]:=xxxxx;

流传输的前期转换
procedure TForm2.VariantToStream (const v : olevariant;
                                 Stream : TMemoryStream);
var
p : pointer;
begin
Stream.Position := 0;
Stream.Size := VarArrayHighBound (v, 1) - VarArrayLowBound(v,  1) + 1;
p := VarArrayLock (v);
Stream.Write (p^, Stream.Size);
VarArrayUnlock (v);
Stream.Position := 0;
end;

procedure TForm2.StreamToVariant (Stream : TMemoryStream; var v : OleVariant);
var
p : pointer;
begin
v := VarArrayCreate ([0, Stream.Size - 1], varByte);
p := VarArrayLock (v);
Stream.Position := 0;
Stream.Read (p^, Stream.Size);
VarArrayUnlock (v);
end;
SOCKET发送流应该很简单吧。。
z_cd (2006-07-07 09:20:14) 
(楼上的封包算法只能对付一维简单数组吧,楼主的多维数组就不行了吧)

步骤:1.将OleVariant转换成Stream流格式
     2.然后用ClientWinSocket.SendStream或者用Socket API自己写

其中:OleVariant --> Stream 算法比较复杂,给大家贡献一段比较成熟的代码(能保证万能变量正确封包)如下:

{ WriteOleVariant, ReadOleVariant }
type
PIntArray = ^TIntArray;
TIntArray = array[0..0] of Integer;
const
EasyArrayTypes = [varSmallInt, varInteger, varSingle, varDouble, varCurrency,
varDate, varBoolean, varByte];

VariantSize: array[0..varByte] of Word  = (0, 0, SizeOf(SmallInt), SizeOf(Integer),
SizeOf(Single), SizeOf(Double), SizeOf(Currency), SizeOf(TDateTime), 0, 0,
SizeOf(Integer), SizeOf(WordBool), 0, 0, 0, 0, 0, SizeOf(Byte));
resourcestring
SBadVariantType = 'Unsupported variant type: %s';

procedure WriteOleVariant(const Value: OleVariant; Stream: TStream);

procedure WriteArray(const Value: OleVariant; Stream: TStream);
var
   LVarData: TVarData;
   VType: Integer;
   VSize, i, DimCount, ElemSize: Integer;
   LSafeArray: PSafeArray;
   LoDim, HiDim, Indices: PIntArray;
   V: OleVariant;
   P: Pointer;
   {$IFDEF VER140}
   function FindVarData(const V: Variant): PVarData;
   begin
     Result := @TVarData(V);
     while Result.VType = varByRef or varVariant do
       Result := PVarData(Result.VPointer);
   end;
   {$ENDIF}
begin
   LVarData := FindVarData(Value)^;
   VType := LVarData.VType;
   LSafeArray := PSafeArray(LVarData.VPointer);

   Stream.Write(VType, SizeOf(Integer));
   //if FGetHeader then Inc(FHeaderSize, SizeOf(Integer));
   DimCount := VarArrayDimCount(Value);
   Stream.Write(DimCount, SizeOf(DimCount));
   //if FGetHeader then Inc(FHeaderSize, SizeOf(Integer));
   VSize := SizeOf(Integer) * DimCount;
   GetMem(LoDim, VSize);
   try
     GetMem(HiDim, VSize);
     try
       for i := 1 to DimCount do
       begin
         LoDim[i - 1] := VarArrayLowBound(Value, i);
         HiDim[i - 1] := VarArrayHighBound(Value, i);
       end;
       Stream.Write(LoDim^,VSize);
       Stream.Write(HiDim^,VSize);
       //if FGetHeader then Inc(FHeaderSize, SizeOf(Integer) * 2);
       if VType and varTypeMask in EasyArrayTypes then
       begin
         ElemSize := SafeArrayGetElemSize(LSafeArray);
         VSize := 1;
         for i := 0 to DimCount - 1 do
           VSize := (HiDim[i] - LoDim[i] + 1) * VSize;
         VSize := VSize * ElemSize;
         P := VarArrayLock(Value);
         try
           Stream.Write(VSize, SizeOf(VSize));
           //if FGetHeader then Inc(FHeaderSize, SizeOf(Integer));
           Stream.Write(P^,VSize);
         finally
           VarArrayUnlock(Value);
         end;
       end else
       begin
         //FGetHeader := False;
         GetMem(Indices, VSize);
         try
           for I := 0 to DimCount - 1 do
             Indices[I] := LoDim[I];
           while True do
           begin
             if VType and varTypeMask <> varVariant then
             begin
               OleCheck(SafeArrayGetElement(LSafeArray, Indices^, TVarData(V).VPointer));
               TVarData(V).VType := VType and varTypeMask;
             end else
               OleCheck(SafeArrayGetElement(LSafeArray, Indices^, V));
             WriteOleVariant(V, Stream);
             Inc(Indices[DimCount - 1]);
             if Indices[DimCount - 1] > HiDim[DimCount - 1] then
               for i := DimCount - 1 downto 0 do
                 if Indices[i] > HiDim[i] then
                 begin
                   if i = 0 then Exit;
                   Inc(Indices[i - 1]);
                   Indices[i] := LoDim[i];
                 end;
           end;
         finally
           FreeMem(Indices);
         end;
       end;
     finally
       FreeMem(HiDim);
     end;
   finally
     FreeMem(LoDim);
   end;
end;

var
I, VType: Integer;
W: WideString;
begin
VType := VarType(Value);
if VType and varArray <> 0 then
   WriteArray(Value, Stream)
else
   case (VType and varTypeMask) of
     varEmpty, varNull:
       Stream.Write(VType, SizeOf(Integer));
     varOleStr:
     begin
       W := WideString(Value);
       I := Length(W);
       Stream.Write(VType, SizeOf(Integer));
       Stream.Write(I,SizeOf(Integer));
       Stream.Write(W[1], I * 2);
       //if FGetHeader then Inc(FHeaderSize, SizeOf(Integer) * 2);
     end;
     varDispatch:
     begin
       raise Exception.CreateResFmt(@SBadVariantType, [IntToHex(VType, 4)]);
     end;
     varVariant:
     begin
       if VType and varByRef <> varByRef then
         raise Exception.CreateResFmt(@SBadVariantType, [IntToHex(VType, 4)]);
       I := varByRef;
       Stream.Write(I, SizeOf(Integer));
       //if FGetHeader then Inc(FHeaderSize, SizeOf(Integer));
       WriteOleVariant(Variant(TVarData(Value).VPointer^), Stream);
     end;
     varUnknown:
       raise Exception.CreateResFmt(@SBadVariantType, [IntToHex(VType, 4)]);
   else
     Stream.Write(VType, SizeOf(Integer));
     //if FGetHeader then Inc(FHeaderSize, SizeOf(Integer));
     if VType and varByRef = varByRef then
       Stream.Write(TVarData(Value).VPointer^, VariantSize[VType and varTypeMask])
     else
       Stream.Write(TVarData(Value).VPointer, VariantSize[VType and varTypeMask]);
   end;
end;

type
TVarFlag = (vfByRef, vfVariant);
TVarFlags = set of TVarFlag;

function ReadOleVariant(Stream: TStream): OleVariant;

function ReadArray(VType: Integer; Stream: TStream): OleVariant;
var
   //Flags: TVarFlags;
   LoDim, HiDim, Indices, Bounds: PIntArray;
   DimCount, VSize, i: Integer;
   {P: Pointer;}
   V: OleVariant;
   LSafeArray: PSafeArray;
   P: Pointer;
begin
   VarClear(Result);
   Stream.Read(DimCount, SizeOf(DimCount));
   VSize := DimCount * SizeOf(Integer);
   GetMem(LoDim, VSize);
   try
     GetMem(HiDim, VSize);
     try
       Stream.Read(LoDim^, VSize);
       Stream.Read(HiDim^, VSize);
       GetMem(Bounds, VSize * 2);
       try
         for i := 0 to DimCount - 1 do
         begin
           Bounds[i * 2] := LoDim[i];
           Bounds[i * 2 + 1] := HiDim[i];
         end;
         Result := VarArrayCreate(Slice(Bounds^,DimCount * 2), VType and varTypeMask);
       finally
         FreeMem(Bounds);
       end;
       if VType and varTypeMask in EasyArrayTypes then
       begin
         Stream.Read(VSize, SizeOf(VSize));
         P := VarArrayLock(Result);
         try
           Stream.Read(P^, VSize);
         finally
           VarArrayUnlock(Result);
         end;
       end else
       begin
         LSafeArray := PSafeArray(TVarData(Result).VArray);
         GetMem(Indices, VSize);
         try
           FillChar(Indices^, VSize, 0);
           for I := 0 to DimCount - 1 do
             Indices[I] := LoDim[I];
           while True do
           begin
             V := ReadOleVariant(Stream);
             if VType and varTypeMask = varVariant then
               OleCheck(SafeArrayPutElement(LSafeArray, Indices^, V)) else
               OleCheck(SafeArrayPutElement(LSafeArray, Indices^, TVarData(V).VPointer^));
             Inc(Indices[DimCount - 1]);
             if Indices[DimCount - 1] > HiDim[DimCount - 1] then
               for i := DimCount - 1 downto 0 do
                 if Indices[i] > HiDim[i] then
                 begin
                   if i = 0 then Exit;
                   Inc(Indices[i - 1]);
                   Indices[i] := LoDim[i];
                 end;
           end;
         finally
           FreeMem(Indices);
         end;
       end;
     finally
       FreeMem(HiDim);
     end;
   finally
     FreeMem(LoDim);
   end;
end;

var
I, VType: Integer;
W: WideString;
//TmpFlags: TVarFlags;
Flags: TVarFlags;
begin
VarClear(Result);
Flags := [];
Stream.Read(VType, SizeOf(VType));
if VType and varByRef = varByRef then
   Include(Flags, vfByRef);
if VType = varByRef then
begin
   Include(Flags, vfVariant);
   Result := ReadOleVariant(Stream);    //TmpFlags, Data);
   Exit;
end;
if vfByRef in Flags then
   VType := VType xor varByRef;
if (VType and varArray) = varArray then
   Result := ReadArray(VType, Stream) else
case VType and varTypeMask of
   varEmpty: VarClear(Result);
   varNull: Result := NULL;
   varOleStr:
   begin
     Stream.Read(I, SizeOf(Integer));
     SetLength(W, I);
     Stream.Read(W[1], I * 2);
     Result := W;
   end;
   varDispatch:
     raise Exception.CreateResFmt(@SBadVariantType, [IntToHex(VType, 4)]);
   varUnknown:
     raise Exception.CreateResFmt(@SBadVariantType, [IntToHex(VType, 4)]);
else
   TVarData(Result).VType := VType;
   Stream.Read(TVarData(Result).VPointer, VariantSize[VType and varTypeMask]);
end;
end;
delphfans (2006-07-07 09:41:19) 
var
tempVr: OleVariant;
c:array[0..4096] of char;
size:integer;
begin
tempVr := VarArrayCreate([1,12,1,2], varinteger);//创建一个5列2行的数组
tempvr[1,1]:=23;
tempvr[2,1]:=23;
tempvr[3,1]:=23;
size:=VarArrayHighBound (tempVr, 1) - VarArrayLowBound(tempVr,  1) + 1;
strmove(c,@tempVr, size);
IdTCPClient1.Socket.Send(c,size);
end;
webwx (2006-07-07 10:35:18) 
各位仁兄真是高见啊,我会验证的。。。 现在不能给出自己的想法哦。。。 继续。鼓励
Writer (2006-07-08 12:04:32) 
不知楼上几位有没考虑到,字符串引用问题。比如你发送的只是字符串指针而不是字符串。复杂就在于置。

posted @ 2010-11-26 14:09  覆雨翻云  阅读(1722)  评论(0编辑  收藏  举报