Ошибка доступа к памяти при вызове функции GetClipboardFormatName в Delphi XE8
При работе с функциями Windows API в среде разработки Delphi XE8 пользователь столкнулся с проблемой, когда при вызове функции GetClipboardFormatName из обработчика события OnClick для TToolButton возникала ошибка доступа к памяти. В то же время, если такая же функция вызывалась из обработчика события OnClick для TButton, ошибка не наблюдалась.
Описание проблемы
Пользователь использует функцию GetClipboardFormatName для получения названий форматов буфера обмена, передавая в неё локальную переменную в качестве буфера для хранения результата. При вызове функции из обработчика события TButton всё работает корректно, но при вызове из TToolButton функция возвращает ошибку ERROR_NOACCESS с кодом 998, что указывает на некорректный доступ к памяти.
Контекст проблемы
Проблема проявляется только в Delphi XE8 и не наблюдается в Delphi 7. Попытки обнулить память буфера перед использованием, а также вызов функций OpenClipboard и CloseClipboard не влияют на результат. Отмечено, что использование глобальной переменной вместо локальной позволяет избежать ошибки.
Подтвержденный ответ
Проблема заключается в том, что в коде используется размер буфера в байтах (SizeOf(fmtname)), в то время как функция GetClipboardFormatName ожидает размер буфера в символах. В Delphi 7 тип Char является псевдонимом для AnsiChar (8 бит), а в Delphi XE8, который использует Unicode, Char является псевдонимом для WideChar (16 бит). Таким образом, размер буфера, переданный в функцию, в два раза меньше ожидаемого, что приводит к ошибке доступа к памяти.
Решение проблемы
Для устранения ошибки необходимо заменить SizeOf(fmtname) на Length(fmtname) в функции GetRegisteredClipBoardFormatName. Это обеспечит корректный размер буфера в символах, что соответствует ожиданиям функции GetClipboardFormatName.
function GetRegisteredClipBoardFormatName(Format: word): string;
var
fmtname: array[0..1024] of Char;
begin
if OpenClipboard(self.handle) then
begin
if GetClipboardFormatName(Format, fmtname, Length(fmtname)) <> 0 then
begin
result := fmtname;
end
else
begin
result := 'Unknown Clipboard Format / GetLastError= ' + IntToStr(GetLastError);
end;
CloseClipboard;
end
else
say('OpenClipboard failed');
end;
Альтернативный ответ
Не приводится, так как проблема решена изменением параметра функции.
Заключение
Важно обращать внимание на изменения типов данных и их размеров при переходе между версиями Delphi, особенно при работе с функциями Windows API. В данном случае, изменение типа символа с 8-битного на 16-битный в версии XE8 привело к необходимости корректировки параметра функции GetClipboardFormatName.
Пользователь столкнулся с проблемой доступа к памяти при вызове функции `GetClipboardFormatName` в Delphi XE8, связанной с некорректным размером буфера символов из-за изменения типа `Char` в этой версии.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.