Исправление ошибок при работе с шрифтами в 64-битных приложениях Delphi: решение проблемы с EnumFontFamiliesEX
При работе с функциями Windows, такими как EnumFontFamiliesEX, важно учитывать различия в работе с 32-битными и 64-битными приложениями. В частности, размер параметра lParam в функции обратного вызова (callback) может отличаться, что и приводит к ошибкам при компиляции и выполнении программы в 64-битной версии Delphi.
Проблема
Разработчик столкнулся с проблемой, когда код, работавший корректно в 32-битной версии Delphi, начал выдавать исключения в 64-битной версии. Проблема заключалась в использовании функции EnumFontFamiliesEX для определения наличия шрифта в системе. Ошибка возникала в функции обратного вызова, которая некорректно обрабатывала параметр lParam.
Контекст
В коде использовалась функция FindFontbyFaceName, которая вызывала EnumFontFamiliesEX с передачей в качестве последнего параметра указателя на локальную переменную MYresult. Это позволило избежать исключений, в отличие от попытки передать указатель на результат функции FindFontbyFaceName.
Подтвержденное решение
Проблема заключалась в некорректном объявлении параметра lParam функции обратного вызова. В 64-битной версии Delphi размер LPARAM отличается от 32-битной, что и приводило к ошибке при попытке записать значение в память, предназначенную для хранения булевой переменной.
Для исправления проблемы необходимо изменить объявление функции обратного вызова, убрав ключевое слово var и кастовать параметр lParam к указателю на булеву переменную. Также можно изменить тип параметра lParam на Boolean, что позволит корректно работать с результатом в 64-битной версии.
Пример корректного объявления функции обратного вызова:
function FindFontFace(lpelf: PLogFont; lpntm: PTextMetric; FontType: DWORD; lParam: PBoolean): Integer; stdcall;
begin
lParam^ := True;
Result := 0;
end;
Использование EnumFontFamiliesEX с корректным параметром lParam:
function FindFontbyFaceName(ACanvas: TCanvas; const AFacename: string): Boolean;
var
lf: TLogFont;
begin
Result := False;
// Инициализация структуры TLogFont
// Вызов EnumFontFamiliesEX с передачей @Result как lParam
EnumFontFamiliesEX(ACanvas.Handle, lf, @FindFontFace, LPARAM(@Result), 0);
end;
Альтернативный ответ
В качестве альтернативы, можно упростить код, используя свойство TScreen.Fonts, что избавит от необходимости прямого вызова EnumFontFamiliesEX. Однако, стоит учитывать, что не все шрифты могут быть доступны через это свойство.
Пример кода с использованием TScreen.Fonts:
function FindFont(const AFacename: string): Boolean;
begin
Result := (Screen.Fonts.IndexOf(AFacename) <> -1);
end;
Заключение
При работе с функциями Windows в 64-битных приложениях Delphi важно учитывать различия в размерах типов данных и корректно обрабатывать параметры функции обратного вызова. Использование примеров кода, представленных выше, позволит избежать ошибок, связанных с некорректной работой с шрифтами в 64-битных приложениях.
Разработчик столкнулся с ошибками при работе с функциями Windows для перечисления шрифтов в 64-битных приложениях Delphi из-за различий в обработке параметров функции обратного вызова.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.