Delphi - access to data from a dynamic array that is populated from an untyped pointer

I use Delphi 2009 , not so much influencing what I do. I think I would have faced the same if I had been back in 2007 .

I have a scsi call that outputs data to a pointer (the wrong way to look at it, but I can't explain it).

I originally used Move to populate a Static byte array with the data that was returned, but I would like to switch to a Dynamic array that knows the length during the call. I tried several things with different results, some get data, but have crazy access violations, others have errors, but get invalid data.

Adding setlength to the array, and then using move , first has an empty array of the given length, and then the second one will not be able to access the data using OutputData [0] , as I did when it was static, in the debugger after moving everything is displayed as invisible value or something else.

Below I tried to read an article in which oposit took a dynamic array and gave a pointer to an address. It mentions errors such as orphaned data.

var
  Output: Pointer;
  OutputData: Array of byte;
  I: Integer;
begin
GetMem(Output, OutputLength.Value);
if SendPSPQuery(Char(DriveLetter[1]), cbxQuery.Items.IndexOf(cbxQuery.Text), Output, OutputLength.Value) = 0 then
  begin
    OutputData := @Output;
    for I := 0 to OutputLength.Value - 1 do
    begin
      edtString.Text := edtString.Text + Char(OutputData[I]);
    end;

There are many other data that are used to be extracted into a string and hexadecimal values.

In any case, how can I take a pointer, put this data in a dynamic array, and then capture this data the way you would access the array.

Thanks.

+3
source share
4 answers

To use a dynamic array with a procedureMove , you need to pass the first element of the array. For example:

var
  Source: Pointer;
  SourceSize: Integer;
  Destination: array of Byte;

SetLength(Destination, SourceSize);
Move(Source^, Destination[0], SourceSize);

, . , Move , , . , , Move.

, , Destination . , Delphi 2009. Delphi 4, . Move .


GetMem, -cast, , . . , , , , , .

PSP . :

var
  Output: array of Byte;

SetLength(Output, OutputLength.Value);
if SendPSPQuery(Char(DriveLetter[1]),
                cbxQuery.Items.IndexOf(cbxQuery.Text),
                @Output[0],
                OutputLength.Value) = 0
then

; , Output , . , . , , , . , , . , , .


, , , , .

  • , . , , , , Delphi 4. :

    type
      PByteArray = ^TByteArray;
      TByteArray = array[0..0] of Byte;
    var
      ByteArray: PByteArray;
    
    ByteArray := PByteArray(Output);
    for i := 0 to Pred(OutputLength.Value) do begin
      {$R-}
      edtString.Text := edtString.Text + Chr(ByteArray[i]);
      {$R+}
    end;
    

    $R , , 1. , , re . . , , , , . ( , .)

  • PByte Pointer, Delphi new ( Delphi 2009) . PChar, PAnsiChar PWideChar. :

    var
      Output: PByte;
    
    for i := 0 to Pred(OutputLength.Value) do begin
      edtString.Text := edtString.Text + Chr(Output[i]);
    end;
    

    $POINTERMATH PByte, , . C , {$POINTERMATH ON} , .


, . . -, , . -, , . , :

var
  OutputString: AnsiString;

SetString(OutputString, PAnsiChar(Buffer), OutputLength.Value);
edtString.Text := edtString.Text + OutputString;
+10

Nevermind... lol - -... - , ive , .

    type
  PDynByteArray = ^TDynByteArray;
  TDynByteArray = array of byte;

procedure TfrmMain.btnQueryClick(Sender: TObject);
var
  Output: Pointer;
  OutputData: PDynByteArray;
  WorkingData: Array of byte;
  DriveLetter: ShortString;
  I: Integer;
  HexOutput: String;
begin
edtSTRING.Clear;
memHEX.Clear;
GetMem(Output, OutputLength.Value);
DriveLetter := edtDrive.Text;
if SendPSPQuery(Char(DriveLetter[1]), cbxQuery.Items.IndexOf(cbxQuery.Text), Output, OutputLength.Value) = 0 then
  begin
    //Move(Output^,OutputData,56);
    OutputData := PDynByteArray(@Output);
    for I := 0 to OutputLength.Value - 1 do
    begin
      edtString.Text := edtString.Text + Char(OutputData^[I]);
    end;
    for I := 0 to OutputLength.Value - 1 do
    begin
      HexOutput := HexOutput + InttoHex(OutputData^[I],2) + ' ';
    end;
    memHex.Lines.Append(HexOutput);
    FreeMem(Output);
    memHex.SelStart := 0;
  end
else edtSTRING.Text := 'SCSI Command Failed';
end;
0

PByte. {$ POINTERMATH ON} .

{$POINTERMATH ON}
var
  Output: Pointer;
  ar: PByte;
begin
  GetMem(Output, 100);
  ar:=Output;
  ShowMessage(IntToStr(ar[0])+IntToStr(ar[1])+'...');
end;
0

Anyway, the reason the output drawing takes time is because you are looking at the purpose of edtString.text. This needs to be assigned only once, and not in a loop. Each time you reassign it, you need to process many levels of material, from concatenating strings to drawing the OS on the screen. You can create a string first and then just assign it at the end in the worst case.

0
source

Source: https://habr.com/ru/post/1704476/


All Articles