Search code examples
delphidebuggingdelphi-2009varianttclientdataset

How to dump Delphi OleVariant content to the file?


I have multi-tiered application that use OleVariant variables to send and receive data accross the line using custom communication framework. Usually the content of this OleVariant variable comes from TClientDataSet.Data (which, of course, is of OleVariant type). I have suspicion that the communication frmework changes the content of this OleVariant variable and therefore I would like to dump the contenct of the variable before sending and after receiving data. I use code:

TmpOrder: OleVariant;
Tmp: TStringList;

Tmp:=TStringList.Create;
try
  Tmp.LoadFromFile('D:\test.txt');
  Tmp.Add('---');
  Tmp.Add(TmpOrder);
  Tmp.SaveToFile('D:\test.txt');
finally
  Tmp.Free;
end;

But the content of the file is meaningless. E.g., the following content of the file can represent the content of the TClientDataSet.Data:

---
??

Of course, there is something different happening.

So - how to capture the content of the OleVariant variable.

Saving TClientDataSet as XML is not option for me, because communication uses OleVariant not XML.

I am using Unciode Delphi (Delphi 2009 and up).


Solution

  • Here is some code which converts TClientDataSet.Data to a string and a test routine which exercises it.

    function VariantToString(V : OleVariant) : String;
      procedure VariantToStringInner(V : OleVariant; var AString : String);
      var
        IsArray : Boolean;
        DimCount : Integer;
        i : Integer;
      begin
        IsArray := VarIsArray(V);
    
        if not IsArray then begin
          //  Handle the case where V is not an array
          if (VarIsEmpty(V) or VarIsNull(V)) then begin
            AString := AString + ' ';
            exit;
          end
          else
            AString := AString + VarToStr(V);
        end
        else begin
          //  V is an array, so first we need to know how many dimensions it has
          DimCount := VarArrayDimCount(V);
    
          //  For TClientDataSet.Data the answer AFAIK should be 1
          //  so we'll process only dimension 1
          Assert(DimCount = 1);
    
          //  Recurse into this proc so that we handle the cases where V[i] is an array
          //  and where it isn't
          for i := VarArrayLowBound(V, 1) to VarArrayHighBound(V, 1) do begin
            VariantToStringInner(V[i], AString);
          end;
        end;
      end;
    
    begin
      Result := '';
      VariantToStringInner(V, Result);
    end;
    
    procedure TForm1.TestVarToStr;
    var
      V : OleVariant;
      S : String;
    begin
      V := 'hello world';
      S := VariantToString(V) + #13#10;
    
      V := CDS1.Data;
      S := S + VariantToString(V);
      Memo1.Lines.Text := S;
    end;
    

    Obviously, if you want to save the result to a file, simply call Memo1.Lines.SaveToFile()

    The result I get is

    hello world 150252241891000240005020003000202027368401000107838566848980692073080651171161111051109904689711610140600000678117109981011144010000047897109101107300010587736884722020200586971081171011073000105877368847220202002010677265787169957679714013006000100000004000200000004000126585847973786786657685694010300044011000578971091014944002000578971091015026567

    The same CDS data, saved as XML is as follows:

    <?xml version="1.0" standalone="yes"?>  
    <DATAPACKET Version="2.0">
    <METADATA>
      <FIELDS>
        <FIELD attrname="ID" fieldtype="i4" SUBTYPE="Autoinc"/><FIELD   attrname="Date" fieldtype="date"/>
        <FIELD attrname="Number" fieldtype="i4"/><FIELD attrname="Name" fieldtype="string" WIDTH="20"/><FIELD attrname="Value" fieldtype="string" WIDTH="20"/>
      </FIELDS>
      <PARAMS CHANGE_LOG="1 0 4 2 0 4" AUTOINCVALUE="3"/>
    </METADATA>
    <ROWDATA>
      <ROW RowState="4" ID="1" Name="Name1"/><ROW RowState="4" ID="2" Name="Name2" Value="AC"/>
    </ROWDATA>
    </DATAPACKET>