Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Как избежать ошибки Access Violation при изменении шрифта в Delphi: решение проблемы с COMCTL32.dll

Delphi , Графика и Игры , Шрифты

 

В процессе разработки приложений на Delphi многие разработчики сталкиваются с ошибкой "Access violation" при попытке изменить свойства шрифта во время выполнения программы. В этой статье мы разберем конкретный случай ошибки в модуле COMCTL32.dll и предложим несколько рабочих решений.

Проблема и ее симптомы

Ошибка проявляется следующим образом:

Access violation at address 6F75232A in module 'COMCTL32.dll' (offset 2232A). Read of address 0000000C.

Она возникает при попытке изменить размер шрифта формы или элементов управления, особенно когда изменение выполняется из обработчика события. Вот типичный код, который может вызвать эту проблему:

procedure TFprincipal.FontNameRClick(Sender: TObject);
begin
  ga_TipoLetra := FontNameR.Text;
  Font.Name := ga_TipoLetra;
  gn_FontSize := StrToInt(ComboSize.Text);
  Font.Size := gn_FontSize;
  Screen.MessageFont := Self.Font;
  ToolBar.Font.Size := Min(gn_FontSize, 14);
end;

Причины ошибки

Основные причины возникновения этой ошибки:

  1. Попытка изменения свойств шрифта во время обработки сообщений Windows - изменение шрифта может вызвать пересоздание оконного дескриптора (Handle) элемента управления, что не всегда безопасно во время обработки других сообщений.

  2. Проблемы с синхронизацией - VCL пытается обработать несколько сообщений одновременно, что приводит к конфликтам.

  3. Кеширование шрифтов в Windows - система может кешировать некоторые данные о шрифтах, и их изменение в "неподходящий" момент вызывает ошибку.

Решения проблемы

1. Использование TThread.ForceQueue (рекомендуемое решение)

Этот метод позволяет отложить выполнение кода до завершения текущей обработки сообщений:

procedure TFprincipal.FontNameRClick(Sender: TObject);
begin
  TThread.ForceQueue(nil,
    procedure
    begin
      ga_TipoLetra := FontNameR.Text;
      Font.Name := ga_TipoLetra;
      gn_FontSize := StrToInt(ComboSize.Text);
      Font.Size := gn_FontSize;
      Screen.MessageFont := Font;
      ToolBar.Font.Size := Min(gn_FontSize, 14);
    end);
end;

2. Использование таймера для отложенного выполнения

Альтернативный подход с использованием TTimer:

procedure TFprincipal.FontNameRClick(Sender: TObject);
begin
  Timer1.Enabled := True;
end;

procedure TFprincipal.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;
  ga_TipoLetra := FontNameR.Text;
  Font.Name := ga_TipoLetra;
  gn_FontSize := StrToInt(ComboSize.Text);
  Font.Size := gn_FontSize;
  Screen.MessageFont := Self.Font;
  ToolBar.Font.Size := Min(gn_FontSize, 14);
end;

Установите Interval таймера на небольшое значение (например, 10-100 мс).

3. Использование PostMessage для отложенного выполнения

Еще один вариант - использовать Windows API функцию PostMessage:

const
  WM_CHANGEFONT = WM_USER + 1;

procedure TFprincipal.FontNameRClick(Sender: TObject);
begin
  PostMessage(Handle, WM_CHANGEFONT, 0, 0);
end;

procedure TFprincipal.WMChangeFont(var Message: TMessage);
begin
  ga_TipoLetra := FontNameR.Text;
  Font.Name := ga_TipoLetra;
  gn_FontSize := StrToInt(ComboSize.Text);
  Font.Size := gn_FontSize;
  Screen.MessageFont := Self.Font;
  ToolBar.Font.Size := Min(gn_FontSize, 14);
end;

Не забудьте добавить объявление метода в раздел private формы:

private
  procedure WMChangeFont(var Message: TMessage); message WM_CHANGEFONT;

4. Оптимизация получения списка шрифтов

Вместо использования EnumFonts рекомендуется использовать свойство Screen.Fonts:

procedure TFprincipal.GetFontNames;
begin
  FontNameR.Items.Assign(Screen.Fonts);
  FontNameR.Sorted := True;
end;

Дополнительные рекомендации

  1. Проверка значений - всегда проверяйте, что передаваемые значения существуют и корректны:
if ComboSize.Text <> '' then
begin
  gn_FontSize := StrToIntDef(ComboSize.Text, Font.Size);
  Font.Size := gn_FontSize;
end;
  1. Использование madExcept - для диагностики подобных ошибок полезно использовать madExcept с включенной проверкой переполнения памяти.

  2. Тестирование без отладчика - некоторые ошибки проявляются только при работе под отладчиком или только без него. Тестируйте приложение в обоих режимах.

Заключение

Ошибка Access Violation при изменении шрифта - распространенная проблема в Delphi, связанная с особенностями работы VCL и Windows API. Представленные в статье решения позволяют надежно избежать этой проблемы, откладывая критичные операции изменения шрифта до завершения текущей обработки сообщений.

Рекомендуется использовать TThread.ForceQueue как наиболее современное и надежное решение. Для старых версий Delphi можно использовать альтернативные методы с таймером или PostMessage.

Помните, что изменение свойств, влияющих на визуальное представление элементов управления, должно выполняться с осторожностью, особенно в обработчиках событий. Всегда проверяйте входные данные и учитывайте возможные побочные эффекты таких изменений.

Создано по материалам из источника по ссылке.

Статья описывает причины и решения ошибки "Access violation" при изменении шрифтов в Delphi, связанной с модулем COMCTL32.dll.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Шрифты ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-08-14 01:41:45/0.0035459995269775/0