如何优雅地关闭这个简单的 Windows GUI 程序?因为它不(有时)

How to gracefully close this simple Windows GUI program? Because it doesn't (sometimes)

我的 Windows 应用程序出现问题,从任务栏或通过热键关闭它时,它偶尔会挂起。我想知道如何优雅地退出以下程序:

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK OwnedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

static HWND mainHwnd;
static HWND ownedHwnd;

void create_windows()
{
    HMODULE thisMod = GetModuleHandleA(NULL);

    WNDCLASSA wc;
    wc.style         = CS_VREDRAW | CS_HREDRAW;
    wc.lpfnWndProc   = MainWndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = thisMod; 
    wc.hIcon         = 0;
    wc.hCursor       = 0;
    wc.hbrBackground = 0;
    wc.lpszMenuName  = NULL; 
    wc.lpszClassName = "MAINWIN";

    RegisterClassA(&wc);

    wc.lpfnWndProc   = OwnedWndProc;
    wc.lpszClassName = "OWNEDWIN";

    RegisterClassA(&wc);

    mainHwnd = CreateWindowExA(WS_EX_TOPMOST, "MAINWIN", "MAINWIN", WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), 0, 0, thisMod, NULL);

    ShowWindow(mainHwnd, SW_SHOWNORMAL);

    ownedHwnd = CreateWindowExA(WS_EX_LAYERED | WS_EX_TOPMOST, "OWNEDWIN", "OWNEDWIN", WS_POPUP, 0, 0, 200, 200, mainHwnd, 0, thisMod, NULL);

    ShowWindow(ownedHwnd, SW_SHOWNORMAL);
}


int main(int argc, char **argv)
{
    if (!RegisterHotKey(NULL, 1, MOD_NOREPEAT, VK_ESCAPE)) {
        return 0;
    }

    create_windows();

    BOOL bRet;
    MSG  msg;

    while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
        if (bRet == -1) {
            /* I'm never reached */
        } else if (msg.message == WM_HOTKEY) {
            UnregisterHotKey(NULL, 1);
            PostMessageA(mainHwnd, WM_CLOSE, 0, 0);
        } else {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    /* Do a bit of cleanup */

    return 0;
}

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static BOOL condition = FALSE;

    switch (uMsg) {
        case WM_CREATE:
            SetTimer(hwnd, 1, 20, NULL);
            return 0;
        case WM_TIMER:
            if (condition) {
                KillTimer(hwnd, 1);
                PostMessageA(ownedHwnd, WM_CLOSE, 0, 0);
            } else {
                /* Do processing here on both windows. The condition variable is
                   updated in here after the program does its thing. */
            }
            return 0;
        case WM_CLOSE:
            DestroyWindow(hwnd);
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    }

    return DefWindowProcA(hwnd, uMsg, wParam, lParam);
}

LRESULT CALLBACK OwnedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    /* Letting DefWindowProcA handle everything since I don't need this window to
       do anything but close afterwards. */
    return DefWindowProcA(hwnd, uMsg, wParam, lParam);
}

当它确实挂起时,它似乎总是在计时器已经被禁用并且拥有的 window 已经关闭之后发生。从未。无论是在控制台模式还是 windows 模式,它总是一样的,总是在这两种情况发生之后我尝试关闭 window.

使用 printf 语句(因为我不完全确定如何调试它)我注意到当它冻结时 WM_CLOSE 并且随后 WM_DESTROY 从未在 MainWndProc 中达到,就好像它是卡在 GetMessage 或 DispatchMessage 或我的消息循环的某个深处,我没有在这个程序中做任何花哨的事情,所以我不知道。当我设法在调试器中实现这一点时,它最终仍然 运行ning 但我无法暂停它并逐步查看它正在执行的位置。

奇怪的是,尽管我不再观察到,当我在控制台模式下关闭它时,window 会消失,但进程会在后台继续 运行,直到 cmd window 我从中启动的程序接收到键盘输入或关闭。相反,在 windows 模式下会发生同样的情况,但不会有 cmd window,而是必须从任务管理器中结束它。

我从来没有遇到过只需要一个 window 的简单 Windows GUI 应用程序的问题。只有当有更多的时候,我才 运行 陷入这个永远不会完全关闭并且不知道如何优雅退出的问题。

Welp 结果是使用 WinMain 而不是 main,并且没有将其指定为入口点(因此 C 运行-time 库被正确初始化)解决了它.就这样。我仍然无法完全理解它。

在我发现这一点之前,我注意到在调试器中,当程序脱离消息循环并退出时,仍有许多线程 运行ning。奇怪的是我从来没有创建任何线程...

不幸的是,我不知道是什么让我尝试 WinMain,因为那时我一直在控制台和 windows 模式下疯狂地尝试不同的配置,直到我到达那个成功了。