扩展TWebBrowser外部对象以执行Delphi代码:如何访问我的表单组件?

时间:2016-06-22 10:01:10

标签: delphi interface delphi-10-seattle twebbrowser

我遵循How to call Delphi code from scripts running in a TWebBrowser DelphiDabbler教程(Peter Johnson),允许Delphi听取TWebBrowser JavaScript事件。

这可以达到我看到我的Delphi程序被调用的程度。但是,从那里我需要更新一些表单标签,我看不到从这些程序访问我的表单 DelphiDabbler示例代码很好地避免了直接表单访问的问题。由creating THintAction.Create(nil);执行此操作:

  

这让我们可以很好地将我们的外部对象实现与程序的形式分离

但我想访问我的表格!要传递的数据是整数和字符串 我可以使用PostMessage()和WM_COPYDATA消息,但这些仍然需要表单句柄。并且没有直接的'路线到表格?

相关代码:

type
   TWebBrowserExternal = class(TAutoIntfObject, IWebBrowserExternal, IDispatch)
   protected
      procedure SetVanLabel(const ACaption: WideString); safecall;  // My 3 procedures that are called...
      procedure SetNaarLabel(const AValue: WideString); safecall;   // ... declared in the type library.
      procedure SetDistanceLabel(AValue: Integer); safecall;
   public
      constructor Create;
      destructor Destroy; override;
   end;

type
   TExternalContainer = class(TNulWBContainer, IDocHostUIHandler, IOleClientSite)
   private
      fExternalObj: IDispatch;  // external object implementation
   protected
      { Re-implemented IDocHostUIHandler method }
      function GetExternal(out ppDispatch: IDispatch): HResult; stdcall;
   public
      constructor Create(const HostedBrowser: TWebBrowser);
   end;

constructor TExternalContainer.Create(const HostedBrowser: TWebBrowser);
begin
   inherited Create(HostedBrowser);
   fExternalObj := TWebBrowserExternal.Create;
end;

表单中有一个property FContainer: TExternalContainer;,在FormCreate中我做fContainer := TExternalContainer.Create(WebBrowser);(参数是设计时TWebBrowser),所以 TExternalContainer.fExternalObj已分配给该帐户。

问题

  procedure TWebBrowserExternal.SetDistanceLabel(AValue: Integer);
  begin
     // **From here, how do I send AValue to a label caption on my form?**
  end;

我必须承认界面不是我的强项; - )

[已添加:]注意:我的表单都是动态创建的,当前单元中没有TForm实例。

2 个答案:

答案 0 :(得分:1)

你说你想要访问你的表格,但你真的没有 - 至少不是直接的。你确实希望“很好地将我们的外部对象实现与程序的形式分离”。您需要做的就是编写一个函数或过程来在程序中执行您想要的操作,然后从Web浏览器调用该函数或过程。这就是解耦和接口的全部内容。您从不直接从另一个应用程序处理属于一个应用程序的数据。而是使用函数和过程作为接口。顺便说一下,这就是为什么接口只包含函数和过程原型(和属性 - 但它们只是作为函数和过程在内部翻译) - 从不包含数据。

现在回答您的具体问题。当然,您可以访问您的表单 - 它是一个全局变量。假设您的主窗体是一个名为Main.pas的单元中的TMainForm类型,将会有一个名为MainForm的全局变量

var
  MainForm : TMainForm;

所以在您的webbrowser单元中,在实现部分中,您将放置

implementation

uses Main;

...

procedure TWebBrowserExternal.SetDistanceLabel(AValue: Integer);
begin
   // **From here, how do I send AValue to a label caption on my form?**
   FormMain.MyLabel.Caption := StrToInt( AValue );
end;

在我所说的上下文中,SetDistanceLabel是接口函数,只能从Delphi应用程序中直接访问Form。

答案 1 :(得分:1)

接受建议你说你想要访问你的表格,但你真的不是 - 至少不是直接来自his/her answer的Dsm,我决定使用{ {1}} / PostMessage(正如我在提问中暗示的那样)。

首先,我在SendMessageTWebBrowserExternal的构造函数中传递窗口句柄,并将其存储为私有属性:

TExternalContainer

在FormCreate中,type TWebBrowserExternal = class(TAutoIntfObject, IWebBrowserExternal, IDispatch) private fHandle: HWND; procedure SendLocationUpdate(AWhere: Integer; ALocation: String); // Helper for SetVanLabel/SetNaarLabel protected procedure SetVanLabel(const AValue: WideString); safecall; procedure SetNaarLabel(const AValue: WideString); safecall; procedure SetDistanceLabel(AValue: Integer); safecall; public constructor Create(AHandle: HWND); destructor Destroy; override; end; type TExternalContainer = class(TNulWBContainer, IDocHostUIHandler, IOleClientSite) private fExternalObj: IDispatch; // external object implementation protected { Re-implemented IDocHostUIHandler method } function GetExternal(out ppDispatch: IDispatch): HResult; stdcall; public constructor Create(const HostedBrowser: TWebBrowser; AHandle: HWND); end; 现在创建为

TExternalContainer

fContainer := TExternalContainer.Create(WebBrowser, Self.Handle); 方法实现为:

Set...

带辅助功能:

procedure TWebBrowserExternal.SetDistanceLabel(AValue: Integer);
begin
   PostMessage(fHandle,UM_UPDATEDIST,AValue,0);  //  const UM_UPDATEDIST = WM_USER + 101;
end;

procedure TWebBrowserExternal.SetNaarLabel(const AValue: WideString);
begin
   SendLocationUpdate(1,AValue);
end;

procedure TWebBrowserExternal.SetVanLabel(const AValue: WideString);
begin
   SendLocationUpdate(0,AValue);
end;

我的表单包含两个实际更新标签的消息处理程序:

procedure TWebBrowserExternal.SendLocationUpdate(AWhere: Integer; ALocation: String);
var lCopyDataStruct: TCopyDataStruct;
begin
   lCopyDataStruct.dwData := AWhere;
   lCopyDataStruct.cbData := 2 * 2 * Length(ALocation);
   lCopyDataStruct.lpData := PChar(ALocation);
   SendMessage(fHandle, WM_COPYDATA, wParam(fHandle), lParam(@lCopyDataStruct));
end;