Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2022年04月15日] [更新 2022年04月21日] Delphi 一般・その他
ScriptGate による JavaScript の関数実行と Delphi のメソッド実行
動作確認等 Windows 10 ビルド 19042 Pro 64 bit + Delphi 10.4 Community VCL-32
Delphi 10.2 以降、TWebBrowser 用サンプル
[整理番号 - 1092]







ScriptGate による JavaScript の関数実行と Delphi のメソッド実行


以下の記事に、TWebBrowser で表示しているウェブページの JavaScript の関数実行と、JavaScript から Delphi のメソッドを実行するサンプルがあります。それらは、最初の記事以外は。JavaScript の window オブジェクトの external の機能を利用する方法です。



ScriptGate というライブラリを使用すると、上のリンクの記事のサンプルと同じ機能を簡単なコードで実現できます。ScriptGate は、Delphi 10.2 以降で利用可能です。






01_ScriptGate ライブラリの入手


VCL 用の ScriptGate は以下のページから入手できます。



図1
ScriptGate の入手
  • 今回は Download ZIP でダウンロード

ダウンロードしたら ZIP 書庫を解凍展開します。[ScruotGate] フォルダを任意の場所にコピーまたは移動して、ライブラリパスを通します。これで準備完了です。



図2
ZIP 書庫の構成
  • 解凍展開
  • [ScriptGate] フォルダを任意の場所にコピーまたは移動
  • [ScriptGate] フォルダにライブラリパスを通す




02_Delphi から JavaScript の関数を実行して戻り値を取得


Delphi から JavaScript の関数を実行して、その関数の戻り値を取得するサンプルです。
以下がテストに使用した HTML コードです。 このコードを JavaScriptTest.html という名前で保存して 実行時に TWebBrowser で表示しています。このコードは UTF-8 で保存してテストしています。



リスト1
テストに使用した HTML のコード。UTF-8 で保存
<html> 
<head> 
  <meta charset="utf-8">
  <script type="text/JavaScript"> 
    function helloJS() {  
      return "Hello !!"; 
    }
  </script> 
</head> 

<body> 
  テスト用のウェブページです。
</body> 
</html>


フォームに TWebBrowser と TButton を配置して、Button1 クリックのイベントを実装します。
下図はが実行結果です。表示している文字列は、JavaScript の関数 helloJS の return の値です。



図3
フォームの Butt1 をクリック
  • JavaScript の関数を実行して戻り値を表示

サンプルのコードです。
ScriptGate を使用するには、uses に SG.ScriptGate を追加して TScriptGate 型ま変数を宣言します。実行時にそのインスタンスを生成して使用します。JavaScript の関数を実行するには TScriptGate.CallScript メソッドを使用します。



リスト2
Delphi から JavaScript の関数を実行して戻り値を取得
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, 
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.OleCtrls, SHDocVw, 
  Vcl.StdCtrls, SG.ScriptGate;

type
  TForm1 = class(TForm)
    Button1: TButton;
    WebBrowser1: TWebBrowser;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    FScriptGate: TScriptGate;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  TWebBrowser でウェブページ (HTML コード) を表示
//  TScriptGate のインスタンを生成
//  Create メソッドの最後の引数は HTML 内で使用する識別子。名前は任意
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  WebBrowser1.Navigate(ExpandFileName('JavaScriptTest.html'));
  FScriptGate := TScriptGate.Create(Self, WebBrowser1, 'delphi');
end;

//=============================================================================
//  JavaScript の関数を実行して戻り値を取得
//  実行する JavaScript の関数名は、CallScript の第 1 引数 (文字列)
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  FScriptGate.CallScript(
    'helloJS()',
    procedure(const iResult: string)
    begin
      ShowMessage(iResult);
    end
  );
end;

end.


Eval という名前のメソッドもあります。構文は CallScript メソッドと同じです。



procedure TForm1.Button1Click(Sender: TObject);
begin
  FScriptGate.Eval(
    'helloJS()',
    procedure(const iResult: string)
    begin
      ShowMessage(iResult);
    end
  );
end;




03_リンクと JavaScript から Delphi のメソッドを実行


TWebBrowser 側から Delphi のメソッドを実行するサンプルです。
以下が、テストに使用した HTML のコードです。このコードを JavaScriptTest.html という名前で保存して 実行時に TWebBrowser で表示しています。このコードは UTF-8 で保存してテストしています。
前項で使用した HTML コードに JavaScript の関数を 1 追加しています。更に、リンクとボタンを各々 1 つ追加しています。リンクをクリック、あるいはボタンをクリックすると Delphi のメソッドを実行します。

HTML から Delphi のメソッドを実行するには、<a> タグの href 属性のリンク先として設定します。以下のコード中の delphi は識別子です。任意の名前が使用できますが、TScriptGate.Create で指定した識別子と同じにします。識別子の次が Delphi のメソッド名と引数の設定です。



リスト3
テストに使用した HTML のコード。UTF-8 で保存
<html> 
<head> 
  <meta charset="utf-8">  
  <script type="text/JavaScript"> 
    function helloJS() {  
      return "Hello !!"; 
    }
    function testScript(msg) {
      IntVal = 1230;
      document.location.href = "delphi:HelloDelphi(" + msg + "," + IntVal + ")";
    }      
  </script> 
</head> 

<body> 
  テスト用のウェブページです。
  <br>
  <br>
  下のリンクをクリックすると Delphi のメソッドを実行します  <br> 
  <a href = "delphi:linkclick(Test Value = , 5200)">Delphi のメソッド実行</a>
  <br>
  <br>
  下のボタンをクリックすると JavaScript の関数から Delphi のメソッドを実行します。
  <br> 
  <form action="" method="post" enctype="" name="delact">
  <input type="button" name="test1" value="Script 実行" onclick="testScript('TEST')">
  </form>        
</body> 
</html>


フォームのユニットにメソッドを実装して、コンパイルして実行した結果です。
ブラウザのリンク部分をクリックすると Delphi の TForm1 のメソッド linkclick を実行します。Delphi 側では、HTML から渡された引数の値をダイアログで表示します。



図4
リンクをクリック
  • Delphi のメソッドを実行
  • メソッドに渡した値を表示

今度はブラウザの [Script 実行] のボタンをクリックします。
JavaScript の関数が執行され、その関数内で Delphi のメソッドを実行します。Delphi のメソッドでは、HTML から渡された引数の値をダイアログで表示します。



図5
ブラウザのボタンをクリック
  • JavaScript の関数を実行
  • その関数から Delphi のメソッドが実行される
  • メソッドに渡した値を表示

テストに使用したフォームのユニットのコードです。



リスト4
リンクと JavaScript から Delphi のメソッドを実行
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, 
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.OleCtrls, SHDocVw, 
  Vcl.StdCtrls, SG.ScriptGate;

type
  TForm1 = class(TForm)
    Button1: TButton;
    WebBrowser1: TWebBrowser;
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
    FScriptGate: TScriptGate;
  public
    { Public 宣言 }
    procedure linkclick(AText: string; IntValue: Integer);
    procedure HelloDelphi(MsgText: string; IntVal: Integer);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  TWebBrowser でウェブページ (HTML コード) を表示
//  TScriptGate のインスタンを生成
//  Create メソッドの最後の引数は HTML 内で使用する識別子。名前は任意
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.Enabled := False;

  WebBrowser1.Navigate(ExpandFileName('JavaScriptTest.html'));
  FScriptGate := TScriptGate.Create(Self, WebBrowser1, 'delphi');
end;

//-----------------------------------------------------------------------------
//  HTML のリンクをクリックした時に呼び出されて実行するメソッド
//  このメソッドは public 部iに宣言する
//  メソッド名と引数の数と型は任意
//-----------------------------------------------------------------------------
procedure TForm1.linkclick(AText: string; IntValue: Integer);
var
  Ltext : string;
begin
  Ltext := 'リンクをクリックした結果' + sLineBreak + Atext + IntToStr(IntValue);
  MessageBox(Handle, PChar(Ltext), '実行結果', MB_ICONINFORMATION);
end;

//-----------------------------------------------------------------------------
//  ウェブページのボタンクリックで呼び出されて実行するメソッド
//  このメソッドは public 部iに宣言する
//  メソッド名と引数の数と型は任意
//-----------------------------------------------------------------------------
procedure TForm1.HelloDelphi(MsgText: string; IntVal: Integer);
var
  Ltext : string;
begin
  Ltext := 'ウェブページのボタンクリックの結果' + sLineBreak
         + MsgText + sLineBreak + IntToStr(IntVal);
  MessageBox(Handle, PChar(Ltext), '実行結果', MB_ICONINFORMATION);
end;

end.




04_Delphi のメソッドの文字列引数に日本語がある場合


前項のサンプルで、Delphi のメソッドの引数に日本語の文字列がある場合です。
ScriptGate では、Delphi のメソッドを HTML から呼び出すのに URL へのリンクとして設定します。したがって、ASCII 文字ではない文字はエンコードが必要です。エンコードしないと、Delphi 側で取得した日本語が文字化けします。JavaScript 内で処理する場合は、JavaScript の encodeURI 関数が利用できます。



リスト5
日本語または日本語を含文字列はエンコードか必要
<html> 
<head> 
  <meta charset="utf-8">  
  <script type="text/JavaScript"> 
    function helloJS() {  
      return "Hello !!"; 
    }
    function testScript(msg) {
      msg = encodeURI(msg + ' - 日本語はエンコード');
      IntVal = 1230;
      document.location.href = "delphi:HelloDelphi(" + msg + "," + IntVal + ")";
    }      
  </script> 
</head> 

<body> 
  テスト用のウェブページです。
  <br>
  <br>
  下のリンクをクリックすると Delphi のメソッドを実行します  <br> 
  <a href = "delphi:linkclick(%E5%BC%95%E6%95%B0 = , 5200)">Delphi のメソッド実行</a>
  <br>
  <br>
  下のボタンをクリックすると JavaScript の関数から Delphi のメソッドを実行します。
  <br> 
  <form action="" method="post" enctype="" name="delact">
  <input type="button" name="test1" value="Script 実行" onclick="testScript('TEST')">
  </form>        
</body> 
</html>


実行結果です。Delphi 側のコードを変更する必要はありません。TScriptGate がデコードします。



図6
リンクをクリック
図7
ウェブページのボタンをクリック




05_TWebBrowser から外部プグラムを起動


TWebBrowser から外部のプログラムを実行するには、メソッドの実装部で ShellExecute 関数等を使用します。以下のコードはコマンドプロンプトを起動する例です。
以下のコードをコンパイルして実行すると、本ページを TWebBrowser で表示します。下のボタンをクリックすると、コマンドプロンプトが起動します。



図8
ブラウザからコマンドプロンプトを起動

リスト6
TWebBrowser からコマンドプロンプトを起動。TWebBrowse は TPanel に alClient にして配置
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, 
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.OleCtrls, SHDocVw, 
  Vcl.StdCtrls, SG.ScriptGate, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    WebBrowser1: TWebBrowser;
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
    FScriptGate: TScriptGate;
  public
    { Public 宣言 }
    procedure BrowserBtnClick;
  end;

var
  Form1: TForm1;

implementation

uses
 Winapi.ShellAPI;

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  TWebBrowser でウェブページを表示
//  TScriptGate のインスタンを生成
//  Create メソッドの最後の引数は HTML 内で使用する識別子
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
  LURL : string;
begin
  LURL := 'http://mrxray.on.coocan.jp/Delphi/Others/JavaScript_ScriptGate.htm#05';
  WebBrowser1.Navigate(LURL);
  FScriptGate := TScriptGate.Create(Self, WebBrowser1, 'delphi');
end;

//-----------------------------------------------------------------------------
//  当サイトの特定のウェブページボタンクリックで呼び出して実行するメソッド
//  このメソッドは public 部iに宣言する
//-----------------------------------------------------------------------------
procedure TForm1.BrowserBtnClick;
var
  LFile   : string;
  LParams : string;
begin
  LFile   := 'cmd.exe';
  LParams := '';
  ShellExecute(Handle, 'open', PChar(LFile), PChar(LParams), nil, SW_SHOWNORMAL);
end;

end.


[備考]
一般的なウェブブラウザアプリで、任意の EXE が直接起動できてしまうとセキュリティ的に問題です。




06_URI スキームを使用してワードの文書等をブラウザから表示


URI スキームが定義されているアプリは、アプリ、あるいはそのアプリが扱うファイルを、ShellExecute 関数を使用しなくてもウェブブラウザから「開く」ことができます。

ワードやエクセル等の Microsoft Office のアプリには URI スキームが定義されていて、ワードの文書やエクセルのブックのファイルパスを指定してウェブブラウザから開くことができます。URI スキームを使用しないで、ファイルのパス名だけの場合は、ウェブブラウザの種類や設定によって挙動が異なります。この場合、ローカルファイルは開けません。
URI スキームを使用すると、常に「開く」動作になります。

以下のコード中のリンク部分をクリックすると動作を確認できます。また、HTML ファイルとして保存して、そのファイルのパス名をウェブブラウザのアドレス欄に入力して表示すれば、ローカルな環境としての動作を確認できます。
このコードは、D:\000 フォルダに WordTestdocx, ExcelTest.xlsx ファイルがあると仮定しています。



<html>
<head>
  <meta charset="utf-8">
</head>
<body>
   --- UWP アプリを起動 ---<br>

<a href="ms-settings:">設定</a><br>
<a href="ms-photos:">フォト</a><br>
<a href="ms-paint:">ペイント 3D</a><br>
<br>
    --- URI スキームを使用してワードの文書やエクセルのブックを開く ---<br>

<a href="ms-word:ofe|u|file:///d:/000/WordTest.docx">ワード文書 (ローカル)</a><br>
<a href="ms-excel:ofe|u|file:///d:/000/ExcelTest.xlsx">エクセルのブック (ローカル)</a><br>
<a href="ms-word:ofv|u|http://mrxray.on.coocan.jp/Others/WordTest.docx">ワード文書</a><br>
<br>
    --- ファイルのパスへの直接リンク ---<br>
    --- ブラウザによって挙動が異なる。file:/// は開けない   ---<br>

<a href="file:///d:/000/WordTest.docx">ワード文書 (ローカル)</a><br>
<a href="file:///d:/000/ExcelTest.xlsx">エクセルのブック (ローカル)</a><br>
<a href="http://mrxray.on.coocan.jp/Others/WordTest.docx">ワード文書</a><br>
</body>
</html>


ネットワークコンピュータのファイルの場合、リンク先は、例えば以下のようになります。Vm-Win7-32 がコンピュータ名です。000 は、共有フォルダ名です。


ms-word:ofe|u|file://Vm-win7-32/000/WordTest.docx



URI スキームのリンクをクリックすると、Google Chrome (バージョン: 100.0.4896.127 - 64 ビット) では、ブラウザの画面上部中央に下図のダイアログが現れます。[Word を開く] をクリックします。



図9
Google Chrome の場合
  • [Word を開く] をクリックして開く

URI スキームのリンクをクリックすると、Chromium 版の Microsoft Edge (バージョン 100.0.1185.44 - 64 ビット) の場合、ブラウザの画面上部中央に下図のダイアログが現れます。[開く] をクリックすると、ワードの文書が開きます。



図10
Microsoft Edge の場合
  • [開く] をクリックする

FireFox (バージョン 99.0.1 - 64 ビット) の場合、デフォルトでは 2 段階の操作になります。
URI スキームのリンクをクリックすると、ブラウザの画面上部中央に下図のダイアログが現れます。[プログラムを選択] をクリックしす。表示されたダイアログで [リンクを開く] をクリックします。
[他のプログラムを選択] をクリックすると、ファイルの選択ダイアログが表示されます。そのダイアログでプログラムを選択します。[常にこのプログラムで ms-word リンクを開く] をチェックすると、次回からは、最初のダイアログで [リンクを開く] をクリックして開くようになります。


図11
FireFox のば場合は 2 段階の操作
  • [プログラムを選択] をクリック
図12
[リンクを開く] をクリック

[備考]
file:/// は ファイル URI と呼ばれています。URI スキームを使用しない場合、メジャーなウェブブラウザでは、セキュリティ上、リンクをクリックしても開かないようになっています。ローカル環境下における html ファイルをウェブブラウザで表示した場合は、拡張子に関連付けされたアプリで開くことができますが、開くまでの操作がブラウザによって異なります。この時、ブラウザによっては自動的にダウンロードすることがあります。ZIP 書庫のように、ダウンロードが目的でない限り、にURI スキームを使用しないファイルのリンクは避けた方が無難と言えます。

file:/// の 3 つ目の / は、ホスト名の省略を意味します。正確には 「file://host名/ファイルパス」で、ローカルコンピュータの場合は file://localhost/ と同じです。この場合、3 つ目の / を省略して、file:// でも動作します。





07_このページのスクリプトでエラーが発生しました


当サイトのページを TWebBrowser で表示する際、下図のような JavaScript の実行エラーが発生したら、IE のレンダリングの互換モードを IE 11 に変更してください。IE コントロールである TWebBrowser のレンダリングの互換モードは、デフォルトで IE 7 になっています。



図13
スクリプトエラー
  • 互換モードを IE 11 に変更して回避する