Cod*_*eat 3 javascript delphi interface webbrowser-control
用例(首先是一些信息):
我制作了一些HTML/CSS3/Javascript游戏,可以在平台特定的可执行文件中在WebView/Embedded浏览器中的不同平台上运行.我自己设计了它,因为我厌倦了所有的"框架",告诉我使用它们的框架是多么简单.我不需要这些框架的所有臃肿与他们令人印象深刻的类和东西,它必须简单作为ABC,对吧?另外,因为webview比本机代码慢,所以它必须简单直接才能获得最佳性能.
所以我设计了一个在javascript中作为变量提供的接口,无需加载额外的javascript类(如cordova或phonegap或其他).因为我也使用Windows(Windows无法将对象变量的名称更改为'publish'),所以可以通过javascript通过window.external访问它.在webview /浏览器中加载html时,此变量将成为对象.
题
这一切都很好(在不同的平台上),但window.external变量似乎是Windows上的一个空对象,但是当你尝试调用一个类似的函数时window.external.vibrate(500),它将被执行而没有错误(此函数存在于该对象的所有平台版本中).
然而,类似的typeof window.external.vibrate结果'undefined'.遍历对象不会做任何事情,例如:
for( var p in window.external ) {
alert( p );
}
Run Code Online (Sandbox Code Playgroud)
因此,测试外部对象是否是"真正的"外部对象并且不可能看到支持哪些功能(如果需要)并不容易.
我该怎么办?我想念一些东西吗?
为了给你一些信息,我已经按照这个'指南':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.
Run Code Online (Sandbox Code Playgroud)
对象库(类):
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;
Run Code Online (Sandbox Code Playgroud)
PS:
我还想知道如何在类型库中创建一个函数,因为它只允许创建过程或属性(但不像Android那样支持属性).
编辑:
另请参阅我的回答,但由于上面的PS,问题仍然存在.
使用ObjComAuto.TObjectDispatchexternal提供的后期绑定功能,可以使用更简单的方法在Delphi中实现方法.
这样您就不需要定义任何接口或类型库.您需要的只是一个实现所需事件的简单类,以及$ METHODINFO提供的扩展RTTI信息.
您可以实现过程和函数,并接收Delphi类型或javascript对象作为参数.也可以从Delphi中使用Javascript对象(可以访问属性和方法).
示例:(只需在表单中删除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;
Run Code Online (Sandbox Code Playgroud)
注意:
Javascript数组很稀疏,因此您无法使用通常的myArray[3]语法从Delphi访问它们.相反,你需要使用索引,就好像它是一个属性,即某种类型myArray.3.这不是Delphi直接支持的,而是使用ComObj.GetDispatchPropValue : GetDispatchPropValue(myArray, '3'). 更多信息在这里.
编辑:
有关如何通过window.external方法进行迭代的信息,请参阅我的其他答案.
| 归档时间: |
|
| 查看次数: |
1681 次 |
| 最近记录: |