【问题标题】:How to interop with TAutoIntfObject object from a TWebBrowser control?如何与 TWebBrowser 控件中的 TAutoIntfObject 对象进行互操作?
【发布时间】:2013-04-12 12:49:39
【问题描述】:

我有一个TWebBrowser 控件,它实现IDocHostUIHandler 以通过IDispatch 容器扩展对JavaScript 互操作的控制。这工作正常,除了我不知道如何将事件从 JavaScript 分派回 Web 浏览器控件。

扩展对象是一个基于TAutoIntfObject 的容器,类似于this example。正如您在示例中看到的,与 Web 浏览器控件没有互操作性。理想情况下,我想在该扩展对象上实现事件,但我不知道如何在我的 Web 浏览器控件中正确声明 TAutoIntfObject 对象。假设我有这个扩展对象:

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;

还有一个像这样的TWebBrowser 控件:

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;

问题在于,如果我将FExtObj 对象声明为TOpenLayersExt,则事件方法已绑定,但FExtObj 对象引用似乎在第一个扩展对象方法调用(来自JavaScript)之后被释放。

如果我声明为IDispatch,则在JavaScript函数调用后不会释放引用,但OnZoomChange事件没有绑定。

这里很难发布完整的代码,因为它由更多部分组成,here is a complete project 在 Delphi 7 中制作。

所以我的问题是,如何在 Web 浏览器控件中使用来自 TAutoIntfObject 扩展对象的事件;如何声明扩展对象,以便我能够处理来自 Web 浏览器控件的事件并将其传递给 IDocHostUIHandler::GetExternal 方法参数仍然保持接口对象引用?

【问题讨论】:

  • 我想你看过这篇文章吧? :delphidabbler.com/articles?article=22&part=3。他们通过 IOleClientSite 使用外部容器。
  • 或者查看 EmbeddedWB 的源代码...
  • @whosrdaddy,这就是我编写代码的地方(甚至在我的问题中链接),但我不知道how the IOleClientSite 在那里发挥作用。每当您通过 external 从 JavaScript 调用方法时,IDocHostUIHandler::GetExternal 方法会请求一个外部对象,该对象必须具有您正在调用的名称的调度方法。这里不需要IOleClientSite。关于 EWB,它对我有什么帮助?只有一个 OnGetExternal 事件,您在其中传递扩展容器,但这就是我实际拥有的。
  • 我不太确定您需要什么。您链接到的example 对我来说非常有效(与 lame EmbeddedWB 实现相反)。查看来源:TExternalContainer = class(TNulWBContainer, IDocHostUIHandler, IOleClientSite) 和主项目中的fContainer := TExternalContainer.Create(WebBrowser1);。这有点棘手,但实际上避免像您那样使用插入器类是一个非常好的主意:TMapBrowser = class(TWebBrowser, IDocHostUIHandler).
  • 我曾经做过相反的事情:从加载在网页中的 ActiveX 进入容器:yoy.be/item.asp?i98 这就是 IOleClientSite 的用武之地。我应该找一些时间来深入研究代码你在这里发帖,看起来很像我做过的事情。

标签: delphi twebbrowser


【解决方案1】:

使用引用计数,即。将 FExtObj 保留为对接口的引用,而不是对象:

  private
    // the extension object
    FExtObj: IDispatch;

...

constructor TMapBrowser.Create(AOwner: TComponent);
var
  AExtObj: TOpenLayersExt;
begin
  inherited Create(AOwner);
  // create extension object
  AExtObj := TOpenLayersExt.Create;
  AExtObj.OnZoomChange := OnZoomChange;
  FExtObj := AExtObj as IDispatch;
end;

destructor TMapBrowser.Destroy;
begin
  FExtObj := nil;
  inherited Destroy;
end;

【讨论】:

  • 我确认,修复引用计数可以解决问题。如果您要进行极简修复,请在第 140 行插入 FExtObj._AddRef;
  • @Stijn,就像their example 中显示的 MS。托德瑞,谢谢!这也很好用。
  • @Stijn,我终于使用了这个解决方案,因为 IE 似乎不规则地释放引用,如果我尝试使用 _AddRef,它们的计数从未减少。还是谢谢!
猜你喜欢
  • 2016-12-04
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
  • 2015-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-17
相关资源
最近更新 更多