[Interest] Handling WM_QUIT messages when no window is shown

Henry Skoglund henry at tungware.se
Wed May 6 14:57:53 CEST 2020


On 2020-05-06 11:09, Julius Bullinger wrote:
> Usually, sending a WM_QUIT message to a QApplication triggers the 
> QCoreApplication::aboutToQuit() signal, e.g. when ending the 
> application via Windows's Task Manager, or using "taskkill /PID <pid>".
>
> We discovered that no aboutToQuit() signal is emitted when a 
> QApplication without windows receives a WM_QUIT:
>
>     #include <QApplication>
>     #include <QDebug>
>     #include <QWidget>
>
>     int main(int argc, char *argv[]) {
>       QApplication app(argc, argv);
>
>       QApplication::connect(&app, &QApplication::aboutToQuit, []() {
>         qDebug() << "QApplication::aboutToQuit";
>       });
>
>       // Commenting those lines will not trigger aboutToQuit() when
>       // the application is closed via Task Manager:
>       QWidget w;
>       w.show();
>
>       return app.exec();
>     }
>
> Our application supports a text-only variant, where the GUI is 
> disabled. We're basically doing it like that, and wondered why our 
> shutdown code was not called when the application was quit via the 
> Task Manager.
>
> Is there anything that needs to be done to get consistent behavior?
>
Hi, when running apps on Windows without a window, you'll be missing out 
on a lot of inter-process stuff like WM_QUIT (that's why it's common for 
windowless apps to create a hidden, non-interactive window just to be 
able to receive all those WM_XXX). So no aboutToQuit() will be emitted 
for you when you skip creating that widget window.

But there's an API for windowless apps where you can receive a control 
signal, e.g. Ctrl-C was pressed or someone (like the Task Manager) is 
shutting down the app, more here: 
https://docs.microsoft.com/en-us/windows/console/setconsolectrlhandler 
and the callback: 
https://docs.microsoft.com/en-us/windows/console/handlerroutine

There's no support for that API in Qt but it's pretty easy to use. 
Here's an example, I created a vanilla Qt console app, and changed 
main.cpp to this:
-----------------------------------------
#include <QCoreApplication>
#include <windows.h>

BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
{
     switch (fdwCtrlType)
     {
     case CTRL_CLOSE_EVENT:
          ::OutputDebugStringA("Ctrl-Close event"); // catch taskkill or 
Task Manager End task
         return TRUE;

     default:
         return FALSE;
     }
}

int main(int argc, char *argv[])
{
     QCoreApplication app(argc, argv);

     SetConsoleCtrlHandler(CtrlHandler, TRUE);

     return app.exec();
}
-----------------------------------------
Note: I'm using OutputDebugString and DbgView.exe to view the output, 
qDebug() output has a tendency to disappear when you test with "End 
task" from TaskManager.

Note 2: this API is very flakey if you try it from a GUI-built .exe, for 
Qt apps I mean built with "QT += core gui etc" in the .pro file, and use 
of QApplication in main.cpp. Instead you need to build your app like a 
Qt console app, "QT -= gui" and CONFIG += console, and use 
QCoreApplication in main.cpp, like in my example above.

Rgrds Henry



More information about the Interest mailing list