html Naprawa błędu Delphi E2010 dla niezgodnych typów tagLOGBRUSH i tagLOGBRUSH32 | losLab Software Development Blog

Artykuł techniczny

Naprawa błędu Delphi E2010 dla niezgodnych typów tagLOGBRUSH i tagLOGBRUSH32

· Programowanie Delphi

Delphi XE2 i nowsze przeniosły dużą część deklaracji Windows API do zakresowej jednostki Winapi.Windows oraz zaostrzyły kilka deklaracji rekordów. Kod, który kompilował się w starszych wersjach Delphi, może więc przestać się kompilować, gdy rekord Enhanced Metafile udostępnia wartość tagLOGBRUSH32, a GDI API oczekuje tagLOGBRUSH albo TLogBrush.

Objaw zwykle pojawia się podczas odtwarzania rekordów EMF lub odbudowywania obiektów pędzla GDI z PEMRCreateBrushIndirect. Bezpośrednie wywołanie takie jak poniżej wygląda rozsądnie, ale te dwa typy rekordów nie są zgodne przy przypisaniu w nowszych kompilatorach Delphi.

1
2
3
4
5
procedure VEMRCREATEBRUSHINDIRECT(Data: PEMRCreateBrushIndirect);
begin
  GDIObjects[Data^.ihBrush] := CreateBrushIndirect(Data^.lb);
//GDIObjects and CreateBrushIndirect are defined in the winapi.windows unit.
end;

Kompilator zgłasza E2010 Incompatible types: 'tagLOGBRUSH' and 'tagLOGBRUSH32'. Nie przepychaj rekordu przez niebezpieczne rzutowanie. Bezpieczniejsza poprawka polega na utworzeniu lokalnego TLogBrush, jawnym skopiowaniu zgodnych pól i przekazaniu tej struktury do CreateBrushIndirect.

1
2
3
4
5
6
7
8
9
procedure VEMRCREATEBRUSHINDIRECT(Data: PEMRCreateBrushIndirect);
var
  LogBrush: TLogBrush;
begin
  LogBrush.lbStyle := Data^.lb.lbStyle;
  LogBrush.lbColor := Data^.lb.lbColor;
  LogBrush.lbHatch := Data^.lb.lbHatch;
  GDIObjects[Data^.ihBrush] := CreateBrushIndirect(LogBrush);
end;

Dlaczego jawne kopiowanie jest bezpieczniejsze

tagLOGBRUSH32 jest używany w formacie rekordu EMF, aby serializowane dane metafile miały stabilny 32-bitowy układ pól. CreateBrushIndirect przyjmuje jednak zwykłą strukturę pędzla Windows używaną przez bieżącą deklarację API. Kopiowanie lbStyle, lbColor i lbHatch dokumentuje konwersję i unika zależności od specyficznej dla kompilatora zgodności rekordów.

Ten wzorzec jest też łatwiejszy do sprawdzenia podczas przenoszenia starszego kodu graficznego do Unicode Delphi lub celów 64-bitowych. Jeśli późniejsza deklaracja Windows SDK znów zmieni aliasy typów, konwersja pole po polu jasno pokaże zamierzoną granicę danych.

Lista kontrolna portowania

  • Zostaw Winapi.Windows na liście uses w nowoczesnych projektach Delphi.
  • Kopiuj pola rekordu EMF do struktury API oczekiwanej przez wywołanie GDI.
  • Nie zastępuj tego ślepym rzutowaniem wskaźnika, chyba że zweryfikowano układ binarny i czas życia danych.
  • Po utworzeniu pędzla zachowaj istniejące reguły własności obiektów w tabeli GDIObjects.

Dlaczego pojawia się to przy aktualizacjach Delphi

Starszy kod odtwarzania EMF często traktuje rekordy Windows tak, jakby struktury API i serializowane struktury metafile były wymienne. Starsze jednostki i luźniejsze aliasy czasem pozwalały takiemu założeniu się kompilować. Nowoczesne deklaracje Delphi są ściślejsze, więc kompilator ujawnia granicę, która już istniała w Windows API.

Błąd nie jest więc tylko problemem składni. To przydatne ostrzeżenie, że kod przechodzi ze struktury formatu pliku do aktywnego wywołania GDI. Jawna konwersja zwiększa bezpieczeństwo kodu, gdy później jest sprawdzany pod kątem kompilacji 64-bitowych, migracji Unicode lub zaktualizowanych deklaracji Windows SDK.

Czego nie robić

Rzutowanie wskaźnika może wyglądać jak usunięcie błędu kompilatora, ale ukrywa rzeczywistą konwersję i może utrudnić późniejsze utrzymanie. Nie daje też recenzentom wskazówki, które pola są używane celowo. Kopia pól jest krótka, deterministyczna i samodokumentująca, więc jest lepszym domyślnym wyborem dla kodu aplikacji i przykładów komponentów.

Jeśli parser EMF obsługuje wiele podobnych rekordów, umieść tę konwersję w małej funkcji pomocniczej i przetestuj ją z kilkoma stylami pędzla. Dzięki temu pętla odtwarzania pozostaje czytelna, a granica Windows API nadal jest jawna.