Delphi 10 Seattle changes to Win32 GetPath and redundant TPoint and _POINTL record types
Asked Answered
T

1

8

I am trying to port some code that works in Delphi XE8 to Delphi 10 Seattle. This code calls the GetPath function in Winapi.Windows.

The new Win32 API function signature is:

function GetPath(DC: HDC; Points: PPointL; Types: PByte; nSize: Integer): Integer; stdcall;

In XE8, previously the function had "var Points,Types" which is known commonly as a "var untyped" parameter.

Fixing the code to work with Delphi 10 Seattle means "unifying" the arbitrary types in the application code to use exactly the types declared in the unit itself. However what is confusing me is that there are two types, PPointL, and TPoint, and when I get the GetPath function working, the data it populates is populated into an array of _POINTL records, declared thus in Winapi.Windows:

type
  _POINTL = record      { ptl }
    x: Longint;
    y: Longint;
  end;
  {$EXTERNALSYM _POINTL}
  PPointL = ^TPointL;
  TPointL = _POINTL;

However, there is also another type TPoint, declared in System.Types:

 TPoint = record
    X: FixedInt;
    Y: FixedInt;
  public

Elsewhere, FixedInt is aliased to Longint for both 32 bit and 64 bit Windows, and so TPoint and _POINTL are equivalent, as far as I can tell, on the Windows platform at least.

If existing application component code is all using a type named TPoint, like this:

procedure AddPoint(const P:TPoint);

... What sense am I to make of the situation on the ground inside the RTL sources in Delphi 10? What should my approach to fixing this be? Alias TPoint to _POINTL at the unit level?

How do I fix this and proceed? Since this code is a commercial component, I'm thinking I'll wait until the vendor fixes this, but then, I think that understanding the _POINTL and TPoint in the RTL, and why these structures are redundantly/duplicated in definition, would help others porting low level Win32 Code from Delphi XE8 to Delphi 10 Seattle.

Update: As a workaround, I find I can re-declare an import of the function GetPath, and have it remain as var untyped in my own private unit implementation area import, and continue:

{$ifdef D23}
{$POINTERMATH ON}
      // Delphi 10 Seattle: function GetPath(DC: HDC; Points: PPointL; Types: PByte; nSize: Integer): Integer; stdcall;
      // previously had "var Points,Types" untyped,
const
   gdi32     = 'gdi32.dll';

{$EXTERNALSYM GetPath}
function GetPath(DC: HDC; var Points, Types; nSize: Integer): Integer; stdcall; external gdi32 name 'GetPath';
{$endif}
Tackling answered 1/9, 2015 at 13:37 Comment(3)
The types are not redundant, since both seem to be used somewhere, but I agree that the wrong type is used. It should be PPoint, not PPointL.Burnish
@RudyVelthuis Some Win32 APIs use POINTL instead of POINT, for reasons that I cannot fathom. But yes, GetPath uses POINT.Oberg
@DavidHeffernan: That is why I said the POINTL type is not redundant in Delphi. FWIW, POINTL and RECTL seem to be used in the Metafile APIs. I have no idea why those can't use the normal POINT and RECT structs. Probably a competing development group inside MS, not communicating with the others. <g>Burnish
O
9

There's not much to be said about this, beyond the fact that the change to Winapi.Windows.GetPath in DX Seattle is wrong. I mean, technically it will work, but it leaves any code that uses GetPath in an isolated silo.

This TPointL type is not new, but it is the wrong type for GetPath. The Win32 API function is:

int GetPath(
  _In_  HDC     hdc,
  _Out_ LPPOINT lpPoints,
  _Out_ LPBYTE  lpTypes,
  _In_  int     nSize
);

And LPPOINT is POINT* and POINT maps to TPoint. There are some Win32 API functions that use POINTL, but the majority use POINT. Of course, Microsoft are not helping by having declared two identical types when one would suffice.

Very hard to see how the Embarcadero developer has managed to come up with POINTL in the new GetPath, but there you go. In my view you should submit a QP report and request that the declaration is changed from PPointL to PPoint.

In the meantime a simple cast will suffice because these two types are binary compatible. You wish to pass a PPoint, but the compiler wants PPointL. So pass PPointL(...) where ... is the expression that yields a PPoint.

Oberg answered 1/9, 2015 at 14:38 Comment(1)
This is fixed in Delphi 10.1 Berlin quality.embarcadero.com/browse/RSP-12086Tackling

© 2022 - 2024 — McMap. All rights reserved.