作者:小 琛
欢迎转载,请标明出处
需求场景
应用在每次退出时,都需要做某些检测操作,例如:版本号、资源信息。但针对某个极端情况,应用未退出,使用者直接将电脑进行了关闭,从而我的应用数据出现了错误
计算器关机时针对未关闭应用的处理方式
- 在Windows操作系统中,当用户关闭计算机或注销用户时,操作系统会向所有运行的进程发送关闭信号。这个信号告知进程系统即将关闭,通常是通过发送
WM_CLOSE
消息(GUI应用程序)或CTRL_SHUTDOWN_EVENT
事件(控制台应用程序)来实现的。这些消息和事件会触发应用程序执行关闭操作,包括清理和保存数据等。 - 如果应用程序在接收到关闭信号后没有正确地执行关闭操作,并且系统超时时间到达,则操作系统可能会直接调用
TerminateProcess
函数来强制终止应用程序。这种情况下,应用程序将会被直接终止,而不会有机会进行正常的关闭和清理操作。
总结:操作系统会先发送WM_CLOSE消息,目的是让应用自行完结。若超时进程仍未退出,则会使用TerminateProcess直接进行退出
WM_QUERYENDSESSION
WM_QUERYENDSESSION 是一个Windows消息,用于向应用程序发送一个询问消息,询问应用程序是否愿意响应系统关闭或注销事件。当系统要关闭或注销时,操作系统会发送
WM_QUERYENDSESSION
消息给所有正在运行的应用程序,以询问它们是否愿意响应并执行一些清理操作。
思路
- 应用程序可以通过处理
WM_QUERYENDSESSION
消息来决定是否终止当前会话。如果应用程序返回,表示它不愿意响应系统关闭或注销事件,系统会尝试终止应用程序,但不会等待应用程序保存数据或执行其他清理操作。如果应用程序返回非0(真),系统会等待应用程序完成必要的清理操作,然后再终止应用程序。 - 例如在Qt中,可以通过重载
nativeEvent
函数来处理WM_QUERYENDSESSION
消息。当收到这个消息时,执行一些需要在系统关闭前完成的操作,比如保存数据、关闭文件等。这样可以确保应用程序在系统关闭或注销时能够做一些额外的处理。
注意:这个过程要尽可能轻量
例子
class NativeEventFilter : public QObject, public QAbstractNativeEventFilter {
public:
explicit NativeEventFilter(QObject* parent = 0) : QObject(parent) {}
bool nativeEventFilter(const QByteArray& et, void* msg, long* result) Q_DECL_OVERRIDE {
bool ret = false;
if (et == "windows_generic_MSG" || et == "windows_dispatcher_MSG") {
if (auto const pMsg = static_cast<MSG*>(msg); pMsg->message == WM_USER_WAKE) {
wakePlayer();
if (result) *result = true;
ret = true;
} else if (pMsg->message == WM_CLOSE) {
// do something
} else if (pMsg->message == WM_QUERYENDSESSION) {
// do something
if (result) *result = TRUE; // Indicate that the session can end
ret = true;
}
}
return ret;
}
};
// 在进程初始化时
NativeEventFilter __filter;
installNativeEventFilter(&__filter);
在这个例子中,我自定义了一个事件处理类,里面实现了当接收到原生的Windows消息时,检查是否是WM_QUERYENDSESSION
消息,并在接收到该消息时执行一些操作,设置result
为非0表示愿意响应系统关闭或注销事件。
同时我在我的application初始化时,生成了一个对象,调用installNativeEventFilter注册一个自定义的事件过滤器对象。
这样就可以实现,在电脑关闭时,正常响应我需要的事件。