第12回 WshShellオブジェクトを利用する(1):基礎解説 演習方式で身につけるチェック式WSH超入門(2/2 ページ)
今回からはWShellオブジェクトについて解説する。最初は外部プログラムの起動や制御を行うRun、AppActivate、SendKeysメソッドについて解説。
ウィンドウをアクティブにしてキー・コードを送るAppActivateとSendKeysメソッド
AppActivateメソッドを使うと任意の(Runメソッドで起動したものも含め)ウィンドウをアクティブにでき、SendKeysメソッドを使うとアクティブなウィンドウに任意のキー・コードを送信できる。すなわち、キーボードからキーを打ち込む作業を自動化できる。
AppActivateメソッドは引数に指定したウィンドウ・タイトルに一致(完全一致だけでなく、前方一致、後方一致でも可)するものがあればそのウィンドウをアクティブにする(次回以降で述べるExecメソッドを使うとProcessIDを指定できるので起動したアプリケーションを厳密に特定してアクティブ化できる)。アクティブ化に成功したらTrueを返し、失敗したらFalseを返す。例えば次のコードを見ていただきたい。
※AppActivate.vbs
Option Explicit
'オブジェクト変数の宣言とWshShellオブジェクトの作成。
Dim objWshShell
Set objWshShell = WScript.CreateObject("WScript.Shell")
'電卓を非同期で起動。
objWshShell.Run "calc.exe"
'メモ帳を非同期で起動。
objWshShell.Run "notepad.exe"
'起動するのに1秒待つ。
WScript.Sleep 1000
Dim intCounter
For intCounter = 1 To 5
'電卓をアクティブにする。
objWshShell.AppActivate "電卓"
'1秒待つ。
WScript.Sleep 1000
'メモ帳をアクティブにする。
objWshShell.AppActivate "メモ帳"
'1秒待つ。
WScript.Sleep 1000
Next
MsgBox "終了。"
Set objWshShell = Nothing
このスクリプトをWindows Vistaで実行すると、電卓とメモ帳が立ち上がり、1秒ごとに交互にアクティブになり、5回繰り返すと終了する。メモ帳の正しいウィンドウ・タイトルは「無題 - メモ帳」だが、"メモ帳" を引数に指定すると後方一致するのでアクティブ化されるわけである。だがもし、"マイメロ帳"などと記述した場合は、一致するウィンドウがないので何も起こらない(戻り値はFalse)。
なお、Windows XP、Windows Server 2003では、(デフォルト状態のままでは)このスクリプトは思惑どおりに動作しない。最初のAppActivateのみ正しく動作し、ウィンドウはアクティブになりフォーカスを持つのだが、2回目以降のAppActivateではウィンドウはアクティブになろうとするもののフォーカスを奪えず、タスク・バーで該当ウィンドウのバーがデフォルトではオレンジ色(Windows Server 2003では青色)の点滅をするだけである(ただしこれは見掛け上アクティブになっていないだけで、AppActivateメソッドの戻り値はTrueであり、実際に次に述べるSendKeysメソッドでキー・コードを送るとフォーカスが得られる)。
さて、実際はAppActivateメソッドはSendKeysメソッドとともに使われるケースがほとんどである。というのも、SendKeysメソッドはアクティブなウィンドウにキー・コードを送るメソッドであるからだ。AppActivateメソッドでウィンドウをアクティブにしてからSendKeysメソッドでキー・コードを送る……、といった使い方がメインになる。実際に電卓で「18782+18782」を計算した結果を、メモ帳にコピーするというデモをご覧にいれよう。
※ファイルCalcAndPaste.vbs
Option Explicit
'オブジェクト変数の宣言とWshShellオブジェクトの作成。
Dim objWshShell
Set objWshShell = WScript.CreateObject("WScript.Shell")
objWshShell.Run "notepad.exe"'メモ帳を非同期で起動。
objWshShell.Run "calc.exe"'電卓を非同期で起動。
WScript.Sleep 1000'起動するのに1秒待つ。
objWshShell.AppActivate "電卓"'電卓をアクティブにする。
WScript.Sleep 100'0.1秒待つ。
objWshShell.SendKeys "18782"'電卓に"18782"と入力する。
WScript.Sleep 1000'1秒待つ
objWshShell.AppActivate "電卓"'電卓をアクティブにする。
WScript.Sleep 100'0.1秒待つ。
objWshShell.SendKeys "{+}"'電卓に"+"と入力する。
WScript.Sleep 1000'1秒待つ
objWshShell.AppActivate "電卓"'電卓をアクティブにする。
WScript.Sleep 100'0.1秒待つ。
objWshShell.SendKeys "18782"'電卓に"18782"と入力する。
WScript.Sleep 1000'1秒待つ
objWshShell.AppActivate "電卓"'電卓をアクティブにする。
WScript.Sleep 100'0.1秒待つ。
objWshShell.SendKeys "="'電卓に"="と入力する。
WScript.Sleep 1000'1秒待つ
objWshShell.AppActivate "電卓"'電卓をアクティブにする。
WScript.Sleep 100'0.1秒待つ。
objWshShell.SendKeys "^C"'電卓に[Ctrl]+[C]を送り、計算結果のコピー。
Wscript.Sleep 1000'1秒待つ
objWshShell.AppActivate "メモ帳"'メモ帳をアクティブにする。
WScript.Sleep 100'0.1秒待つ。
objWshShell.SendKeys "^V"'メモ帳に[Ctrl]+[V]を送り、計算結果を貼り付ける。
Set objWshShell = Nothing
このスクリプト実行中は誤動作を防ぐため、画面をクリックしたり、キーボードから入力しないようにしていただきたい。実行結果は例えば次のようになる。
SendKeysメソッドの引数にはキー・コードを指定する。「1」や「A」など単純な半角英数文字や「@」などの特殊文字はそのまま送ることができるが(ただし「+」「^」「%」「~」「[」「]」「{」「}」は、{+}のように、{ } で囲む)、「あ」などの日本語の文字列は残念ながら送ることができない。[Enter]などの特殊キーを送るには、{Enter}のように { } で特殊キー名を囲んで指定する。これらの特殊キーの一覧は「SendKeysメソッドの解説(MSDNサイト)」を参考にしてもらいたい。また、[Shift]や[Ctrl]や[Alt]キーをほかのキーと同時に押したときのキー・コードは、それぞれ「+」「^」「%」を同時押ししたいほかのキー・コードの前に付ける。例えば[Ctrl]+[C]を送るなら「^C」と指定する。「^」([Ctrl])を押し、続けて「C」「V」と入力したい場合は、「^C^V」と書いてもよいが、「^(CV)」という書き方もできる。これらのキー修飾は複数同時指定も可能で、[Shift]+[Ctrl]+[Esc](タスク・マネージャを起動するショートカット)を送るには、「+^{Esc}」とする。「X」という文字を10回入力したい場合は「XXXXXXXXXX」と書いてもよいが、「{X 10}」と書いてもよい。
なお、SendKeysメソッドはコンソール・アプリケーションにはキー・コードを送れない。代わりに後の回で述べるExecメソッドを用いる。
さて、先ほど掲載したスクリプトはいくつか問題点がある。AppActivateが何らかの原因で失敗し、Falseを返した場合、後続するSendKeysによって送られるキー・コードはどのウィンドウに送られるか分からない。そのため、それを防いだうえ、何度か再試行も行いたい。また、同じような動作を繰り返しているので連載第7回と第8回で説明したように、そういったコードはプロシージャ化するのが望ましい。ここではウィンドウをアクティブにしてキー・コードをそのウィンドウに送るActivateAndSendKeysプロシージャを定義し、コードを簡略化してみよう。少し難しくなるが問題としてみたい。
マーカーで隠れたところを選択してチェックしてみよう。
※ファイルActivateAndSendKeys.vbs
Option Explicit
'オブジェクト変数の宣言とWshShellオブジェクトの作成。
Dim objWshShell
Set objWshShell = WScript.CreateObject("WScript.Shell")
'メモ帳を非同期で起動。
objWshShell.Run "notepad.exe"
'電卓を非同期で起動。
objWshShell.Run "calc.exe"
'電卓に"18782"と入力する。
ActivateAndSendKeys "電卓", "18782", 1000
'電卓に"+"と入力する。
ActivateAndSendKeys "電卓", "{+}", 1000
'電卓に"18782"と入力する。
ActivateAndSendKeys "電卓", "18782", 1000
'電卓に"="と入力する。
ActivateAndSendKeys "電卓", "=", 1000
'電卓に[Ctrl]+[C]を送り、計算結果のコピー。
ActivateAndSendKeys "電卓"," ^C", 1000
'メモ帳に[Ctrl]+[V]を送り、計算結果を貼り付ける。
ActivateAndSendKeys "メモ帳", "^V", 0
Set objWshShell = Nothing
'*********************************************************
'用途: 指定したタイトルのウィンドウをアクティブにし、指定
' したキー・コードを送り、数ミリ秒待つ。
'受け取る値: strTitle: ウィンドウ・タイトル(String)
' strKey: 送るキー・コード(String)
' intWait: キー・コードを送った後待つミリ秒数
' (Integer)
'戻り値: 成功したらTrue、失敗したらFalseを返す(Boolean)。
'*********************************************************
Function ActivateAndSendKeys(strTitle, strKey, intWait)
Dim intCounter
'10回試行する。
For intCounter = 1 To 10
'AppActivateメソッドを実行し、戻り値がTrueなら、
If objWshShell.AppActivate(strTitle) Then
WScript.Sleep 100
'キー・コードを送る。
objWshShell.SendKeys strKey
'intWaitミリ秒待つ。
WScript.Sleep intWait
'成功を意味するTrueを返し、ループを抜ける。
ActivateAndSendKeys = True
Exit For
Else
WScript.Sleep 1000
'失敗を意味するFalseを返し、続行。
ActivateAndSendKeys = False
End If
Next
End Function
このスクリプトの実行結果は先ほどと同様なので省略する。このスクリプトのポイントは、Functionプロシージャ内でIf objWshShell.AppActivate(strTitle) Thenとすることで、AppActivateメソッドを実行すると同時に、その戻り値(成功=True、失敗=False)を判別していることである。これにより、成功していた場合は続けてSendKeysメソッドを実行して、指定ミリ秒待った後に試行ループを抜け、失敗した場合は1秒待ってから2度目のループを実行する。これを10回繰り返しても失敗するようなら、Functionプロシージャは失敗したものとする。
このFunctionプロシージャは実行結果を戻り値(成功=True、失敗=False)として返すので、もしAppActivateとSendKeysがうまくいったと思われる場合は次の処理へ、そうでない場合はエラーを出して終了させる、などの条件分岐も可能である。例えば、次のようなコードだ。
If ActivateAndSendKeys("タイトル1","aaa",2000) Then
ActivateAndSendKeys "タイトル2","bbb",500
Else
MsgBox "キー送出に失敗しました。"
WScript.Quit()
End If
ただし、AppActivateとSendKeysは万能選手ではない。このようにキー送出の「誤爆」を避ける処理を施しても、ほかのプログラムやユーザーの割り込みによって失敗する可能性は避けられない。そのことをよく念頭に置いて、ほかの手段(COMコンポーネントを通じてアプリケーションを外部から操作する、など)が用意されていない場合の最終手段として用いるようにしたい。
今回はWshShellオブジェクトの中核となる3つのメソッド、Run、AppActivate、SendKeysを掘り下げて詳説した。次回以降はWshShellオブジェクトの残りのメンバを紹介し、派生するオブジェクトのメンバを取り上げていく予定である。
Copyright© Digital Advantage Corp. All Rights Reserved.