はじめに
WSH JScript に Chakra を指定すると WScript Object の機能が制限される為、
WScript.Quit
関数が利用できず、戻り値を返す術が失われます。
今回は、この問題の対処例を挙げます。
前提
Windows 環境には、Windows Script Host(WSH)と呼ばれる
Node.js の様な JavaScript が動作するスクリプトの実行環境が標準搭載されています。
技術としては古いものなので、デフォルトでは ES3 程度のサポートですが、
スクリプトエンジンを Chakra に変更することでES6の機能が利用可能
です。
WSH JScript Chakra を使用した ES2015(ES6) 対応 ( スクリプトエンジン まとめ )
既定のJScript で、Chakra 用の処理をラップする形の対処法です。
WScript.Quit は、CScript でないと戻り値が機能しないので、バッチに埋め込みます。
この方法は、JScript と Chakra で各エンジンが共存するので、
機能制限の掛かる箇所は、JScript側で関数化する等の対処で回避可能になります。
※ 例えば、GetObject等のChakraでは未定義となる関数は、JScript 経由で利用できます。
0<
0;
function main()
{
const msg = `${WSH} for Chakra`;
WSH.Echo(msg);
const r = JS.hoge();
const shell = WSH.CreateObject("WScript.Shell");
shell.popup(msg);
return r;
}
function fuga()
{
WSH.Echo("fuga");
}
var quit=!1;let item,ie,w=WSH.CreateObject("Shell.Application").Windows(),i=0;
for(;i<w.Count;i++)if((item=w(i))&&item.hWnd==WSH.Arguments(0)){ie=item;break}
for(ie.PutProperty("@",this);!quit;)WSH.Sleep(1e3);
仕組み
条件付きコンパイル
機能を使って、1つのスクリプト内に
エンジン毎(JScript, Chakra)で実行されるコードを共存させています。
また、プロセス間でオブジェクトを共有するために、
InternetExplorer
Object の PutProperty / GetProperty
を利用しています。
該当部分は、コーディングに直接関係無いのでMinify済みですが、
大体下記のように処理しています。
- JScript
- IEオブジェクトを作成
- 実行引数に、IEのウィンドウハンドルを設定して、Chakraエンジンで自身を起動
- GetPropertyでChakraのオブジェクトが設定されるまで待機
- ChakraのWScriptを、JScriptの定義で上書き
- Chakra側のmain関数を呼び出して、戻り値を受け取る
- プロセス同期用のフラグを折ってChakra側を終了
- main関数の戻り値をWScript.Quitに指定して終了
- Chakra
- 実行引数に渡されたウィンドウハンドルから、IEオブジェクトを特定
- PutPropertyで、IEオブジェクトに this を設定
- プロセス同期用のフラグが折れるまで待機
別解:一時ファイルを使用する方法
別解として泥臭い方法になりますが、
”戻り値だけ” であれば、一時ファイルで解決可能。
諸々の制限を回避できない分、仕組みはシンプルです。
exit /b
で戻り値を設定するため、バッチに埋め込みます。
ファイル名に日時と乱数を使用しているのは、多重起動に対応するため。
0<
0;
function main()
{
WSH.Echo(`${WSH} for Chakra`);
return 123;
}
try {
var shell=WSH.CreateObject("WScript.Shell"),
fso=WSH.CreateObject("Scripting.FileSystemObject"),ExitCode=0;
ExitCode=main();
}
catch(e){WSH.Echo(`${e.name}:${e.message}`)}
finally{
const procEnv=shell.Environment("Process"),
file=fso.OpenTextFile(procEnv("result_file"), 2, true, -2);
file.Write(ExitCode),file.Close();
}
おわりに
一般的に、外部から呼び出されることを想定するプログラムは、
戻り値から、エラー原因を特定できるようにしています。
Chakra を指定したスクリプトでは、スクリプトが失敗しても
戻り値から判断できない状況でしたが、これで一件落着?でしょうか。
元々 Chakra を指定する事自体が、仕様の穴をつくような方法なので、
回りくどい対応を取らざる得なくなる事もありますが、
それを差し引いても ES6 が利用できる点は大きいかと思います。
参考