如何正常关闭此简单的Windows GUI程序?因为它不(有时)

问题描述 投票:0回答:1

我的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);
}

当它挂起时,它似乎总是在定时器已被禁用并且拥有的窗口已关闭之后发生。前所未有。无论是在控制台模式下还是在Windows模式下,它总是相同的,总是在这两种情况发生之后,然后尝试关闭窗口。

使用printf语句(因为我不太确定如何调试它),我已经注意到,当它冻结WM_CLOSE并随后在MainWndProc中从未到达WM_DESTROY时,就好像它被卡在GetMessage或DispatchMessage或我的消息中循环,我没有在该程序中做任何花哨的事情,所以我一无所知。当我设法在调试器中完成此操作时,它最终仍在运行,但是我无法暂停它,而是一步一步查看执行的位置。

奇怪的是,虽然我已经观察不到,但是当我以控制台方式关闭它时,该窗口将消失,但是该过程将继续在后台运行,直到启动该程序的cmd窗口收到键盘输入或关闭为止。相反,在Windows模式下会发生相同的情况,但是没有cmd窗口,而是必须从任务管理器中结束它。

我对只需要一个窗口的简单Windows GUI应用程序从未遇到任何麻烦。只有在我遇到更多问题时,它才会完全关闭并且不知道如何正常退出。

c windows winapi gdi windows-messages
1个回答
0
投票

您从未将condition设置为TRUE,不会杀死计时器。

并添加错误检查以确保窗口类注册成功并创建窗口。

下面是可以检查的工作代码:

#include <iostream>
#include <windows.h>

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";

    ATOM mainAtom = RegisterClassA(&wc);
    if (!mainAtom)
    {
        printf("error: %d\n", GetLastError());
        return;
    }

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

    ATOM ownAtom = RegisterClassA(&wc);
    if (!ownAtom)
    {
        printf("error: %d\n", GetLastError());
        return;
    }

    mainHwnd = CreateWindowExA(WS_EX_TOPMOST, "MAINWIN", "MAINWIN", WS_POPUP | WS_BORDER, 10, 10, 100, 100, 0, 0, thisMod, NULL);
    if (mainHwnd == NULL)
    {
        printf("error: %d\n", GetLastError());
        return;
    }

    ShowWindow(mainHwnd, SW_SHOWNORMAL);

    ownedHwnd = CreateWindowExA(WS_EX_LAYERED | WS_EX_TOPMOST, "OWNEDWIN", "OWNEDWIN", WS_POPUP | WS_BORDER, 10, 130, 200, 200, mainHwnd, 0, thisMod, NULL);
    if (ownedHwnd == NULL)
    {
        printf("error: %d\n", GetLastError());
        return;
    }

    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) {
        }
        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:
        condition = TRUE;
        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);
}
© www.soinside.com 2019 - 2024. All rights reserved.