Как изящно закрыть эту простую Windows GUI программу? Потому что это не (иногда) - PullRequest
0 голосов
/ 26 марта 2020

У меня проблема с моим 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 и впоследствии WM_DESTROY никогда не достигается в MainWndPro c, как будто он застрял где-то глубоко в GetMessage или DispatchMessage, или мое сообщение l oop, я не делаю ничего фантастического в этой программе поэтому я понятия не имею. Когда мне удается сделать это в отладчике, он все равно работает, но я не могу приостановить его и посмотреть, где он выполняется.

Странно, хотя я больше не наблюдал, когда я закрывал его в консольном режиме, окно исчезало, но процесс продолжал выполняться в фоновом режиме, пока окно cmd, из которого я запускал программу, не получило ввод с клавиатуры или не закрылось. И наоборот, в режиме windows происходит то же самое, но окна cmd не будет, вместо этого придется завершать его из диспетчера задач.

У меня никогда не было проблем с простым Windows GUI приложения, где требуется только одно окно. Только когда я сталкиваюсь с этой проблемой, я больше никогда не закрываюсь и не знаю, как изящно выйти.

1 Ответ

0 голосов
/ 03 апреля 2020

Хорошо, получается, что с помощью WinMain вместо main, и без указания ее в качестве точки входа (таким образом, библиотека времени выполнения C инициализируется правильно), это решено. И это все. Я все еще не могу полностью обернуть голову вокруг него.

Прежде чем я обнаружил это, я заметил в отладчике, что, когда программа вышла из сообщения l oop и вышла, было еще несколько потоков, все еще работающих. Что странно, я никогда не создавал никаких потоков ...

Я не знаю, что побудило меня попробовать WinMain, к сожалению, поскольку я дико экспериментировал с другой конфигурацией в тот момент в консоли и windows режим, пока я не прибыл на тот, который работал.

...