LoginSignup
0
1

More than 5 years have passed since last update.

[AutoHotKey]OnExitが動かない条件

Posted at

Loopを含むスクリプトでOnExitが動かないことがあったので調べてみた。

結論としては、ざっくり言ってスクリプトがなんらかの待機中だとダメなもよう。

基本的なOnExitの使い方

サブルーチンラベルを指定する方法と関数を指定する方法があるが、どちらでも条件は変わらない。今回は、Wikiに記載のない関数指定の紹介を兼ねてそちらを例に取る。

原則として、以下を守ること。

  • OnExitコマンドはAuto-executeセクションに記述する
    • サブルーチンの場合、ラベルはAuto-executeセクションに記述してはならない(その後に書く)
      • そうしないとスクリプト起動時に実行されてしまうから
    • 関数の場合、どちらに書いてもよい
  • 指定サブルーチンまたは関数内でExitなりExitAppを実行する
    • 関数の場合、それらコマンドの終了コードを1とする

以下は正常に実行される例。単純なホットキーを実装したスクリプト。

タスクトレイアイコンのコンテクストメニューからExitするとメッセージが表示される。

/*
いちおうサブルーチンラベルの場合もコメントで併記した。
*/
; OnExit, ExitSub
OnExit("ExitFunc")

Return ; Auto-executeセクションの終了

; ExitSub:
    ; MsgBox, , , 終了したよーーーーーー!!!!!
    ; ExitApp, 1
ExitFunc(ExitReason, ExitCode)
{
    MsgBox, , , 終了したよーーーーーー!!!!!
    ExitApp, 1
}

~^S:: ; Ctrl+Sを押したときにメッセージを表示する
    MsgBox, , %A_ScriptName%, セーブしたよーーーーーー!!!!!
    Return

仕様的には問題ないと思うけどダメな例

他にもありそうだが、とりあえず検証できたのは以下の通り。

Loopの実行中

以下は、無限ループで数値を加算しながらツールチップに表示するスクリプト。

無限ループなので、手動で終了しない限り永遠に止まらない。このような場合、OnExitは機能しない。

loop
{
    counter+=1
    ToolTip, %counter%
}

/*
いちおうサブルーチンラベルの場合もコメントで併記した。
*/
; OnExit, ExitSub
OnExit("ExitFunc")

Return ; Auto-executeセクションの終了

; ExitSub:
    ; MsgBox, , , 終了したよーーーーーー!!!!!
    ; Exit, 1
ExitFunc(ExitReason, ExitCode)
{
    MsgBox, , , 終了したよーーーーーー!!!!!
    Exit, 1
}

Sleep中

以下は、一定時間Sleep後にメッセージを表示するスクリプト。一定時間が経過して最後まで実行された場合は問題ないが、Sleep中にタスクトレイアイコンから終了するとダメ。

Sleep 5000 ; 5秒待つ
MsgBox, , %A_ScriptName%, 5秒経ったよーーーーーー!!!!!

/*
いちおうサブルーチンラベルの場合もコメントで併記した。
*/
; OnExit, ExitSub
OnExit("ExitFunc")

Return ; Auto-executeセクションの終了

; ExitSub:
    ; MsgBox, , , 終了したよーーーーーー!!!!!
    ; Exit, 1
ExitFunc(ExitReason, ExitCode)
{
    MsgBox, , , 終了したよーーーーーー!!!!!
    Exit, 1
}

なんちゃらWait中

以下は、メモ帳がアクティブになったらメッセージを表示するスクリプト。

一度メモ帳がアクティブになり、WinWaitActiveが済んだらOKだが、その前にタスクトレイアイコンから終了するとダメ。

SetTitleMatchMode, 2 ; タイトルを中間一致検索
WinWaitActive, メモ帳
MsgBox, , , メモ帳を開いたよーーーーーー!!!!!

/*
いちおうサブルーチンラベルの場合もコメントで併記した。
*/
; OnExit, ExitSub
OnExit("ExitFunc")

Return ; Auto-executeセクションの終了

; ExitSub:
    ; MsgBox, , , 終了したよーーーーーー!!!!!
    ; Exit, 1
ExitFunc(ExitReason, ExitCode)
{
    MsgBox, , , 終了したよーーーーーー!!!!!
    Exit, 1
}

Msgboxの表示中

以下は、メッセージを表示するだけのスクリプト。

OKボタンをクリックして(またはEnterを押して)メッセージを消したらOKだが、メッセージが表示されたまんまタスクトレイアイコンから終了するとダメ。

MsgBox, , , ぎゃおおおおおおおん!!!!!

/*
いちおうサブルーチンラベルの場合もコメントで併記した。
*/
; OnExit, ExitSub
OnExit("ExitFunc")

Return ; Auto-executeセクションの終了

; ExitSub:
    ; MsgBox, , , 終了したよーーーーーー!!!!!
    ; Exit, 1
ExitFunc(ExitReason, ExitCode)
{
    MsgBox, , , 終了したよーーーーーー!!!!!
    Exit, 1
}

そもそも仕様的にダメそうな例

例えば、Windowsタスクマネージャからプロセスを終了するとダメ。まあそりゃそうだ。

試してないけど、コマンドプロンプトでtaskkillとかAutoHotKeyスクリプトでProcess, closeとかもダメだろう。

一応の対処方法

そもそも何をしようとしてたかって、ループを手動で中断した時に指定の処理を入れたかったんだけど、OnExitじゃできないもよう。困った。

無理矢理感あふるるが、例えば、Menu, Trayで「なんかしつつExitする」メニューを作るとかすれば、似たようなことはできんでもない。

以下は、Loopの例にタスクトレイアイコンのコンテクストメニューの指定を加えたもの。

Menu, Tray, Add, Exit2, ExitALT ; タスクトレイアイコンのコンテクストメニューに「Exit2」を追加

loop
{
    counter+=1
    ToolTip, %counter%
}

Return ; Auto-executeセクションの終了

ExitALT: ; 「Exit2」の処理内容。メッセージを表示してスクリプトを終了する。
    MsgBox, , , 終了したよーーーーーー!!!!!
    Exit, 1

タスクトレイメニューなりホットキーなりで手動で終了する場合の処理はこんな感じでできんでもないのだが、なんらかの待機中にWindowsが再起動した場合とかはどうしようもない。

さらなる無理やりだが、スクリプトを監視するためのスクリプトを作ってしまうくらいか。

  • 実行用スクリプト
    • 終了時になんらかの処理を行う
      • OnExitを使う
      • 手動終了時についでにできるようにしておく
    • 起動/終了時に監視用スクリプトを起動/終了する
  • 監視用スクリプト
    • それ自体がWindowsのログオフ/シャットダウン(再起動)に伴って終了する場合、実行用スクリプトの実行状態を確認する
      • つまりIf (A_ExitReason = "Logoff" or "Shutdown")
    • 実行用スクリプトが実行中でない(つまり、Windowsの終了に巻き込まれて意図せず終了している)場合、なんらかの処理を行う

とても両方書き起こす気力が沸かないが、せっかく調べたのでスクリプトの実行状態を確認する方法のみ記す。

DetectHiddenWindows, On ; 非表示ウインドウを検出する
IfWinExist, <対象スクリプトのパス> ahk_class AutoHotkey
{
    /*
    実行したい処理
    */
}
  • この際、対象スクリプトは#Persistentないしホットキーラベル等により明示的に常駐状態である必要はない。
  • #NoTrayIconでも問題ない。
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1