TEmbeddedWB/TWebbrowser:window.external是一个空对象,但可以调用函数,为什么它首先是“空”?

2023-12-29

使用案例(先一些信息):

我制作了一些 HTML/CSS3/Javascript 游戏,可以在特定于平台的可执行文件中的 WebView/嵌入式浏览器中的不同平台上运行。我自己设计了它,因为我厌倦了周围所有的“框架”,这些“框架”告诉我使用他们的框架是多么简单。我不需要这些框架及其令人印象深刻的类和东西,它一定很简单,对吧?另外,由于 Web 视图比本机代码慢,因此它必须简单直接才能获得最佳性能。

所以我设计了一个接口,它可以作为 JavaScript 中的变量使用,无需加载额外的 JavaScript 类(如 cordova 或phonegap 或其他)。因为我也使用 Windows(Windows 无法将对象变量的名称更改为“publish”),所以可以通过 javascript 通过 window.external 访问它。当 html 加载到 webview/浏览器中时,该变量将是一个对象。

Question

这一切都运行得很好(在不同的平台上),但是window.external变量在Windows上似乎是一个空对象,但是当你尝试调用像这样的函数时window.external.vibrate(500)它将被正确执行(该函数存在于该对象的所有平台版本中)。

然而,像typeof window.external.vibrate结果是'undefined'。遍历对象不执行任何操作,例如:

for( var p in window.external ) {
   alert( p );
}

因此,测试外部对象是否是“真实的”外部对象并不容易,并且无法查看支持哪些功能(如果需要)。

对此我能做什么?我错过了什么内在的东西吗?

为了给您提供一些信息,我遵循了这个“指南”:http://www.delphidabbler.com/articles?article=22 http://www.delphidabbler.com/articles?article=22.

我的代码(简化):

类型库:

unit WebBrowserBridge_TLB;

// ************************************************************************ //
// WARNING                                                                    
// -------                                                                    
// The types declared in this file were generated from data read from a       
// Type Library. If this type library is explicitly or indirectly (via        
// another type library referring to this type library) re-imported, or the   
// 'Refresh' command of the Type Library Editor activated while editing the   
// Type Library, the contents of this file will be regenerated and all        
// manual modifications will be lost.                                         
// ************************************************************************ //

// PASTLWTR : $Revision:   1.88.1.0.1.0  $
// File generated on 4-3-2014 6:50:23 from Type Library described below.

// ************************************************************************ //
// Type Lib: ExternalInterface\WebBrowserBridge.tlb (1)
// IID\LCID: {517F7078-5E73-4E5A-A8A2-8F0FF14EF21B}\0
// Helpfile: 
// DepndLst: 
//   (1) v2.0 stdole, (C:\Windows\SysWOW64\stdole2.tlb)
// ************************************************************************ //
{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers. 
interface

uses Windows, ActiveX, Classes, Graphics, OleServer, OleCtrls, StdVCL;

// *********************************************************************//
// GUIDS declared in the TypeLibrary. Following prefixes are used:        
//   Type Libraries     : LIBID_xxxx                                      
//   CoClasses          : CLASS_xxxx                                      
//   DISPInterfaces     : DIID_xxxx                                       
//   Non-DISP interfaces: IID_xxxx                                        
// *********************************************************************//
const
  // TypeLibrary Major and minor versions
  WebBrowserBridgeMajorVersion = 1;
  WebBrowserBridgeMinorVersion = 0;

  LIBID_WebBrowserBridge: TGUID = '{517F7078-5E73-XXXX-B8A2-8F0FF14EF21B}';

  IID_IWebBrowserBridge: TGUID = '{4F995D09-XXXX-4042-993E-C71A8AED661E}';
type

// *********************************************************************//
// Forward declaration of types defined in TypeLibrary                    
// *********************************************************************//
  IWebBrowserBridge = interface;
  IWebBrowserBridgeDisp = dispinterface;

// *********************************************************************//
// Interface: IWebBrowserBridge
// Flags:     (4416) Dual OleAutomation Dispatchable
// GUID:      {4F995D09-CF9E-XXX-993E-C71A8AED661E}
// *********************************************************************//
  IWebBrowserBridge = interface(IDispatch)
    ['{4F995D09-CF9E-4042XXXX-C71A8AED661E}']
    procedure isAvailable; safecall;
    procedure vibrate(ms: Integer); safecall;
  end;

// *********************************************************************//
// DispIntf:  IWebBrowserBridgeDisp
// Flags:     (4416) Dual OleAutomation Dispatchable
// GUID:      {4F995D09-CF9E-XXX-993E-C71A8AED661E}
// *********************************************************************//
  IWebBrowserBridgeDisp = dispinterface
    ['{4F995D09-CF9E-404XXXE-C71A8AED661E}']
    procedure isAvailable; dispid 200;
    procedure vibrate(ms: Integer); dispid 201;
  end;

implementation

uses ComObj;

end.

对象库(类):

unit WebBrowserBridge;

interface

uses
  // Delphi
  ActiveX, SHDocVw, Windows, Classes, ComObj, Dialogs,
  // Project
  IntfDocHostUIHandler, UNulContainer, WebBrowserBridge_TLB;

type
  TWebBrowserBridge = class(TAutoIntfObject, IWebBrowserBridge, IDispatch)
  public
    { IMyExternal methods }
    procedure isAvailable(); safecall;
    procedure vibrate(ms: Integer); safecall;

  public
    constructor Create;
    destructor Destroy; override;
  end;

  {
  TWebBrowserBridgeContainer:
    UI handler that extends browser's external object.
  }
  TWebBrowserBridgeContainer = 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 WBDefaultInterface: IDispatch);
  end;

implementation

uses
  SysUtils, StdActns;

  { TWebBrowserBridgeContainer }
constructor TWebBrowserBridgeContainer.Create(const WBDefaultInterface: IDispatch);
begin
  inherited;
  fExternalObj := TWebBrowserBridge.Create;
end;

function TWebBrowserBridgeContainer.GetExternal(out ppDispatch: IDispatch): HResult;
begin
  ppDispatch := fExternalObj;
  Result := S_OK; // indicates we've provided script
end;


 { TWebBrowserBridge }
constructor TWebBrowserBridge.Create;
var
  TypeLib: ITypeLib;    // type library information
  ExeName: WideString;  // name of our program's exe file
begin
  // Get name of application
  ExeName := ParamStr(0);
  // Load type library from application's resources
  OleCheck(LoadTypeLib(PWideChar(ExeName), TypeLib));
  // Call inherited constructor
  inherited Create(TypeLib, IWebBrowserBridge);
end;

destructor TWebBrowserBridge.Destroy;
begin
  inherited;
end;

procedure TWebBrowserBridge.isAvailable();
begin
 //Result:=1;
end;

procedure TWebBrowserBridge.vibrate(ms: Integer);
begin
  windows.beep( 100, ms );
  //showMessage( IntToStr( ms ));
end;

PS:

我还想知道如何在类型库中创建函数,因为它只允许创建过程或属性(但不支持像 Android 上的属性)。

EDIT:

另请参阅我的回答,但问题仍然悬而未决,因为PS above.


可以使用更简单的方法来实现externalDelphi 中的方法,使用以下提供的后期绑定功能ObjComAuto.TObjectDispatch http://docwiki.embarcadero.com/Libraries/en/System.Win.ObjComAuto.TObjectDispatch.

这样您就不需要定义任何接口或类型库。您所需要的只是一个实现所需事件的简单类,以及由$方法信息 http://docwiki.embarcadero.com/RADStudio/en/METHODINFO_directive_(Delphi).

您可以实现过程和函数,并接收 Delphi 类型或 javascript 对象作为参数。 Javascript 对象也可以从 Delphi 中使用(属性和方法都可以访问)。

Example:(只需在表单中放置 TEmbeddedWB)

uses MSHTML_EWB, ObjComAuto;

type
{$METHODINFO ON} // activate detailed RTTI
  TJavascriptReceiver = class
    procedure MyMouseMove(event: variant);
    procedure MyClick(event: variant);
    function MyGet(msg: string): string;
  end;
{$METHODINFO OFF}

{ TJavascriptReceiver }

procedure TJavascriptReceiver.MyMouseMove(event: variant);
begin
  Form1.Caption := IntToStr(event.clientX) + ', ' + IntToStr(event.clientY);
end;

procedure TJavascriptReceiver.MyClick(event: variant);
var
  w: variant;
begin
  w := (Form1.EmbeddedWB1.Document as IHTMLDocument2).parentWindow;
  w.testGet('Caption: ');
end;

function TJavascriptReceiver.MyGet(msg: string): string;
begin
  Result := msg + Form1.Caption;
end;

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
var
  strs: TStringStream;
begin
  strs := TStringStream.Create;
  try
    strs.WriteString(
      '<!DOCTYPE html>'
      +'<html>'
      +'<head>'
      +'  <style>'
      +'    html, body { margin: 0; padding: 0; height: 100%; }'
      +'  </style>'

      +'  <script>'
      +'    function testGet(msg) {'
      +'      alert(external.MyGet(msg));'
      +'    }'
      +'  </script>'
      +'</head>'

      +'<body'
      +'  onmousemove="external.MyMouseMove(event)"'
      +'  onclick="external.MyClick(event)"'
      +'>'
      +'Click anywhere'
      +'</body>'
      +'</html>'
    );
    EmbeddedWB1.LoadFromStream(strs);
  finally
    strs.Free;
  end;
end;

procedure TForm1.EmbeddedWB1GetExternal(Sender: TCustomEmbeddedWB;
  var ppDispatch: IDispatch);
begin
  ppDispatch := TObjectDispatch.Create(TJavascriptReceiver.Create);
end;

Note:

Javascript 数组是稀疏的 https://stackoverflow.com/questions/1510778/are-javascript-arrays-sparse,因此您无法使用通常的方法从 Delphi 访问它们myArray[3]句法。相反,您需要像使用属性一样使用索引,即某种myArray.3。 Delphi不直接支持这一点,但是使用ComObj.GetDispatchPropValue http://docwiki.embarcadero.com/Libraries/en/System.Win.ComObj.GetDispatchPropValue: GetDispatchPropValue(myArray, '3')。更多信息here https://stackoverflow.com/a/17843836/859646.

Edit:

有关如何迭代的信息,请参阅我的其他答案window.external方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TEmbeddedWB/TWebbrowser:window.external是一个空对象,但可以调用函数,为什么它首先是“空”? 的相关文章

随机推荐

  • URI 太长时 Chrome 崩溃

    我正在为我的 HTML5 游戏制作一个导出功能 我当前的保存方法是游戏数据的粗略序列化 然后 this is Javascript var gameData abc this is actually a HUGE string of ove
  • 使用 PHP 从 Youtube 视频 URL 获取 Youtube 视频缩略图

    假设我有一个 YouTube 视频网址www youtube com watch v B4CRkpBGQzU feature youtube gdata par1 1 par2 2 我想获取视频缩略图 gt i3 ytimg com vi
  • Android Espresso IdlingResources 和片段/活动转换

    我有一个托管片段 F1 的活动 单击按钮后 F1 被另一个片段 F2 替换 当按下后退按钮时 应用程序通过一个按钮从 F2 返回到 F1退出过渡动画片 我的 Espresso 测试用例大致如下所示 Test public void pres
  • Django 和 MySQL unicode 错误

    我正在得到一个Incorrect string value Exception Value Incorrect string value xEA xB0 x95 xED x95 x98 for column object repr at r
  • 如何将存储过程的多个输出抓取到临时表中

    我的存储过程返回两个输出 我想在另一个存储过程中使用其中一个 因此尝试获取临时表中的第二个输出 但由于两个输出的结构不同 因此我总是得到 列名称或提供的值的数量与表定义不匹配 即使我更改输出的顺序 第一个输出第二个 第二个输出第一个 它也不
  • 如何在R中保存foreach循环的输出

    我在保存数据输出后遇到问题foreach loop 这是读取我的数据并处理它的函数 readFiles lt function x data lt read table filelist skip grep Begin Data Text
  • Java 中最终字符串的串联是如何完成的?

    当我编译这个片段时 public class InternTest public static void main String strings final String str1 str final String str2 ing Str
  • Netbeans 中的 Git 控制台

    我刚刚安装了 Netbeans 8 我想开始使用 Git 有很多按钮 菜单等 但在哪里可以找到 Git 控制台 我使用Windows 如果您想要控制台 您可能最好直接安装它 IDE 通常只提供菜单集成选项 Git 的网站有 Windows
  • Symfony2主义mysql IN查询

    我有一系列产品 ID 我必须像这样进行查询 SELECT FROM products WHERE pid IN 1 2 8 4 etc 我的 id 位于变量 pids 中 qb em gt createQueryBuilder query
  • 如何使用 Amazon AWS Elastic Beanstalk 安装 PHP 扩展?

    我们在 EC2 实例上的 PHP 应用程序中使用 aws elastic beanstalk 由于我们选择了负载平衡 它会不断地更改实例 我想知道如果我们安装 PHP 插件 它会受到实例更改的影响还是在新实例中也可用 提出这个问题是因为我们
  • macOS 上 CLion 中的 std::unordered_map

    我怎样才能看到元素std unordered map在 CLion 调试器中 有一些recipe https blog jetbrains com clion 2015 05 debug clion 怎么看std map元素 但它不适用于s
  • 添加两个 NSDate

    我有两个 NSDate 日期和时间 我想以这样的方式添加它们 以便我从日期中获取日期 从时间中获取时间 关于我如何做到这一点有什么建议吗 Cheers Nik 如果我没听错的话NSDates dateByAddingTimeInterval
  • 在 Symfony 1.4 中重命名“web”文件夹

    我想在 symfony 1 4 中将 web 文件夹重命名为 html 不幸的是 搜索这方面的文档却一无所获 除了在 1 0 中如何实现这一点之外 这似乎不起作用 首先 您不必重命名它 您可以只创建一个符号链接 除非您运行的是 Window
  • 使用 MySQL 和 ejabberd 进行高效的外部排班

    Question 请注意 这个问题的解决方案就在下面 使用 Eugen 的视图思想 我正在为 PHP MySQL 用户驱动的网站编写一个聊天模块 允许两个用户交朋友 并选择 eJabberd 作为聊天系统 我已经使用 PHP 守护程序成功设
  • 透明外壳。如何将很长的 JavaScript 拆分为多行?

    我有一个 JS 压缩文件 长约 14k 并且在一行中 这会在 Clear Case 上造成一些问题 导致无法办理登机手续 有没有办法修复clearcase 如果我想将JS文件拆分为多行 插入换行符时需要注意什么吗 显然我不会分割字符串或数字
  • schema.org 中的产品类别?

    用作参考 https support google com webmasters answer 146750 hl en https support google com webmasters answer 146750 hl en 您会注
  • 如何加密/解密 XML 文件?

    我正在尝试加密 解密 XML 文件 我找到了这个加密示例 但我不知道如何解密 任何想法 谢谢 Load this XML file System Xml XmlDocument myDoc new System Xml XmlDocumen
  • ArCore Sceneform:检测图像时播放.mp4视频

    当我找到图像时 我想在其上方放置文本和视频 文本视图放置在场景上 但视频没有放置在场景中 它只是添加到中间的主布局中 我正在使用组件 VideoView 我不确定这是问题所在 override fun onCreate savedInsta
  • 如何使用PHP给上传的图片添加水印

    如何使用 PHP 对上传的图片添加水印 示例链接 http www kitebeaches com kitesurf uploadPicture NIRVANA Club Village html http www kitebeaches
  • TEmbeddedWB/TWebbrowser:window.external是一个空对象,但可以调用函数,为什么它首先是“空”?

    使用案例 先一些信息 我制作了一些 HTML CSS3 Javascript 游戏 可以在特定于平台的可执行文件中的 WebView 嵌入式浏览器中的不同平台上运行 我自己设计了它 因为我厌倦了周围所有的 框架 这些 框架 告诉我使用他们的