Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
扩展TWebBrowser外部对象以执行Delphi代码:如何访问我的表单组件?_Delphi_Interface_Delphi 10 Seattle_Twebbrowser - Fatal编程技术网

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

扩展TWebBrowser外部对象以执行Delphi代码:如何访问我的表单组件?,delphi,interface,delphi-10-seattle,twebbrowser,Delphi,Interface,Delphi 10 Seattle,Twebbrowser,我正在学习DelphiDabbler教程(由Peter Johnson编写),以允许Delphi收听TWebBrowserJavaScript事件 这一直到我看到我的Delphi程序被调用的时候。但是,从那里我需要更新一些表单标签,我看不到从这些过程访问表单的方法。 Delphidabler示例代码通过THintAction.Create(nil)很好地绕过了“直接表单访问”哪一个将完成它的任务: 这让我们能够很好地将外部对象实现与程序的形式解耦 但我想进入我的表格!要传递的数据是整数和字符串。

我正在学习DelphiDabbler教程(由Peter Johnson编写),以允许Delphi收听
TWebBrowser
JavaScript事件

这一直到我看到我的Delphi程序被调用的时候。但是,从那里我需要更新一些表单标签,我看不到从这些过程访问表单的方法。
Delphidabler示例代码通过
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;
表单有一个
属性FContainer:TExternalContainer,格式为Create I do
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实例。

你说你想访问表单,但你真的不想,至少不想直接访问。您确实希望“将外部对象实现与程序的形式很好地解耦”。您真正需要做的就是编写一个函数或过程,在程序中执行您想要的操作,然后从web浏览器调用该函数或过程。这就是解耦和接口的意义所在。您从不直接从另一个应用程序处理属于一个应用程序的数据。相反,您使用函数和过程作为接口。顺便说一句,这就是为什么接口只包含函数和过程原型(以及属性——但它们只是在内部转换为函数和过程)——而不包含数据

现在谈谈你的具体问题。当然,您可以访问表单-它是一个全局变量。假设主窗体的类型为TMainForm,单位名为main.pas,则会有一个名为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应用程序中直接访问。

接受您所说的希望访问表单的建议,但您确实不想访问表单-至少不直接从Dsm中访问,我决定使用
PostMessage
/
SendMessage
(正如我在问题中所暗示的)

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

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;
“我的表单”包含两个实际更新标签的消息处理程序:

procedure UpdateDistMsgHandler(var Msg: TMessage); message UM_UPDATEDIST;
procedure WMCopyData(var Msg : TWMCopyData) ; message WM_COPYDATA;

procedure TFrmGoogleMapsLiveUpdate.UpdateDistMsgHandler(var Msg: TMessage);
begin
   LabelDistance.Caption := IntToStr(Msg.WParam);
end;

procedure TFrmGoogleMapsLiveUpdate.WMCopyData(var Msg: TWMCopyData);
var
   lWhere    : integer;
   lLocation : string;
begin
   lWhere := Msg.CopyDataStruct.dwData;
   lLocation := String(PChar(Msg.CopyDataStruct.lpData));
   if lWhere = 0 then
      LabelVan.Caption := lLocation
   else
      LabelNaar.Caption := lLocation;
end;

啊,对不起,我应该说我只有动态创建的表单(更新我的问题)。这并不意味着我不能访问它们,但我必须查找它们。但我接受您关于解耦的建议。同样的原则也适用。实现中的“uses”子句的要点是我不希望表单位于同一个单元中。这是绕过单元递归的标准方法。如果必要,请使用全局变量应用程序(在VCL.Forms或FMX.Forms中,视情况而定),以查找所需的表单。如果在TWebBrowserExternal中返回表单句柄,如函数GetformHandle():Word?可以使用ObjComAuto.TObjectDispatch提供的后期绑定功能使用。这样,您不需要定义任何接口或类型库。