2012年1月23日月曜日

Windows でアプリケーションを再起動するバッチ処理 - タスクの強制終了、タスクリスト、エラーレベルによる条件分岐

1. Tray Volume が動作しなくなる

PC の音量を素早く変更するために、Tray Volume を利用している。

Tray Volume の設定で、

  1. マウスポインタをタスクバーに移動し、
  2. マウスホイールを動かす

ことにより、音量を変更するようにしている。

しかし、何が原因か分からないけれど、アプリケーションが起動しているにもかかわらず、音量を変更できなくなることがある。

Tray Volume のバージョンは、1.4.4.0。使用環境は Windows 7 64bit 。

 

2. Tray Volume を再起動するためのバッチファイル

動作しなくなる度に、アプリケーションを再起動している。

毎回、起動しなおすのは面倒なので、Tray Volume を再起動するバッチファイルを作成しておく。

@echo off

tasklist | findstr "TrayVolume.exe"

if errorlevel 1 goto START
if errorlevel 0 taskkill /f /im "TrayVolume.exe"

:START
start "" "C:\Program Files (x86)\TrayVolume\TrayVolume.exe"

上記を、適当に restartTrayVolume.bat と名前を付けて保存。

Tray Volume が動作しなくなったら、バッチファイルを起動する。

 

3. 再起動するアプリケーションを指定できるように変更する

追記(2013/09/12): 他のアプリケーションも再起動できるように、対象のアプリケーションを「引数として与えるよう」にバッチファイルを変更しておく。

バッチファイルで引数を受け取るには %数字 という記述をする。

EZ-NET: Windows コンソール プログラミング - バッチファイルの引数を操作する

バッチファイルでもコマンドと同様に引数を渡すことが出来ます。渡された引数は %1 から %9 までの変数として保存されます。 %0 もあるのですけど、これには実行中のバッチファイル名が保存されます。

restart.bat

REM @echo off

tasklist | findstr %1

if errorlevel 1 goto START
if errorlevel 0 taskkill /f /im %1

:START
start "" %2

上記を適当に restart.bat と名前をつけて保存する。

 

コマンドプロンプトから起動する

使い方は、ファイルのあるフォルダでコマンドプロンプトを起動し、以下のように入力する。

restart.bat "TrayVolume.exe" "C:\Program Files (x86)\TrayVolume\TrayVolume.exe"

 

ショートカットファイルでワンクリックで再起動

restart.bat ファイルのショートカットを作成し、再起動したいプログラムを引数で与えることにより、マウスでアイコンをクリックして簡単に起動できる。

  1. restart.bat ファイルをショートカット作成し、適当に restart-TrayVolume.bat と名前をつける。
  2. 作成したショートカットのプロパティを開き、「ショートカット」タブの「リンク先」フィールドの末尾に  "TrayVolume.exe" "C:\Program Files (x86)\TrayVolume\TrayVolume.exe" を追記する。(先頭に半角スペースを入れること。)

SnapCrab_No-0426

 

4. Windows 7 でクイック起動により、バッチファイルを起動する

Windows 7 では、タスクバーにバッチファイルを登録することができない。Windows XP や Vista のようにクイック起動を利用したい。

以下を参照して、Windows 7 でクイック起動を作成。

要するに、以下のフォルダを作成すれば良いとのこと。

  • C:\Users\ユーザ名\AppData\Roaming\Microsoft\Internet Explorer\Quick Launch

 

5. バッチファイルの内容について

a. タスクの強制終了

タスクを終了するためのコマンドは taskkill 。

強制終了をするための /f オプションを付けないと、終了できないことがあった。

 

b. タスクリストから、タスクが起動しているか確かめる

Tray Volume を終了する前に、Tray Volume が起動しているか確かめておく。

動作しているタスクの一覧を得るには、tasklist コマンドを利用する。

tasklist コマンドで、当該タスクが存在するか判定するには、findstr コマンドを併用し、条件分岐でエラーレベルを取得する。

【バッチファイル】tasklistの実行結果取得方法について - Insider.NET - @IT によると、

下記のコマンドで起動成功失敗のerrorlevelが取れました。
tasklist /FI "USERNAME eq ユーザ名" | findstr プロセス名
echo %errorlevel%

findstr コマンドは、文字列の検索を行うためのもの。

 

c. エラーレベルによる条件分岐は、順序に注意

上記のコマンドは、実行すると結果を返す。

【ハウツー】ゼロからはじめるバッチプログラミング - 制御編 (1) 分岐を使うバッチプログラミング  | マイナビニュース によると、

アプリケーションは、終了時にシステムに対して値を返すことができます。例えば、C言語でプログラムを作ったことがあればmain()関数の最後に return文で整数を返したはずです。この値がどのような意味を持っているのかはアプリケーションが定めますが、システムはアプリケーションが返した終了コードを受け取り、ifコマンドでバッチ処理できます。多くの開発者にとってもあまり意識されない終了コードですが、エラーの発生などによって返す値を定めることで、バッチファイルによる管理が可能になります。

if errorlevel 番号 コマンド

このifコマンドは、直前に実行したアプリケーションの終了コードが指定した番号と同じかそれより上であれば、続くコマンドを実行します。多くのアプリケーションは、正常終了した場合は0を返し、そうでなければ0以外の値を返します。

注意する点は、ERRORLEVEL の数値を並べる順序。

バッチファイルの制御用コマンド [FPCU]DOS/V&Windowsコマンド・プロンプト・リファレンス によると、

≪条件書式1≫ ERRORLEVEL 数値
IFより前に実行されたプログラムが、指定した「数値」以上の「終了コード」をDOSに返しているときに、条件が成立します。

例えば、ERRORLEVELでの条件分岐が意図した結果にならない (DOSプロンプト活用相談室LOG) によると、

… 仕様として IF ERRORLEVEL の判定が「以上」であることが原因だと思います。等号じゃないんですね。
なので、
>IF ERRORLEVEL 0 GOTO NG
>IF ERRORLEVEL 1 GOTO OK
という順序で記述されると、最初の行は errorlevel が 1 の場合でも成り立ってしまって GOTO NG してしまうと思います。
IF ERRORLEVEL 1 GOTO OK
IF ERRORLEVEL 0 GOTO NG
というように、判定順序を数字の大きい方からにすればよいのではないでしょうか。

ERRORLEVEL は、比較演算子。

バッチメモ(Hishidama's bat-file Memo) によると、、

条件には、以下の比較演算が使える。(大文字でも小文字でもよい)…

単項演算子…

ERRORLEVEL
%ERRORLEVEL%が値以上
なぜこんな演算子がわざわざあるかについては、注意点を参照。
if errorlevel 1 echo エラー

バッチ処理の仕様に辟易 (+_+)