Loop
を含むスクリプトでOnExit
が動かないことがあったので調べてみた。
結論としては、ざっくり言ってスクリプトがなんらかの待機中だとダメなもよう。
基本的なOnExitの使い方
サブルーチンラベルを指定する方法と関数を指定する方法があるが、どちらでも条件は変わらない。今回は、Wikiに記載のない関数指定の紹介を兼ねてそちらを例に取る。
原則として、以下を守ること。
-
OnExit
コマンドはAuto-executeセクションに記述する- サブルーチンの場合、ラベルは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の終了に巻き込まれて意図せず終了している)場合、なんらかの処理を行う
- それ自体がWindowsのログオフ/シャットダウン(再起動)に伴って終了する場合、実行用スクリプトの実行状態を確認する
とても両方書き起こす気力が沸かないが、せっかく調べたのでスクリプトの実行状態を確認する方法のみ記す。
DetectHiddenWindows, On ; 非表示ウインドウを検出する
IfWinExist, <対象スクリプトのパス> ahk_class AutoHotkey
{
/*
実行したい処理
*/
}
- この際、対象スクリプトは
#Persistent
ないしホットキーラベル等により明示的に常駐状態である必要はない。 -
#NoTrayIcon
でも問題ない。