圖片來源:網路 |
系統維護一段時間之後,總會遇到各式各樣的需求,哪怕是改字改公式這樣的小需要,都必須把專案修改後重新編譯以及發佈這樣的改版模式,才能讓使用者順利使用。
『如果有一套語言引擎嵌入到系統中,我只需要改腳本就能夠無痛更新。』
這樣的念頭在我腦海中出現,有想法就來試試看。
在開始之前,自造輪子不如使用輪子,來看看 3rd party 有沒有好用的函式庫可以使用,如果有就不需要再重新寫起。
Devart 的 VirtualDAC (建議售價:79.95 鎂起)
VirtualDAC 的 VirtualQuery 概念圖 (圖片來源:Devart) |
JSEngine (建議售價:80 鎂起)
JSEngine 展示畫面 (圖片來源:WinSoft) |
ScriptGate (Open source for FireMonkey)
ScriptGate 官網 |
包裝 TWebBrowser,讓 Delphi 利用它和 JavaScript 進行交互作業,從 Delphi 10.2 開始支援,使用 FireMonkey 框架,也能夠順利跨平台,有多平台開發的需求者一定要來試用看看。
其它對我而言學習曲線蠻高的,以上就我可以理解使用的項目分享給大家參考。
因為現有的專案仍舊是 VCL,所以 ScriptGate就無法應用在專案裡面,不過,既然可以透過 TWebBrowser 來和 JavaScript 互動,想必 VCL 應該也能如法泡製才是。
ScriptGate for VCL DIY
本著踩在巨人的肩膀上看世界為原則,谷哥哥給了一個令人驚奇的答案:
果然已經有人做好了!
在 http://delphidabbler.com 裡的 Article 14 和 21 兩篇文章,就已經有 ScriptGate 的內容了。
感謝 Mauricio Julio 貢獻,讓我們可以用到這麼好的作品 |
HTML & JavaScript
在這邊重點有兩個:- JavaScript DoEval function
- Input tag
Delphi
在Delphi中主要還是對TWebBrowser進行存取,文章的範例不難,在這邊複製貼上:function ExecuteJavaScript(WebBrowser:TWebBrowser; Code: string):Variant;
var
Document:IHTMLDocument2;
Window:IHTMLWindow2;
begin
// execute javascript in webbrowser
Document:=WebBrowser.Document as IHTMLDocument2;
if not Assigned(Document) then Exit;
Window:=Document.parentWindow;
if not Assigned(Window) then Exit;
try
Result:=Window.execScript(Code,'JavaScript');
except
on E:Exception do raise Exception.Create('Javascript error '+E.Message+' in: '#13#10+Code);
end;
end;
function GetElementIdValue(WebBrowser:TWebBrowser; TagName,TagId,TagAttrib:String):String;
var
Document: IHTMLDocument2;
Body: IHTMLElement2;
Tags: IHTMLElementCollection;
Tag: IHTMLElement;
I: Integer;
begin
Result:='';
if not Supports(WebBrowser.Document, IHTMLDocument2, Document) then
raise Exception.Create('Invalid HTML document');
if not Supports(Document.body, IHTMLElement2, Body) then
raise Exception.Create('Can''t find );
Tags := Body.getElementsByTagName(UpperCase(TagName));
for I := 0 to Pred(Tags.length) do begin
Tag:=Tags.item(I,EmptyParam) as IHTMLElement;
if Tag.id=TagId then Result:=Tag.getAttribute(TagAttrib,0);
end;
end;
TWebBrowser 在存取上其實還有些細節,不一定要用 UWebBrowserWrapper 單元,但用它不吃虧,於是最終測試碼如下:
procedure TForm2.Button2Click(Sender: TObject);
var
LWbWra: TWebBrowserWrapper;
begin
LWbWra := TWebBrowserWrapper.Create(WebBrowser1);
try
LWbWra.NavigateToLocalFile(ExtractFilePath(Application.ExeName)+'test1.htm');
ExecuteJavaScript(LWbWra.WebBrowser,'DoEval("'+Edit1.Text+'");');
Caption := GetElementIdValue(LWbWra.WebBrowser,'input','result','value');
except
on E:Exception do
raise E
end;
LWbWra.Free;
end;
每一次的呼叫都會重新載入 HTML 檔案,所以修改完就可即時測試程式內容。
由於 Delphi 所附的 TWebBrowser 的核心是系統內的 Internet Explorer (IE),因此在 JavaScript 的支援上要留意 OS 各版的相容性,這點請開發者務必要留意。
以上各家的 Script Engine 提供給大家參考。 下次見 ^_^
===2019/09/25更新===
因為 VCL TWebBrowser 使用的就是 IE 核心,抓這個元件來用其實有點繞遠路了。
按照【Delphi中ScriptControl的高级应用】這篇所言,可以呼叫 MSScriptControl.ScriptControl ActiveX 元件,如此一來就可以把 TWebBrowser 這麼大的元件放下。
唯二的缺點大概就是 Debug 比較困難這件事。
另一方面,萬惡的 IE 本身也有很多漏洞,諸如:
- 微軟緊急修補JSsript引擎,抑制IE 0-day在野攻擊
- 漏洞多得補不完,微軟本月將關閉Windows 7、8上IE11的VBScript
- 預防重於治療,停用Windows Script Host 可防止勒索軟體哦!(JScript)
但遇到被系統管理員限制等情形,軟體功能會被很大的限縮,不管是採行 TWebBrowser 或 ScriptControl 解決方案都比須要留意。
再者,被限縮事小,如果又因為漏洞而被當駭客的攻擊跳板,進而造成嚴重資安問題,就得不償失了!
====== 2022/01/14 ======
ScriptEngine 除了有個難以 Debug 的小缺點外,它其實還蠻方便的,Eden 做了兩個練習:
查詢 JScript Engine 版本
程式碼
uses
ComObj;
procedure TForm2.btnscriptVersionClick(Sender: TObject);
var
sc : OleVariant;
begin
sc := CreateOleObject('MSScriptControl.ScriptControl.1');
sc.Language :='JavaScript'; // Eden 2022/01/14
sc.AddCode(mmoJscriptVersion.Text);
lbJscriptVersion.Caption := sc.Run('GetScriptEngineInfo');
sc := Unassigned;
end;
JS 程式碼參考微軟說明手冊,可以得到 Windows 10 的 JScript 版本為 5.8,相當於 JavaScript 1.5 (2000年) 版本。
JSON 字串化
程式碼
uses
ComObj;
procedure TForm2.btnscriptVersionClick(Sender: TObject);
var
sc : OleVariant;
begin
sc := CreateOleObject('MSScriptControl.ScriptControl.1');
sc.Language :='JavaScript'; // Eden 2022/01/14
sc.AddCode(mmoJson2.Text);
sc.AddCode(mmoJSON.Text);
lbJSON.Caption := sc.Run('getJSONDemo');
sc := Unassigned;
end;
因為 JScript 要向下相容 IE6, 7,所以並未將 JSON 物件啟用 (ECMA-262 3rd edition + ECMA-327(ES-CP) non JSON),在這裡我引入外部 JSON2 檔案,再取用微軟文件的範例程式,可以順利使用 JSON!
See also :
- Devart VirtualDAC
- Six Easy Ways To Embed JavaScript Engines In Your Delphi 10.2 Tokyo Apps
- WinSoft JSEngine
- ScriptGate
- How to load and save documents in TWebBrowser in a Delphi-like way
- How to call JavaScript functions in a TWebBrowser from Delphi
- Delphi中ScriptControl的高级应用
- [維基百科]JScript
- JScript Language Reference (Windows Scripting - JScript) JScript 微軟文件
- [Github]MSScriptControl_TLB.pas
沒有留言:
張貼留言