昨日からJScriptでInputBoxを実装する方法を探して苦労していたわけだが、これといった決め手が見つからない。
MSScriptControl.ScriptControlを使う方法(JScriptでinputBoxを使う » Jeans & Development)が割とスマートに思えたのだけど、Windows 7で実行してみたところ動作せず。どうやら、MSScriptControlはWindows Vista以降ではオプションでインストールは可能なものの*1、標準でインストールされてないと判明。
function inputBox_SC(prompt, title)
{
var result;
var objScr;objScr = WScript.createObject("MSScriptControl.ScriptControl");
objScr.language="VBScript";
objScr.addCode(
"Function getInput()" +
" getInput = InputBox(\"" + prompt + "\", \"" + title + "\") " +
"End Function");
result = objScr.eval("getInput");objScr = null;
return result;
}
それならば、と次はIE経由でInputBox呼び出せばOS依存性ないよね、ということで作ってみた。
ただし、この方式の欠点は、IEのメインウィンドウを消すために ie.visible = false としているので、InputBoxダイアログがカレントウィンドウの背面に回ってしまうこと。一回Alt+Tabしないと前面に出てこない。
function inputBox_IE(prompt, title)
{
var ie;
var result;ie = WScript.createObject("InternetExplorer.Application");
ie.visible = false;
ie.navigate("about:blank");
while(ie.busy || ie.readyState < 3) WScript.sleep(100);
ie.document.write("<html><body><textarea id='text'></textarea></body></html>");
while(ie.busy || ie.readyState < 3) WScript.sleep(100);
ie.document.parentWindow.execScript(
"document.all.text.value = InputBox('" + prompt + "', '" + title + "')",
"VBScript");
result = ie.document.all.text.value;
ie.quit();
ie = null;return result;
}
あと、Windows 7+IE8な環境では動作しなかった。
いろいろデバッグした結果、ローカル環境(about:blank)ではInputBox()はクロスサイトスクリプティング対策で弾かれてしまうらしい、ということがわかって、結局この方式も頓挫。どうやらIE8からの機能らしい。
クロスサイト スクリプティング (XSS) フィルター : Internet Explorer 8 のこの新しい機能により "リフレクション (タイプ I) XSS" の脆弱性を悪用することが難しくなります。 スクリプトは、サーバーの応答の生成に HTTP 要求の一部が使用されるときに反映できます。これにより、要求内の悪意のあるスクリプトは、残りのページと同じアクセス レベルで実行できるようになります。 XSS フィルターは、ブラウザー内を移動するすべての要求と応答を監視します。 フィルターは、クロスサイト要求でスクリプトを検出したとき、スクリプトがサーバーの応答で再生された場合に、そのスクリプトを特定して無効化します。 このような動作が発生した場合、メッセージ "Internet Explorer modified this page to prevent a potential cross-site scripting attack" が表示されます。
最終的に、もういっそ、小細工しないでVBSそのまま呼べばいいじゃん!てことに思い至って無理やり作ってみた最終形がこれ。いやもう、そこまでJScriptに拘る必要ってあるのかどうかわからんけど…。
流れとしてはまったく大したことはしておらず、
(1)InputBox()を実行してWScript.EchoするだけのVBSファイルをテンポラリフォルダに作成。
(2)VBSファイルを実行し、終了待ち
(3)標準出力から実行結果を受け取る
(4)VBSファイルを削除
という感じ。ただの力技とも言う。たぶん環境依存せず可搬性ある。
function inputBox(prompt, title)
{
var WshRunning = 0;
var TemporaryFolder = 2;var fso;
var wsh;
var cmdline;
var oExec;
var vbsFile;
var vbsFilePath;
var result;fso = WScript.createObject("Scripting.FileSystemObject");
wsh = WScript.createObject("WScript.Shell");// Creates a temporary VBS script file
vbsFilePath = fso.getSpecialFolder(TemporaryFolder).path + "\\inputbox.vbs";vbsFile = fso.createTextFile(vbsFilePath, true, false);
vbsFile.writeLine("If WScript.Arguments.Count = 1 Then");
vbsFile.writeLine(" WScript.Echo InputBox(WScript.Arguments.Item(0))");
vbsFile.writeLine("End If");
vbsFile.writeLine("If WScript.Arguments.Count = 2 Then");
vbsFile.writeLine(" WScript.Echo InputBox(WScript.Arguments.Item(0), WScript.Arguments.Item(1))");
vbsFile.writeLine("End If");
vbsFile.close();
vbsFile = null;// Invokes the VBS script and retrieve the result via StdOut
cmdline = "cscript.exe " + vbsFilePath + " //nologo";
if(prompt){
cmdline += " " + prompt;
if(title){
cmdline += " " + title;
}
}oExec = wsh.exec(cmdline);
while(oExec.status == WshRunning){
WScript.sleep(100);
}if(oExec.stdOut.atEndOfStream){
result = false;
} else {
result = oExec.stdOut.readLine();
}oExec = null;
// Deletes the temporary VBS script file
fso.deleteFile(vbsFilePath, true);wsh = null;
fso = null;return result;
}