2022年5月
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
無料ブログはココログ

« 2009年2月 | トップページ | 2009年4月 »

2009年3月30日 (月)

常駐のWSHスクリプトを外部からの指示で終了する。

常駐のWSHスクリプトを、強制終了は避けて、なおかつ外部からの指示で終了するには、WScript.Timeoutを操作すればよいのです。
例えば、WScitptオブジェクトの参照を外部に渡すのも、ひとつの方法です。
その他に、IEなど、アウトプロセスサーバのイベント出口を使う方法もあります。

例えば、以下のスクリプトを実行して、出てきたIEを閉じると、スクリプトも終了します。

Set ie=WScript.CreateObject("InternetExplorer.Application","IE_")
ie.Visible=True
MsgBox "waiting..."

Sub IE_OnQuit()
WScript.Timeout=1
End Sub

2009年3月27日 (金)

WSHスクリプトの強制終了は避けましょう。

Excelなど、アウトプロセスサーバのオブジェクトを参照するWSHスクリプトを強制終了すると、参照カウンタが残って、サーバが終了できなくなったりします。

APIのTerminateProcess()
タスクマネジャの「プロセスの終了」
タスクスケジューラの「タスクの終了」
TaskKill.exe
CScriptのCTRL+C
WScript.ShellのExec().Terminate()
などの強制終了は避けられるなら避けたほうがよいでしょう。

一方、WScript.Timeoutによる終了ではオブジェクト参照が解放されます。

万一の暴走やハングアップの対策に、WScript.Timeoutを設定しておくとよいでしょう。
スクリプトのソース内で、WScript.Timeout=秒
コマンドラインのオプションで、//T:秒
ショートカットファイル(.WSH)で、Timeout=秒

2009年3月19日 (木)

WSHから他のWSHを操作する。(その3)

VBScriptもJScriptもCOMオブジェクトです。
なので、それぞれのオブジェクトを他方に渡せば、他方のオブジェクトを操作したり、関数を呼び出したりもできます。

では、VBScriptからJScriptへ、JScriptからVBScriptへ、それぞれの関数のオブジェクト参照を渡して、互いに呼び出してみましょう。

コマンドプロンプトを二つ開いて、一方で、

cscript f1.vbs

CreateObject("Shell.Application").Windows().Item(0).PutProperty "VBS",GetRef("Sub1")
Dim fWait
fWait=True
Do While fWait
  WScript.Sleep 100
Loop
Set JS=CreateObject("Shell.Application").Windows().Item(0).GetProperty("JS")
JS "なんだよ"

Sub Sub1(s)
WScript.Echo s
fWait=False
End Sub

他方で、

cscript f2.js

WScript.CreateObject("Shell.Application").Windows().Item(0).PutProperty("JS",func1);
var VBS=WScript.CreateObject("Shell.Application").Windows().Item(0).GetProperty("VBS");
VBS("おい");
WScript.Sleep(10000);

function func1(s){
WScript.Echo(s);
WScript.Timeout=1;
WScript.Quit(1);
}

関数はオブジェクトのデフォルトメソッドになってます。

2009年3月16日 (月)

WSHから他のWSHを操作する。(その2)

WSH間で会話も可能です。

グローバルオブジェクトもCOMオブジェクト(VBScriptTypeInfo)です。
先の例ではWScriptオブジェクトを渡していましたが、ここで、もしグローバルオブジェクトを渡せば、他方のグローバル変数を操作したり、関数を呼び出したりができます。

では、グローバルオブジェクト(グローバルコンテキストでのMe)を渡して、グローバル変数を操作してみましょう。

コマンドプロンプトを二つ開いて、一方で、

cscript g1.vbs

CreateObject("Shell.Application").Windows().Item(0).PutProperty "WSH",Me
Dim fWait
Dim WSH2
fWait=True
Do While fWait
  WScript.Sleep 100
Loop
WSH2.Echo "なんだよ"
WSH2.Quit 9

他方で、

cscript g2.vbs

Set Me1=CreateObject("Shell.Application").Windows().Item(0).GetProperty("WSH")
Me1.WScript.Echo "おい"
Set Me1.WSH2=WScript
Me1.fWait=False
WScript.Sleep 10000

グローバル変数や関数はグローバルオブジェクトのプロパティとメソッドになってます。

2009年3月12日 (木)

WSHから他のWSHを操作する。

WScriptオブジェクトはCOMオブジェクト(IHost_Class)です。
なので、スクリプト1からそのWScriptオブジェクトの参照をスクリプト2へ渡せば、スクリプト2からスクリプト1のWScript.Echoを呼び出したり、終了させたりできます。

では、実験してみましょう。

コマンドプロンプトを二つ開いて、一方で、

cscript s1.vbs

CreateObject("Shell.Application").Windows().Item(0).PutProperty "WSH",WScript
MsgBox "Waiting..."

他方で、

cscript s2.vbs

Set WSH1=CreateObject("Shell.Application").Windows().Item(0).GetProperty("WSH")
WSH1.Echo "Stopping..."
WSH1.Timeout=1

2009年3月 8日 (日)

FOR /Fコマンドでファイル更新するときの出力リダイレクト

FOR /Fコマンドでは、ファイルを読み込んで、同じファイルに書き出すことができます。

for /f %i in (file) do echo %i >>file

とすれば、元のファイルの後ろに追加書きされます。

上書きするには、最初のdoコマンドでファイルを空にします。

set n=
for /f %i in (file) do (
  if not defined n type nul >file
  set /a n+=1
  echo %i >>file
)

あるいは、in内のコマンドの最後でファイルを空にします。

for /f %i in ('type file ^& call ^>file') do echo %i >>file

2009年3月 7日 (土)

FORコマンドの出力リダイレクト

FORコマンドの出力をファイルにリダイレクトするとき、

for %i in (a b) do echo %i >file

と書くと、doコマンドの繰り返しごとにリダイレクトされます。
この場合、毎回、上書きになってファイルには最後の1行しか入りません。

for %i in (a b) do echo %i >>file

と書くと、追加書きになって、すべて入ります。
しかし、最初からfileが空でないと、その追加書きになります。

もし上書きにしたいときは、最初に空にします。

type nul >file
for %i in (a b) do echo %i >>file

あるいは、forコマンド全体をリダイレクトします。

(for %i in (a b) do echo %i) >file

ただし、このとき、doコマンドのコマンドエコーも一緒にリダイレクトされるので、注意が必要です。

echo off
(for %i in (a b) do echo %i) >file

または、

echo on
(for %i in (a b) do @echo %i) >file

あるいは、

(for %i in (a b) do echo %i >&4) 4>file

とすれば、doコマンドのコマンドエコーはリダイレクトされません。

2009年3月 6日 (金)

ファイル名に!を使うと、環境変数の遅延展開と相性が悪い。

もし、ファイル名に!があると、バッチ変数(%1など)やFOR変数(%%iなど)の展開でファイル名中の!が遅延展開されちゃいます。
これは、"~"では、エスケープできません。

これを回避するには、バッチ変数やFOR変数の展開時に遅延展開を無効にすることです。
しかし、遅延展開はSETLOCAL抜きに切り替えができません。
しかも、SETLOCALのネストには上限もあります。

また、バッチファイルの遅延展開の初期状態は呼び出し元に依存します。
なので、バッチファイルの先頭に、SETLOCAL DISABLEDELAYEDEXPANSION を必ず入れておくことを推奨します。

« 2009年2月 | トップページ | 2009年4月 »