ヨーキョクデイ

100% pure impurities, which may imply some value. (j は虚数単位)

定期的にソフトを再起動したい

俺様用メモ。
非アクティブウィンドウのスクロールをマウスホイールで可能にするソフトっていうのが Wheel Redirector やら各種あると思うのだが、別用途で昔から使っていた Pito! にもこの機能がある。しかしながら、Windows 7 でこれらを使っていると、ふとしたときにこの機能が効かなくなることがある。そのたびにソフトを閉じ、起動し直していたが、ようやく重い腰を上げて調べてみたところ、Windows 7 の仕様で、グローバルフックのタイムアウトがどうこうらしいということがわかった。たとえば次。

そこで、タスクスケジューラを使って定期的に再起動させることにした。
まずは JScript で再起動処理を書く。黒窓を表示させないようにするための策。

var shell = WScript.CreateObject("Wscript.Shell");
var err = shell.run("taskkill /im pito.exe", 0, true);
err == 0 && WScript.sleep(1000 /* ms */);
shell.run("D:\\util\\pito\\pito.exe", 0, false);
var shell = WScript.CreateObject("Wscript.Shell");
var path = WScript.ScriptFullName.replace(WScript.ScriptName, "");


function getTarget(){
  var args = WScript.arguments;
  if(args.length < 1){
    WScript.quit(-666);
  }
  return args(0);
}

function kill(aTarget){
  return shell.run("taskkill /im " + aTarget, 0, true) == 0;
}

function isAlive(aTarget){
  return shell.run("cmd /c tasklist /fi \"IMAGENAME eq " + aTarget + "\" | find \"" + aTarget + "\"", 0, true) == 0;
}


var target = getTarget();

if(kill(target)){
  for(var i = 0; isAlive(target) && i < 20; i++){
    WScript.sleep(1000);
  }
}

if(!isAlive(target)){
  shell.run(path + target, 0, false);
}
else{ // give up
  WScript.quit(-334);
}

taskkill でプロセスを殺そうとし、ポア指令送信が成功したら 1 秒待機した後に起動し直す、また、送信失敗(基本的には対象プロセスがない場合だよね)ならば即起動というもの。taskkill は処刑台のスイッチを押すだけで、プロセス死亡そのものは非同期のようで、実際に死ぬ前に処理が返っているが、1 秒待てばその間に死ぬよね、という発想なので、ダメそうだったら待機時間を増やすなり、監視するようにするなりしよう。
やはりアレだったので変更。taskkill でプロセスを殺そうとし、最大で 20 秒だけプロセスの生死を監視し、実際に死んだら再起動、死ななかったら放置ということにした。また、スクリプトへの引数で対象プログラム名を与えることにした。これを exe と同じフォルダに置く。
これをタスクスケジューラに登録する。
f:id:electrolysis:20150119193237p:plain
「遅延時間を指定する」でログオン時から 2 分後に始動するようにしたのは、Pito! をスタートアップフォルダに入れており、2 重起動のようになるを回避するため。スタートアップから除去すれば遅延時間の設定は不要。「繰り返し間隔」を 10 分間にし、10 分ごとにスクリプトが呼ばれるようにした。すなわち、俺ログオン -> Pito! 起動 -> 2 分後にスクリプト呼び出し -> 以後 10 分ごとに呼び出し という流れになると思われる。

f:id:electrolysis:20150130214535p:plain