Deaa Darawsheh
Deaa Darawsheh

Reputation: 95

Pointer of ^Pchar to array of PChar

when i migrate from Delphi 6 to Delphi 10.2 Tokyo i get error when i try to casting pointer of ^PChar to array of PChar

type
  PServEnt = ^TServEnt;
  TServEnt = packed record
    s_name: PChar;                 // official service name
    s_aliases: ^PChar;             // alias list
    s_port: Smallint;              // protocol to use
    s_proto: PChar;                // port #
  end;

function TIdStackWindows.WSGetServByPort(
  const APortNumber: Integer): TIdStrings;
var
  ps: PServEnt;
  i: integer;
  p: array of PChar;
begin
  Result := TIdStringList.Create;
  p := nil;
  try
    ps := GetServByPort(HToNs(APortNumber), nil);
    if ps <> nil then
    begin
      Result.Add(ps^.s_name);
      i := 0;
      p := Pointer(ps^.s_aliases); // get error Incompatible types: 'Dynamic array' and 'Pointer' 
      while p[i] <> nil do
      begin
        Result.Add(PChar(p[i]));
        inc(i);
      end;
    end;
  except
    Result.Free;
  end;
end;

this code working well at Delphi 2010 ,how to make it correct at Delphi 10.2 Tokyo

Upvotes: 1

Views: 955

Answers (1)

David Heffernan
David Heffernan

Reputation: 612804

The error message is correct, and if the code compiled in earlier versions of Delphi then that was because those earlier versions of the compiler were deficient.

A dynamic array is more than just a pointer to the first element. It also encapsulates the meta data which stores the length of the array, and the reference count. Your cast is therefore not valid. You got away with this invalid code because you did not attempt to access this meta data, but that's as much by chance as through intention.

Don't attempt to cast to a dynamic array. Instead use pointer arithmetic. For instance:

function TIdStackWindows.WSGetServByPort(
  const APortNumber: Integer): TIdStrings;
var
  ps: PServEnt;
  p: PPChar;
begin
  Result := TIdStringList.Create;
  try
    ps := GetServByPort(HToNs(APortNumber), nil);
    if ps <> nil then
    begin
      Result.Add(ps^.s_name);
      p := PPChar(ps^.s_aliases); // cast needed due to Indy record type's use of un-nameable type
      while p^ <> nil do
      begin
        Result.Add(p^);
        inc(p);
      end;
    end;
  except
    Result.Free;
    raise;
  end;
end;

I changed the type declaration of the alias list to PPChar to avoid incompatible type errors when assigning to the local variable of that type.

Note also that I have corrected your exception handling which was previously swallowing exceptions and returning an invalid object reference.

Upvotes: 4

Related Questions