Delphi 10 Seattle переходит на Win32 GetPath и избыточные типы записей TPoint и _POINTL

Я пытаюсь перенести некоторый код, который работает в Delphi XE8, в Delphi 10 Seattle. Этот код вызывает функцию GetPath в Winapi.Windows.

Новая сигнатура функции Win32 API:

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

В XE8 ранее у функции был параметр "var Points,Types", известный как параметр "var untyped".

Исправление кода для работы с Delphi 10 Seattle означает «унификацию» произвольных типов в коде приложения для использования именно тех типов, которые объявлены в самом модуле. Однако меня смущает то, что существует два типа, PPointL и TPoint, и когда я запускаю функцию GetPath, заполняемые ею данные заполняются в массив записей _POINTL, объявленный таким образом в Winapi.Windows:

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

Однако есть и другой тип TPoint, объявленный в System.Types:

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

В другом месте FixedInt имеет псевдоним Longint как для 32-битной, так и для 64-битной Windows, поэтому, насколько я могу судить, TPoint и _POINTL эквивалентны, по крайней мере, на платформе Windows.

Если весь существующий код компонентов приложения использует тип с именем TPoint, например:

procedure AddPoint(const P:TPoint);

... Какой мне смысл понимать ситуацию внутри исходников RTL в Delphi 10? Каким должен быть мой подход к исправлению этого? Псевдоним TPoint для _POINTL на уровне устройства?

Как это исправить и продолжить? Поскольку этот код является коммерческим компонентом, я думаю, что подожду, пока поставщик исправит это, но тогда я думаю, что понимание _POINTL и TPoint в RTL и почему эти структуры избыточно/дублируются в определении, поможет другие переносят низкоуровневый код Win32 с Delphi XE8 на Delphi 10 Seattle.

Обновление: в качестве обходного пути я обнаружил, что могу повторно объявить импорт функции GetPath и оставить ее как нетипизированную переменную в моем собственном импорте области реализации частного модуля и продолжить:

{$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}

person Warren P    schedule 01.09.2015    source источник
comment
Типы не избыточны, так как вроде оба где-то используются, но я согласен, что используется не тот тип. Должно быть PPoint, а не PPointL.   -  person Rudy Velthuis    schedule 01.09.2015
comment
@RudyVelthuis Некоторые API-интерфейсы Win32 используют POINTL вместо POINT по причинам, которые я не могу понять. Но да, GetPath использует POINT.   -  person David Heffernan    schedule 01.09.2015
comment
@DavidHeffernan: Вот почему я сказал, что тип POINTL не является избыточным в Delphi. FWIW, POINTL и RECTL, похоже, используются в API-интерфейсах метафайлов. Я понятия не имею, почему они не могут использовать обычные структуры POINT и RECT. Вероятно, это конкурирующая группа разработчиков внутри MS, не общающаяся с остальными. <г>   -  person Rudy Velthuis    schedule 02.09.2015


Ответы (1)


Об этом особо нечего сказать, кроме того факта, что изменение на Winapi.Windows.GetPath в DX Seattle неверно. Я имею в виду, что технически это будет работать, но оставит любой код, использующий GetPath, в изолированном бункере.

Этот тип TPointL не нов, но он не подходит для GetPath. Функция Win32 API:

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

А LPPOINT это POINT*, а POINT соответствует TPoint. Некоторые функции Win32 API используют POINTL, но большинство используют POINT. Конечно, Microsoft не помогает, объявляя два идентичных типа, когда достаточно одного.

Очень трудно понять, как разработчику Embarcadero удалось придумать POINTL в новом GetPath, но вот так. На мой взгляд, вы должны представить отчет QP и запросить изменение декларации с PPointL на PPoint.

А пока будет достаточно простого приведения, потому что эти два типа совместимы в бинарном режиме. Вы хотите передать PPoint, но компилятор хочет PPointL. Поэтому передайте PPointL(...), где ... — это выражение, которое дает PPoint.

person David Heffernan    schedule 01.09.2015
comment
Это исправлено в Delphi 10.1 Berlin quality.embarcadero.com/browse/RSP-12086. - person Warren P; 22.04.2016