How to read a packed record written to a TDataSet.Field (ftBytes)

67 views Asked by At

We have a legacy dataset in which one of the fields (the last) was used for saving a packed record.

We need to access this data now and I thought reading it back into a packed record would be pretty simple - but not so much. Seems like I'm striking out.

The folks that designed/wrote the code are long gone so I'm left with what I can discover.

Here's what I have so far -

The packed record format written was:

    TRecordStru = packed record
       RecData1 : integer ;
       RecData2 : array [0..9] of char ;
       RecData3 : array [0..9] of char ;
       RecData4 : integer ;
       RecData5 : array [0..9] of char ; 
       RecData6 : integer ;
    end;

The code to create the packed record was:

with myRecord do // TRecordStru
begin
  RecData1 := Num1   ; // integer
  StrPLCopy(RecData2,StrData2,sizeof(RecData2)) ; // mm/dd/yyyy
  StrPLCopy(RecData3,StrData3,sizeof(RecData3)) ; 
  RecData4 := Num2   ; // integer 
  StrPLCopy(RecData5,StrData5,sizeof(RecData5)) ; 
  RecData6 := Num6   ; // integer 
end;

The code which created the data for the field:

...
var
  tmpData : string
...    
tmpData := spaces(sizeof(myRecord)); // TRecordStru
move(myRecord,tmpData[1],sizeof(myRecord));
... 

And the code which saved the data to the field:

...FieldByName('myField').AsString := VarToStr(Value)+#0 ; // variant

For reading it back, I have tried the following:

The DataType reported by FieldByName('myField').DataType is ftBytes.

I am able to get the data into a buffer using:

FieldByName('myField').GetData(myBuffer)

myBuffer is defined as:

myBuffer : array of byte;

And initialized like this:

getmem(myBuffer,260) ;

I can see the data is there, and could be manually parsed, but is there a 'correct' way of doing this?

1

There are 1 answers

0
Old Skull On

I would use something like this. Perhaps with additional checks.

type
  PRecordStru = ^TRecordStru;

// ...

function RecToVar(const pSource: PRecordStru): Variant;
var
  pValue: PByte absolute pSource;
  i: Integer;

begin
  Result := Null;
  if ( nil = pSource ) then exit;

  try
    Result := VarArrayCreate([0, SizeOf(TRecordStru) - 1], varByte);
  except
    exit;
  end;

  for i := 0 to SizeOf(TRecordStru) - 1 do
  begin
    Result[i] := pValue[i];
  end;
end;

function VarToRec(const vSource: Variant; const pTarget: PRecordStru): Boolean;
var
  pValue: PByte absolute pTarget;
  i: Integer;

begin
  Result := ( pTarget <> nil )
    and VarIsArray(vSource)
    and ( 1 = VarArrayDimCount(vSource) )
    and ( SizeOf(TRecordStru) - 1 = VarArrayHighBound(vSource, 1) );

  if ( not Result ) then exit;

  for i := 0 to SizeOf(TRecordStru) - 1 do
  begin
    pValue[i] := vSource[i];
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  r: TRecordStru;

begin
  r.RecData1 := 1;
  r.RecData2 := '2222222222';
  r.RecData3 := '3333333333';
  r.RecData4 := 4;
  r.RecData5 := '5555555555';
  r.RecData6 := 6;

  MyDataSet.Append();
  // ...
  MyDataSet.FieldValues['myField'] := RecToVar(@r);
  MyDataSet.Post();
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  r: TRecordStru;

begin
  if ( VarToRec(MyDataSet.FieldValues['myField'], @r) ) then
  begin
    // ...
  end;
end;