Обработка событий интерфейса TAutoIntfObject с TWebBrowser в Delphi: решение проблемы с TOpenLayersExt
Вопрос пользователя связан с необходимостью обработки событий в компоненте TWebBrowser, использующем интерфейс IDocHostUIHandler для взаимодействия с JavaScript через контейнер IDispatch. Проблема заключается в том, что объект FExtObj, реализующий интерфейс TOpenLayersExt, основанный на TAutoIntfObject, теряет свою ссылку после первого вызова метода из JavaScript. Это происходит, когда FExtObj объявляется как TOpenLayersExt. Если же FExtObj объявляется как IDispatch, ссылка сохраняется, но обработчик событий OnZoomChange не работает.
Решение проблемы
Для решения проблемы необходимо использовать подсчет ссылок (reference counting), то есть сохранять FExtObj как ссылку на интерфейс, а не как объект. Это позволит избежать потери ссылки после первого вызова метода из JavaScript и обеспечит корректную обработку событий.
Пример кода
type
TZoomChangeEvent = procedure(Sender: TObject; ZoomLevel: Integer) of object;
TOpenLayersExt = class(TAutoIntfObject, IOpenLayers)
private
FOnZoomChange: TZoomChangeEvent;
// метод ZoomChange вызывается из JavaScript
procedure ZoomChange(ZoomLevel: Integer); safecall;
public
property OnZoomChange: TZoomChangeEvent read FOnZoomChange write FOnZoomChange;
end;
implementation
procedure TOpenLayersExt.ZoomChange(ZoomLevel: Integer);
begin
if Assigned(FOnZoomChange) then
FOnZoomChange(Self, ZoomLevel);
end;
// ...
type
TMapBrowser = class(TWebBrowser, IDocHostUIHandler)
private
// объект расширения
FExtObj: IDispatch;
// метод IDocHostUIHandler::GetExternal
function GetExternal(out ppDispatch: IDispatch): HRESULT; stdcall;
// реализация метода обработчика события OnZoomChange
procedure OnZoomChange(Sender: TObject; Zoom: Integer);
public
// конструктор
constructor Create(AOwner: TComponent); override;
end;
constructor TMapBrowser.Create(AOwner: TComponent);
var
AExtObj: TOpenLayersExt;
begin
inherited Create(AOwner);
// создание объекта расширения
AExtObj := TOpenLayersExt.Create;
AExtObj.OnZoomChange := OnZoomChange;
// сохранение ссылки на интерфейс
FExtObj := AExtObj as IDispatch;
end;
destructor TMapBrowser.Destroy;
begin
// освобождение ссылки на интерфейс
FExtObj := nil;
inherited Destroy;
end;
function TMapBrowser.GetExternal(out ppDispatch: IDispatch): HRESULT;
begin
// передача ссылки на объект расширения
ppDispatch := FExtObj;
Result := S_OK;
end;
Важные моменты
При создании объекта TOpenLayersExt необходимо связать обработчик событий OnZoomChange.
В конструкторе TMapBrowser создается экземпляр TOpenLayersExt, к которому привязывается обработчик событий, и затем сохраняется ссылка на интерфейс IDispatch.
В деструкторе TMapBrowser необходимо освободить ссылку на интерфейс, чтобы избежать утечек памяти.
В методе GetExternal возвращается ссылка на объект расширения.
Заключение
Использование подсчета ссылок позволяет корректно работать с объектами TAutoIntfObject в контексте TWebBrowser, обеспечивая сохранение ссылки на объект и возможность обработки событий, вызываемых из JavaScript.
Проблема связана с обработкой событий в `TWebBrowser` через интерфейс `IDocHostUIHandler` и потерю ссылки на объект `TAutoIntfObject` после первого вызова из JavaScript, требующая использования подсчета ссылок для сохранения ссылки и
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.