开发者

Gracefully closing a windowless app in WinAPI

开发者 https://www.devze.com 2023-02-08 03:32 出处:网络
I\'m writing a little utility app to control the system master volume via hotkeys for my GF, whose laptop is for some reason deprived of such function keys. I whipped up the code pretty much instantly

I'm writing a little utility app to control the system master volume via hotkeys for my GF, whose laptop is for some reason deprived of such function keys. I whipped up the code pretty much instantly and I've got the main functionality working perfectly; however, since I'm not creating any windows (just a message loop handling the WM_HOTKEY message), I can't terminate the app in a more elegant manner than just gracelessly terminating the process (also, when the system is shutting down, it shows the "should I wait for the process to end or kill it now" window with some rubbish in the place where the window title usually is).

Is there any way of doing this which doesn't involve creating a fake window just for the sake of intercepting WM_CLOSE messages?

Here's the code (I left out the mixer control functions intentionally, they're irrelevant 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开发者_StackOverflow is also never posted.


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

SetConsoleCtrlHandler( ShutdownHandler, TRUE );

You handler would 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 or not the application is a console application.


Have a look at the ExitProcess API call for shutting down a process gracefully. To detect a Windows shutdown, include WM_ENDSESSION in your message handling. If your application is more complex than what is posted, you may also want to review the ExitThread function.


You didn't create any window, not even a hidden one, so there's no way to get the loop to exit by sending a message to a window. Also the reason that WM_DESTROY never fires.

All that's left is PostThreadMessage() to post WM_QUIT. You'd have to be able to find the thread ID somehow. Using Shell_NotifyIcon() would be wise.


You could always show something in the system tray easily enough from which you could elegantly close it. And as your application grows, that may be desirable, because the user may eventually want to be able to configure or change the hotkeys, or temporarily turn them off it they interfere with another application etc.

Or have another hotkey which shows a small window with configuration options?

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号