Microsoft Office を購入したとき、スプレッドシートに始まって、ワードプロセッサから電子メール クライアントに至るまで、すべてを含むワールドクラスのアプリケーション セットを手に入れたことを実感できたと思います。お気付きでなかったかもしれませんが、長年スクリプト ライタを悩ませていた次のような質問に対する答えも実は手に入れていたのです。「どうすれば、コンピュータで実行中のすべてのアプリケーションと開いているウィンドウの一覧を取得することができますか。」
ここで、コンピュータで実行中のすべてのプロセスの一覧を取得する方法について話しているわけではないことに留意してください。このデータが必要ならば、WMI の Win32_Process クラスを使って取得することができます。Win32_Process を使って、コンピュータで実行中のすべてのプロセス名を取得すると、次のような情報が得られます。
この情報には何の問題もありません。実際、コンピュータで実行中のすべてのプロセスの一覧が必要な場合もあります。しかし、タスク マネージャの [アプリケーション] タブにある項目の一覧だけが必要な場合もあります。
つまり、開いているウィンドウだけが必要で、実行可能ファイル名ではなくフレンドリ名 (たとえば、hh.exe ではなく "Portable Script Center") を取得したい場合です。しかし、WMI では、この情報にアクセスできませんし、オペレーティング システムに組み込まれたその他のスクリプト オブジェクトもアクセスできません (Shell オブジェクトは、コンピュータで開いているすべてのシェル項目を一覧する手段を提供していますが、それだけです)。
ところが、驚くべきことに、Microsoft Office を使えばこの情報が取得できるのです。Microsoft Word の Application オブジェクトには、コンピュータで実行中のすべてのプロセスのコレクションを返す Tasks プロパティが含まれています。このプロパティと Win32_Process の違いは、Tasks コレクションが、実行可能ファイル名ではなく、プロセスのフレンドリ名を返すことです。これによって、次のような情報を取得できます。
ちょっと待ってください。Tasks コレクション内の各プロセスを表す Task オブジェクトと Win32_Process によって返されたオブジェクトの間には、少なくとも、もう 1 つ違いがあります。以前の記事に書いたとおり、コンピュータで 46 のプロセスが実行されていても、タスク マネージャの [アプリケーション] タブには 11 の項目しか表示されていませんでした。これは、ほとんどのプロセス (ほとんどのサービスを含みます) が非表示ウィンドウで実行されているためです。つまり、このことが、タスク マネージャが [アプリケーション] タブに表示するプロセスを決定する方法なのです。プロセスを実行しているウィンドウが表示されていれば、タスク マネージャは、そのプロセスをアプリケーションとしてリストアップします。ウィンドウが表示されていなければ、そのプロセスはアプリケーションとしてリストアップされません。
メモ コンピュータで実行中のすべてのプロセスのフレンドリ名を返すスクリプトについては後で説明します。このスクリプトで、実行可能ファイル名を取得したり、コンピュータで実際に何が実行されているかを理解したりすることは困難ですが、フレンドリ名によって、より明確に状況を把握することができます。
Win32_Process では、プロセスが非表示ウィンドウで実行中であるか、そうでないかを知ることはできません。そのため、Win32_Process では、タスク マネージャがアプリケーションとしてマークしたプロセスを識別することができません。しかし、Task オブジェクトには、プロセスが表示ウィンドウで実行中であるか、そうでないかを示す Visible プロパティが含まれています。Visible プロパティを使用すれば、開いているウィンドウとアプリケーションを識別することができます。
実際にこれを実行するスクリプトを以下に示します。
Set objWord = CreateObject("Word.Application")
Set colTasks = objWord.Tasks
For Each objTask in colTasks
If objTask.Visible Then
Wscript.Echo objTask.Name
End If
Next
objWord.Quit
まず、Microsoft Word のインスタンスを作成します。colTasks という名前の変数に Tasks コレクションを代入してから、コレクションを順に読み取る For Each ループを設定します。タスクごとに (つまり、コンピュータで実行中のプロセスごとに)、表示ウィンドウで実行中かどうかをチェックします。次のコード行が、そのような処理を実行します。
If objTask.Visible Then
Visible プロパティが True であれば、そのタスク名を表示します。Visible プロパティが False の場合は (つまり、プロセスが非表示ウィンドウで実行されている場合は)、ループの最初に戻ってコレクション内の次のタスクをチェックします。コレクション全体をチェックしたら、Word を終了し、スクリプトが終わります。
結果は、どうなるでしょうか。そうですね。結果として、タスク マネージャの [アプリケーション] タブとほぼ同じ一覧が得られます。唯一の違いは、Windows 98 から搭載され、実際には [スタート] メニューを参照しているプログラム マネージャが、スクリプトの出力には表示されて、タスク マネージャには表示されないことです。同様に、タスク マネージャ自体は、タスク マネージャの [アプリケーション] タブには表示されませんが、スクリプトの出力には表示されます。
すごいと思いませんか。プロセスが表示されているかどうかに関係なく、すべてのプロセスの一覧を取得するには、次のようなスクリプトを使用してください。
Set objWord = CreateObject("Word.Application")
Set colTasks = objWord.Tasks
For Each objTask in colTasks
Wscript.Echo objTask.Name
Next
objWord.Quit
これでは、まだ半分にも達していません。コンピュータで、ソリティア (Solitaire) で遊んでいる人がいるかどうか知りたくありませんか。その場合は、次のように Exists メソッドを使って、Tasks コレクション内に Solitaire があるかどうかを確認します。
Set objWord = CreateObject("Word.Application")
Set colTasks = objWord.Tasks
If colTasks.Exists("Solitaire") Then
Wscript.Echo "Someone is playing Solitaire."
End If
objWord.Quit
ソリティアで遊ぶのを止めさせたい場合は、次のように Close メソッドを使って、Solitaire をシャットダウンします。
Set objWord = CreateObject("Word.Application")
Set colTasks = objWord.Tasks
If colTasks.Exists("Solitaire") Then
colTasks("Solitaire").Close
End If
objWord.Quit
または、ソリティアを一番手前に移動して最大化することで、その人を手助けすることもできます。これには、まず、そのウィンドウをアクティブ化してから (Activate メソッドを使用します)、WindowState プロパティを wdWindowStateMaximize (私たちが定義した定数で、値として 1 が代入されています) に設定します。スクリプトは次のようになります。
Const wdWindowStateMaximize = 1
Set objWord = CreateObject("Word.Application")
Set colTasks = objWord.Tasks
If colTasks.Exists("Solitaire") Then
colTasks("Solitaire").Activate
colTasks("Solitaire").WindowState = wdWindowStateMaximize
End If
objWord.Quit
ウィンドウを最小化する場合は、wdWindowStateMaximize 定数に値として 2 を代入します。
まだやる気があれば、Task オブジェクトを使用して、Height、Width、Top (ウィンドウの垂直方向の位置をポイント単位で指定します)、Left (ウィンドウの水平方向の位置をポイント単位で指定します) などの他のウィンドウ プロパティにアクセスすることができます。このスクリプトは次のようになります。
Set objWord = CreateObject("Word.Application")
Set colTasks = objWord.Tasks
If colTasks.Exists("Solitaire") Then
Wscript.Echo "Name: " & colTasks("Solitaire").Name
Wscript.Echo "Top: " & colTasks("Solitaire").Top
Wscript.Echo "Left: " & colTasks("Solitaire").Left
Wscript.Echo "Height: " & colTasks("Solitaire").Height
Wscript.Echo "Width: " & colTasks("Solitaire").Width
End If
objWord.Quit
次のようなデータが返されます。
Name: Solitaire Top: 65 Left: 50 Height: 329 Width: 445
これまで、Word はただのメモ用ソフトだと思っていませんでしたか。そんなあなたには、Microsoft からこんな言葉を送ります。「Word は何でもできます。本当ですよ。」
もちろん、Word の Tasks コレクションは Win32_Process クラスを補完することはできても、その代わりになることはできないことを指摘しておく必要があります。これは、Tasks コレクションが返せない大量の情報 (カーネル モード時間、ユーザー モード時間、プロセス ID、ハンドルの数) を、Win32_Process は返すことができるからです。また、Tasks コレクションで取得したプログラムを、Win32_Process 内の対応するプロセスに関連付ける方法については、明らかな方法がわかりません。この方法がわかったら、お知らせします。