Gracefully closing a windowless application in WinAPI

I am writing a small utility application to control the system volume using hot keys for my GF, whose laptop for some reason lacks such function keys. I instantly cracked the code, and I have basic functionality that works perfectly; however, since I do not create any windows (just the message loop processes the WM_HOTKEY message), I cannot finish the application more elegantly than simply terminate the process immeasurably (also when the system shuts down, it shows "should I wait for the process to finish or kill it now "with some garbage in the place where the window title is usually).

Is there a way to do this, not involving creating a fake window just to intercept WM_CLOSE messages?

Here is the code (I deliberately ignored the mixer control functions, they are not relevant to the question):

int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) {
    MSG msg;
    int step;
    MixerInfo_t mi;
    HANDLE mutex;

    mutex = CreateMutex(NULL, TRUE, "volhotkey");
    if (mutex == NULL)
        return 1;
    if (GetLastError() == ERROR_ALREADY_EXISTS)
        return 0;

    RegisterHotKey(NULL, 1, MOD_ALT | MOD_CONTROL, VK_F5);
    RegisterHotKey(NULL, 2, MOD_ALT | MOD_CONTROL, VK_F6);
    RegisterHotKey(NULL, 3, MOD_ALT | MOD_CONTROL, VK_F7);

    mi = GetMixerControls();
    step = (mi.maxVolume - mi.minVolume) / 20;

    while (GetMessage(&msg, NULL, 0, 0)) {
        switch (msg.message) {
            case WM_HOTKEY:
                switch (msg.wParam) {
                    case 1:
                        AdjustVolume(&mi, -step);
                        break;
                    case 2:
                        AdjustVolume(&mi, step);
                        break;
                    case 3:
                        SetMute(&mi, !IsMuted(&mi));
                        break;
                }
                MessageBeep(MB_ICONASTERISK);
                break;
            case WM_DESTROY:
                PostQuitMessage(0);
                break;
            default:
                break;
        }
    }

    UnregisterHotKey(NULL, 1);
    UnregisterHotKey(NULL, 2);

    return msg.wParam;
}

Thanks in advance!

Oh, and for the record, WM_DESTROY is also never sent.

+3
source share
4 answers

You can use the SetConsoleCtrlHandler () function to listen for the shutdown event.

SetConsoleCtrlHandler( ShutdownHandler, TRUE );

Your handler will look something like this:

BOOL WINAPI ShutdownHandler( DWORD dwCtrlType )
{
    if( dwCtrlType == CTRL_SHUTDOWN_EVENT || dwCtrlType == CTRL_LOGOFF_EVENT )
    {
        ExitProcess( 0 );
        return TRUE; // just to keep the compiler happy
    }

    return FALSE;
}

Despite the name, SetConsoleCtrlHandler () works regardless of whether the application is a console application.

+4
source
+1

, , , . , WM_DESTROY .

, , - PostThreadMessage(), WM_QUIT. - . Shell_NotifyIcon() .

+1

You can always show something in the system tray quite easily, from which you could elegantly close it. And as your application grows, this may be desirable, because the user may ultimately want to configure or change the hot keys or temporarily disable them, they interfere with another application, etc.

Or is there another hotkey that displays a small window with configuration options?

0
source

Source: https://habr.com/ru/post/1789317/


All Articles