【发布时间】:2013-10-12 07:41:16
【问题描述】:
我正在将一个 Linux 应用程序移植到用 Qt 编写的 Windows。应用程序需要在关闭前保存一些设置。在 Linux 上,我们可以通过 SIGTERM 等信号处理程序来做到这一点。如何在 Windows 上实现相同的功能。
【问题讨论】:
标签: c++ windows qt qt-signals qtcore
我正在将一个 Linux 应用程序移植到用 Qt 编写的 Windows。应用程序需要在关闭前保存一些设置。在 Linux 上,我们可以通过 SIGTERM 等信号处理程序来做到这一点。如何在 Windows 上实现相同的功能。
【问题讨论】:
标签: c++ windows qt qt-signals qtcore
如果你使用的是 Qt 事件循环,你可以捕捉到以下信号:
void QCoreApplication::aboutToQuit() [信号]
当应用程序即将退出主事件循环时发出此信号,例如当事件循环级别降至零时。这可能发生在从应用程序内部调用 quit() 之后或当用户关闭整个桌面会话时。 如果您的应用程序必须在最后一秒进行清理,该信号特别有用。请注意,在此状态下无法进行任何用户交互。
除此之外,如果上述信号不适合您的用例,您可能会在下面查找以下消息:
WM_QUIT:http://msdn.microsoft.com/en-us/library/windows/desktop/ms632641(v=vs.85).aspx
WM_CLOSE:http://msdn.microsoft.com/en-us/library/windows/desktop/ms632617(v=vs.85).aspx
WM_QUERYENDSESSION:http://msdn.microsoft.com/en-US/library/windows/desktop/aa376890.aspx
WM_ENDSESSION:http://msdn.microsoft.com/en-US/library/windows/desktop/aa376889.aspx
【讨论】:
我不知道 Qt。如果您负担得起仅 Windows 的费用,WM_QUERYENDSESSION 和 WM_ENDSESSION 消息可能是正确的做法。
【讨论】:
我认为其他答案完全没有抓住重点:当你强行结束一个应用程序时,它就像 Unix 上的 SIGKILL。 没有办法处理它 - 除非提前。提前处理它的意思是确保每次更改设置时都保存设置。当然,您可以优化此行为,例如,如果设置脏了,则每隔几秒保存一次设置,如果您想尽量减少磁盘访问次数(想想移动设备上的功耗)。
QSettings 会为您处理很多问题。只要你使用QSettings,你就会得到合理的行为。如果您自己保存文件,请使用QSaveFile,因为它处理刷新文件和近似原子文件替换,这样如果在您进行写入的过程中出现终止(强制终止),您就不会丢失设置.
QCoreApplication 发出的aboutToQuit 信号是您想要在应用程序被要求退出时简单地做某事时想要做出的反应。这相当于处理WM_QUIT 消息, 或处理Unix 上的 处理 SIGTERM。因此,以特定于平台的方式进行操作是毫无意义的,因为 Qt 已经为您完成了。WM_CLOSE 同样没有意义,因为这是只有 Windows 才能收到的消息,而且 Qt 已经为您处理了。
您还可以通过安装QAbstractNativeEventFilter 并处理WM_ENDSESSION 和WM_QUERYENDSESSION 来参与注销/关闭过程。仅当您想提前知道应用程序将被退出时,这才有意义。除非您明确想要停止关机/注销,否则您无需担心。
【讨论】:
SIGTERM,这是一个优雅的关闭信号,而不是SIGKILL。
我认为处理QApplication::commitDataRequest 信号(或Qt5 中的QGuiApplication::commitDataRequest)而不是aboutToQuit 可能会更好。只需将信号连接到您的功能即可保存设置。
【讨论】:
会话注销将发出aboutToQuit
case WM_ENDSESSION: {
sm_smActive = false;
sm_blockUserInput = false;
bool endsession = (bool) wParam;
// we receive the message for each toplevel window included internal hidden ones,
// but the aboutToQuit signal should be emitted only once.
QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
if (endsession && !qAppPriv->aboutToQuitEmitted) {
qAppPriv->aboutToQuitEmitted = true;
int index = QApplication::staticMetaObject.indexOfSignal("aboutToQuit()");
qApp->qt_metacall(QMetaObject::InvokeMetaMethod, index,0);
// since the process will be killed immediately quit() has no real effect
QApplication::quit();
}
RETURN(0);
}
【讨论】: