UWSCで標準入出力制御
UWSC公式掲示板で教えて頂いた方法をモジュール化。
感謝です!
なお、本方法では、上手くいかないケースがある。
その場合は、別な方法で。
UWSCでコマンドプロンプト - じゅんじゅんのきまぐれ
Stdinout.uws
OPTION EXPLICIT IFB GET_UWSC_NAME="Stdinout.uws" THEN WITH Stdinout //.Exec("cmd") //.Write("for /l %i in (1,1,5) do @ping -n 2 www.yahoo.co.jp<#CR>") .Exec("cmd /c for /l %i in (1,1,5) do @ping -n 2 www.yahoo.co.jp<#CR>", "cmd.exe") DIM text, loop = TRUE WHILE loop SLEEP(3) text = .Read() IFB LENGTH(text) THEN PRINT text ELSE loop = FALSE ENDIF WEND //.Write("exit<#CR>") // 「for〜」Write版では、これが必要。.Kill()という手もあるけど //.Kill() // .Kill()で呼んでるメソッドは最終手段だそうな .Close() ENDWITH ENDIF MODULE Stdinout DIM _wshShell DIM _exec = -1 DIM _wait = FALSE DIM _getNewText = "" PROCEDURE Stdinout() _wshShell = CREATEOLEOBJ("WScript.Shell") FEND // Execの多重呼び出しには対応してません // 多重呼び出ししたいなら、Module内部変数を配列か何かにしないと FUNCTION Exec(cmd, title=EMPTY) Close() _exec = _wshShell.Exec(cmd) THREAD PrivateReadThread() IF title <> EMPTY THEN CTRLWIN(GETID(title), HIDE) RESULT = _exec FEND PROCEDURE PrivateReadThread() WHILE !_exec.StdOut.AtEndOfStream DIM read = _exec.StdOut.Read(1) // いい加減な排他処理。まいいでしょう WHILE _wait; SLEEP(0.001); WEND _wait = TRUE _getNewText = _getNewText + read _wait = FALSE WEND FEND FUNCTION Read() // いい加減な排他処理。まいいでしょう // THREADで多重Read()する予定があるなら、これはNG WHILE _wait; SLEEP(0.001); WEND _wait = TRUE RESULT = _getNewText _getNewText = "" _wait = FALSE FEND FUNCTION Write(cmd) RESULT = FALSE IFB _exec <> -1 THEN _exec.Stdin.Write(cmd) RESULT = TRUE ENDIF FEND PROCEDURE Kill() IF _exec <> -1 THEN _exec.Terminate() Close() FEND PROCEDURE Close() _exec = -1 _wait = FALSE _getNewText = "" FEND ENDMODULE
ちなみに、遭遇した上手くいかないケースは、
- バッチスクリプトからexeを呼び出している
- それが標準入出力を使う
- exeが標準出力し、入力待ちでは、何の文字も取得できない
- 入力して制御が戻ると、標準出力からメッセージが取得できる(入力待ち前の文字も含めて)