OnExit

AutoHotKey

OnExit

指定一个在脚本退出时自动运行的 子程序 (通常表示标签) 或 函数.

OnExit [, Label]
OnExit(Func [, AddRemove])  ; 需要 [v1.1.20+]

参数

Label

如果省略, 则脚本会返回到正常的退出行为. 否则, 请指定 label (标签) 的名称, 当脚本由于任意原因退出时将执行标签中的内容 (作为新 线程).

Func

脚本退出时调用的一个函数名称或 函数对象 . 该函数还可以有选择的定义参数, 请参考下面的例子. 如果 OnExit 调用的函数返回一个非零整数, 脚本将不会继续退出. 否则, 脚本将在该函数运行完成之后退出.

ExitFunc(ExitReason, ExitCode)
AddRemove

下列的某个值:
1: (默认) 在所有之前注册的函数之后调用该函数.
-1: 在所有之前注册的函数之前调用该函数.
0 : 不调用该函数.

总是优先调用注册的 label (标签) (子程序).

Remarks

注意: 这是调用子程序而不是退出脚本, 如果希望最终能退出脚本, 该子程序必须使用 ExitApp 命令. [v1.1.20+]: 推荐新脚本使用函数替代原来的标签 (子程序) 形式 -- 这样可以降低脚本无法退出的风险, 还能确保传递给 Exit 或 ExitApp 的退出码是可控的(保存).

[v1.1.20+]: OnExit 函数可以注册任意多个. 如果同时还注册了 label (子程序) 也会被注册, 注册的这些函数会在子程序执行 ExitApp 命令之后被调用. 通常 OnExit 不需要调用 ExitApp 命令; 如果调用了, 脚本将会立即退出.

OnExit 子程序在(收到)任何 means (译者注:理解为有意的退出信息) 时被调用 (除非被类似 "结束任务" 的方式强行终止). 无论脚本之前的实例是否使用了 #SingleInstanceReload 命令都可调用它来终止脚本.

脚本可以检测甚至终止操作系统关闭或注销, 用这段代码即可 OnMessage(0x11, "WM_QUERYENDSESSION").

OnExit 线程 并不受到 #MaxThreads 的限制 (它总是在需要的时候启动). 此外, 当它运行时, 它不会被任何 线程 中断, 包括 热键, 自定义菜单项, 和 定时器子程序 . 不过, 它会在这些情况下被终止 (且脚本也同时被终止了) : 用户从系统栏 或 主菜单栏中选择 exit 退出, 或脚本被 Reload#SingleInstance 请求作为返回值. 由于这些原因, OnExit 子程序应该被设计为尽快结束, 除非用户知道自己在做什么.

如果 OnExit 线程 遇到失败条件, 比如运行时错误时, 脚本将会终止. 这可以防止有缺陷的 OnExit 子程序脚本无法终止.

如果 OnExit 子程序由 ExitExitApp 启动并设置了退出码, 在 v1.1.19 和之前的版本中被将忽略且不可获取. 而从 [v1.1.20+] 开始, 最初的退出码将使用, 除非使用 ExitApp 指定了新的退出码.

任何当 OnExit 子程序被 exit 尝试调用时, 它都会使用脚本默认配置, 如 SendMode. 这些默认配置可在 auto-execute section (自动运行区域) 改变.

内置变量 A_ExitReason 为空,除非 OnExit 子程序正在运行或者在之前的退出中至少调用过一次.如果不是空的, 则它为下列单词的其中一个:

logoff 用户正在注销.
Shutdown 正在关闭或重启系统, 例如使用 Shutdown 命令.
Close 脚本接收到 WM_CLOSE 或 WM_QUIT 消息, 出现致命错误或者正被以其他方式关闭. 尽管这些情况都是很少见的, 然而 WM_CLOSE 可能是由脚本主窗口使用 WinClose 命令发出的. 要避免这种情况,请使用 Send, !{F4} 关闭主窗口.
错误 在没有热键且不是 持续运行的 脚本中发生了运行时错误. 运行时错误的一个例子是 Run/RunWait 命令无法启动指定的程序或打开指定的文档.
Menu 用户在主窗口的菜单或标准托盘菜单中选择了退出.
Exit 使用了 ExitExitApp 命令 (包括 自定义菜单项).
Reload 正通过 Reload 命令或菜单项重载脚本.
Single 由于 #SingleInstance 的结果, 脚本正被它自身的新实例代替.

相关

OnMessage(), RegisterCallback(), OnClipboardChange, ExitApp, Shutdown, #Persistent, Threads, Gosub, Return, Menu

示例

下面的例子使用 #Persistent 来防止脚本自动退出. 脚本启动之后, 在系统栏图标上点击鼠标右键选择 Exit 来测试 OnExit 子程序或函数. 然后点击 "Yes" 来终止脚本 或 "No" 使脚本继续运行.

#Persistent
OnExit, ExitSub
return

ExitSub:
if A_ExitReason not in Logoff,Shutdown  ; 在这行语句中, 注意不要在逗号周围含有空格.
{
    MsgBox, 4, , Are you sure you want to exit?
    IfMsgBox, No
        return
}
ExitApp  ; 脚本含有 OnExit 子程序时不会立即终止, 除非子程序使用 ExitApp.
 
#Persistent

; 注册一个在退出时调用的函数:
OnExit("ExitFunc")

; 注册一个在退出时调用的对象:
OnExit(ObjBindMethod(MyObject, "Exiting"))

ExitFunc(ExitReason, ExitCode)
{
    if ExitReason not in Logoff,Shutdown
    {
        MsgBox, 4, , Are you sure you want to exit?
        IfMsgBox, No
            return 1  ; OnExit 函数必须返回非零值来防止退出.
    }
    ; 不要用 ExitApp -- 那会阻止其他 OnExit 函数被调用.
}

class MyObject
{
    Exiting()
    {
        MsgBox, MyObject is cleaning up prior to exiting...
        /*
        this.SayGoodbye()
        this.CloseNetworkConnections()
        */
    }
}