Проблема, с которой столкнулся разработчик, заключается в том, что после конвертации DLL из 32-битной версии в 64-битную в среде Delphi 10 Seattle, при загрузке этой DLL из 64-битного приложения происходит сбой и закрытие приложения. Проблема связана с использованием компонента TWebBrowser на форме DLL. После отладки была найдена проблема в 64-битной конвертации в модуле VCL "Vcl.OleCtrls.pas", которая была решена путем изменения кода метода TOleControl.HookControlWndProc. Это исправление устранило проблему с сбоем, но привело к тому, что события TWebBrowser перестали обрабатываться, и проблема наблюдается только в 64-битной версии.
Подробности проблемы
При конвертации DLL из 32-битной версии в 64-битную в Delphi 10 Seattle, разработчик столкнулся с тем, что при загрузке DLL в 64-битное приложение, которое занимает значительный объем памяти, приложение крашится. Причиной является компонент TWebBrowser, расположенный на форме DLL. После детального анализа и отладки, была выявлена проблема в модуле Vcl.OleCtrls.pas, связанная с 64-битной конверсией. Проблема была решена путем изменения метода TOleControl.HookControlWndProc, который обрабатывает окно контрола и его процедуру оконных сообщений.
Исходный код метода до исправления:
procedure TOleControl.HookControlWndProc;
begin
// ... старый код ...
DefWndProc := Pointer(GetWindowLong(WindowHandle, GWL_WNDPROC));
// ... старый код ...
SetWindowLong(WindowHandle, GWL_WNDPROC, Longint(@InitWndProc));
// ... старый код ...
end;
После изменения типов данных на 64-битные, процедура HookControlWndProc больше не вызывала ошибку сбоя, но в то же время перестала обрабатываться событийность TWebBrowser.
Подтвержденное исправление
Разработчик обнаружил еще одну ошибку в приведении типов, которая и вызвала проблему с обработкой событий TWebBrowser. Ошибка была найдена в модуле "Vcl.OleCtrls.pas" в процедуре TOleControl.InvokeEvent. Исправление заключалось в замене приведения типов из Integer на Int64, что позволило избежать переполнения в условиях высокой загрузки памяти и обеспечить корректный вызов событий.
Исправленный код процедуры TOleControl.InvokeEvent:
procedure TOleControl.InvokeEvent(DispID: TDispID; var Params: TDispParams);
{$IFDEF CPUX64}
begin
// ... код, который обрабатывает 64-битные типы ...
ParamBlock.RegRCX := Int64(EventMethod.Data);
ParamBlock.RegRDX := Int64(Self);
// ... обработка параметров ...
for i := 1 to Params.cArgs do
begin
case i of
// ... обработка первых двух параметров ...
else
StackParams2[i-3] := Int64(Params.rgvarg[Params.cArgs-i].unkVal);
end;
end;
// ... установка размера и указателя на стек ...
RawInvoke(EventMethod.Code, @ParamBlock);
end;
{$ELSE !CPUX64}
// ... код для 32-битной архитектуры ...
end;
Альтернативные подходы
В комментариях упоминается, что использование функции SetWindowSubclass() может быть более безопасным, чем SetWindowLongPtr(GWL_WNDPROC). Также рекомендуется включить выделение памяти "сверху вниз" на уровне системы для выявления всех дефектов.
Заключение
Исправление, предложенное разработчиком, заключалось в изменении типов данных с Integer на Int64 в процедуре InvokeEvent. Это позволило устранить проблему с обработкой событий TWebBrowser в 64-битной версии DLL, созданной в Delphi 10 Seattle. Разработчикам, столкнувшимся с подобными проблемами, рекомендуется внимательно следить за приведением типов данных, особенно при работе с 64-битными приложениями.
Исправление багов компонента TWebBrowser в 64-битной версии Delphi 10 Seattle после конвертации из 32-битной версии.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.