APIを使わないで実行中のタスク一覧を調べる


Excel VBAのTipsとしては、かなりの反則だと思います。だって、Excel VBAの機能ではないのですから。

これは、先日作成していたマクロで、どうしてもこの情報が必要になり、あれこれ探していたら偶然見つけたテクニックです。見つけたときに思ったのは「えぇ~ズルい!」という印象でした(^^;

現在実行しているすべてのソフトを調べるには、タスクマネージャを起動して[アプリケーション]タブを開きます。ここにリストされる「プロセス一覧」をプログラムから取得するには、WindowsのAPIや、WMI(Windows Management Instrumentation)などを使うのが一般的です。この「プロセス一覧」をVBAだけで取得しようというのが今回のテーマです。次のようにやります。

Sub Sample1()
    Dim WD, task, n As Long
    Set WD = CreateObject("Word.Application")    ''Wordを起動します
    For Each task In WD.Tasks                    ''Word VBAのTasksコレクションを調べます
        If task.Visible = True Then              ''タスク(プロセス)が実行中だったら
            n = n + 1
            Cells(n, 1) = task.Name              ''タスクの名前を書き出します
        End If
    Next
    WD.Quit
    Set WD = Nothing
End Sub

実行結果と、このときのタスクマネージャは次の通りです。

2行目の「Set WD = CreateObject("Word.Application")」はWordを起動しています。なぜWordが必要かというと、驚くべきことにWordのVBAには現在実行中のタスク一覧を返すTasksコレクションが実装されているからです。正確には、タスクではなく実行中のプロセスでしょうか。本稿では便宜上「タスク」と呼ぶことにします。

なぜWordに!?文章の作成にどう関係してくるのでしょう!?まぁ、Wordについて私は詳しくありませんから、もしかすると何か密接なつながりがあるのかもしれません。いずれにしても、こんなに便利な機能がExcel VBAに実装されていないのはズルい!です(^^;

Tasksコレクションには現在実行中の全タスク(Taskオブジェクト)が含まれますので、For Eachステートメントで取得しています。ただし、実行中の全タスクには、ユーザーが意識しない特別なものも含まれます。それらはWindowsのバックグラウンドで動作しています。そこで、Taskオブジェクト(各プロセス)のVisibleプロパティがTrueかどうかを調べて「実行中」のタスクだけをアクティブシートに書き出しました。

Taskオブジェクトには、いくつかのプロパティやメソッドが用意されています。詳しくはWordのヘルプを呼んでもらうとして(読んでもよくわかりませんけど)、ここでは「もしInternet Explorerが起動していたら終了する」というサンプルを紹介します。まずは、起動しているかどうかを調べてみましょう。

Sub Sample2()
    Dim WD
    Set WD = CreateObject("Word.Application")
    If WD.Tasks.Exists("Internet Explorer") Then
        MsgBox "Internet Explorerが起動しています", vbInformation
    End If
    WD.Quit
    Set WD = Nothing
End Sub

TasksコレクションのExistsメソッドは、指定したタスクが存在するかどうかを返します。引数にはタスクの名前(Nameプロパティ)を指定します。Sub Sample1の結果を見てもらうとわかるように、現在起動しているIEのタスク名は「気象庁 | 週間天気予報 - Microsoft Internet Explorer」ですが、Existsメソッドでは「引数に指定した文字列を含む」タスクが存在した場合にTrueが返ります。ですから、他のタスクに似た名前がないのなら「If WD.Tasks.Exists("Explorer") Then」などでも判定は可能です。

さて、Taskオブジェクトには、指定したタスクを終了させるCloseメソッドが用意されています。起動しているIEを終了するには、先のコードを利用して次のようにします。

Sub Sample2()
    Dim WD
    Set WD = CreateObject("Word.Application")
    If WD.Tasks.Exists("Internet Explorer") Then
        WD.Tasks("Internet Explorer").Close
    End If
    WD.Quit
    Set WD = Nothing
End Sub

さすがに、Closeメソッドで閉じるときは正確な名前を指定しなくてはエラーになるだろうと思ったら、ナント削除できてしまいました。ここまでアバウトだと逆に心配です。それでいいのか?>Tasksコレクション

念のため確認メッセージを出したいのなら、次のようにします。

Sub Sample3()
    Dim WD, task
    Set WD = CreateObject("Word.Application")
    For Each task In WD.Tasks
        If task.Visible = True And InStr(task.Name, "Internet Explorer") > 0 Then
           If MsgBox(task.Name & vbCrLf & "を終了させますか?", 36) = vbYes Then
            task.Close
           End If
        End If
    Next
    WD.Quit
    Set WD = Nothing
End Sub

心配なので、実行中のタスクで、かつタスク名に"Internet Explorer"を含んでいるかどうかを判定するようにしました。

用途は限られますが、知っていると思わぬときに役立つかもしれないテクニックですね。それにしても、なぜWord VBAにだけ実装されているのでしょうね。ズルいです・・・