以前、このテーマについて以下のような記事を書いた。
今更だが JScript で VBScript の Inputbox を使う - Qiita
https://qiita.com/itasnasal/items/1747f9bcf6859093b7fe
ここでは wsc (Widows Script Component) を使う、という奇矯な方法に辿り着いた。
しかし。
結局原因は不明なままだが、2回呼び出すと2回目がきちんと動かなかったりとか安定しない。
元々半ば冗談で試した手法で「できるじゃんwww」的なところが大きかった。
「少なくとも、全く同じものはWEBではいまのところ見つけられてない。」に尽きる。
そして久しぶりにこの問題をもう一度考えてみた。
「どうにかして JScript から VBScript を動かして、結果を取得する」
どうすればいいか。
ここで身も蓋もない原点に戻ってきた。
「スクリプトなんだからスクリプト・ファイル作って実行すればいいじゃん。」
というわけで書いたのがこれである。
・InputBox を実行して結果を標準出力に吐くVBScriptファイルを生成する。
・これを WshShell.exec() で実行して、標準出力の内容を取ってくる。
// magic spell for WSH ///////////////////////////////////////////////////////
if(typeof console==="undefined") console={log: function(s){WScript.Echo(s)}};
if(typeof process==="undefined"){ process={exit:function(e){WScript.Quit(e)}};
var v=process.argv=[];v.push(WScript.FullName);v.push(WScript.ScriptFullName);
var n=WScript.Arguments.Unnamed;for(var i=0;i<n.length;i++)v.push(n.item(i))};
//////////////////////////////////////////////////////////////////////////////
// require('vbFunctions'); // 超原始的に JScript から VBScript の関数を実行する。
initVbsFunction();
var result = vbsMsgBox( 'テストです。', 3+32, 'MagBoxTest' );
console.log( result );
var result = vbsInputBox( 'テストです。', 'InputBoxTest', 'デフォルト値', 3000, 1500 );
console.log( result );
process.exit()
function initVbsFunction() {
//--------------------------------------------------------------------------//
//////////////////////////////////////////////////////////////////////////////
// 超原始的に JScript から VBScript の関数を実行する。
// 現在は以下の2つ。
//
// vbsInputBox( prompt, title, dflt, xpos, ypos, helpfile, context )
// vbsMsgBox( prompt, buttons, title, helpfile, context )
//
// おまけ:とりあえずこれも出しとく。
// vbsFunction( funcName, args )
var fso = fso || new ActiveXObject("Scripting.FileSystemObject");
var WshShell = WshShell|| new ActiveXObject("WScript.Shell");
// 超原始的に JScript から VBScript の InputBox を実行する。
vbsInputBox = function( prompt, title, dflt, xpos, ypos, helpfile, context ) {
return vbsFunction( 'InputBox', arguments );
}
// 超原始的に JScript から VBScript の MsgBox を実行する。
vbsMsgBox = function( prompt, buttons, title, helpfile, context ) {
return vbsFunction( 'MsgBox', arguments );
}
// 超原始的に JScript から VBScript の関数を実行するための共通ルーチン
vbsFunction = function( funcName, args ) {
var vbsPath = genTempNameEx( 'Dummy_', '.vbs' );
var param = [];
for (var i = 0; i < args.length; ++i) param[i] = ( '\"'+args[i]+'\"' );
var vbs = 'WScript.Echo ' + funcName + '( '+ param.join(', ') + ' )';
text2file( vbs, vbsPath );
var sce = WScript.FullName.replace(/Wscript/i, "cscript") + " //nologo ";
var oExec = WshShell.exec( sce + vbsPath );
var result = oExec.StdOut.ReadAll().replace(/\r\n$/,"");
fso.DeleteFile( vbsPath );
return result
}
// %TEMP% 内に一時ファイル名を生成
function genTempNameEx( prifix, postfix ) { // 一時名前の生成
prifix = prifix || '';
postfix = postfix || '';
var tempPath = fso.BuildPath( fso.GetSpecialFolder(2), prifix + fso.GetTempName() + postfix );
// fso.GetTempName() を使ってみる。
if( fso.FileExists( tempPath ) || fso.FolderExists( tempPath ) ) throw new Error( '一時ファイル名の生成に失敗しました。' );
return tempPath;
}
// 指定ファイルを全読みしてテキストで返す。
function file2text( file ) {
if( ! fso.FileExists( file ) ) return null;
var f = fso.OpenTextFile( file, 1 ); // iomode 1:ForReading
var r = "";
if( ! f.AtEndOfStream ) r = f.ReadAll();
f.close();
return r;
}
// 指定テキストをファイルに保存する。
function text2file( text, file ) {
var f = fso.CreateTextFile( file, true );
f.Write(text);
f.close();
return;
}
// module.exports = {};
//--------------------------------------------------------------------------//
}
Script Control使って「別の言語のコードを押し込んで使う」んじゃなく
普通に「別の言語のスクリプトファイルを書いて実行する」というシンプルな方法。
最初すごくあほらしいと自分では思ったけれども、1ファイルに収まるし、使っている仕組みも既知のシンプルなもので、内部の動きに wsc のような不明さ謎さもない。
奇矯な方法よりも、いろいろシンプルであることが大事だよなあ。と改めて思いました。