I'm having a TWebBrowser
control which implements IDocHostUIHandler
to extend the control of a JavaScript interop through the IDispatch
container. This works fine, except that I don't know, how to dispatch event from JavaScript back to the web browser control.
The extension object is a container based on TAutoIntfObject
like in this example
. As you can see in the example, there is no interop with the web browser control. Ideally, I'd like to implement events on that extension object, but I don't know how to properly declare the TAutoIntfObject
object in my web browser control. Let's say I'm having this extension object:
type
TZoomChangeEvent = procedure(Sender: TObject; ZoomLevel: Integer) of object;
TOpenLayersExt = class(TAutoIntfObject, IOpenLayers)
private
FOnZoomChange: TZoomChangeEvent;
// the ZoomChange method is invoked from 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;
And a TWebBrowser
control like this:
type
TMapBrowser = class(TWebBrowser, IDocHostUIHandler)
private
// the extension object
FExtObj: TOpenLayersExt;
// IDocHostUIHandler::GetExternal method
function GetExternal(out ppDispatch: IDispatch): HRESULT; stdcall;
// this is the TOpenLayersExt.OnZoomChange event method implementation
procedure OnZoomChange(Sender: TObject; Zoom: Integer);
public
// ordinary constructor
constructor Create(AOwner: TComponent); override;
end;
implementation
constructor TMapBrowser.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
// create extension object
FExtObj := TOpenLayersExt.Create;
// here the event method is properly binded; if I'd change the FExtObj type
// to IDispatch with TOpenLayersExt(FExtObj) typecast, it wouldn't
FExtObj.OnZoomChange := OnZoomChange;
end;
function TMapBrowser.GetExternal(out ppDispatch: IDispatch): HRESULT;
begin
// the problem is that I don't know how to properly pass this object to the
// ppDispatch parameter; if this GetExternal method is called second time,
// the FExtObj seems to be released, but I don't get why
ppDispatch := FExtObj as IDispatch;
Result := S_OK;
end;
The problem is that if I declare the FExtObj
object as TOpenLayersExt
, the event method is binded but the FExtObj
object reference seems to be released after the first extension object method invoke (from JavaScript).
If I declare it as IDispatch
, the reference is not released after the JavaScript function invoke, but the OnZoomChange
event is not binded.
It's hard to post the full code here as it's composed from more parts, here is a complete project
made in Delphi 7.
So my question is, how to consume events from TAutoIntfObject
extension object in a web browser control; how to declare the extension object, so I'll be able to handle events from a web browser control and pass it to the IDocHostUIHandler::GetExternal
method parameter still keeping the interface object reference ?