Приложение WINAPI закрывается, когда я нажимаю ALT, почему? - PullRequest
0 голосов
/ 19 октября 2019

Я практиковал приложения Winapi раньше, но никогда не сталкивался с этой проблемой.

Я попытался создать собственный WindowProc для переопределения поведения по умолчанию для сообщений WM_QUIT / WM_CLOSE / WM_DESTROY, чтобы ничего не делать, но окно все равно закрывается, когда я нажимаю ALT!

Это весь код:

int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
    const LPCSTR className = "Class name";
    WNDCLASS wc = {};
    wc.style = 0;
    wc.lpfnWndProc = DefWindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = GetModuleHandle(nullptr);
    wc.hIcon = nullptr;
    wc.hCursor = nullptr;
    wc.hbrBackground = nullptr;
    wc.lpszMenuName = nullptr;
    wc.lpszClassName = className;

    RegisterClass(&wc);
    HWND window = CreateWindow(className, "Title", WS_OVERLAPPEDWINDOW, 200, 200, 600, 400, nullptr, nullptr, nullptr, nullptr);

    ShowWindow(window, SW_SHOW);

    MSG msg = {};

    while (msg.wParam != WM_QUIT)
    {
        while(PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return msg.wParam;
}

Я считаю, что окно не должно закрываться, когда я нажимаю ALT, но оно закрывается.

Ответы [ 2 ]

4 голосов
/ 19 октября 2019

Вы смешиваете поле message с полем wParam:

while (msg.wParam != WM_QUIT)

Когда вы нажимаете ALT, окно получает сообщение WM_KEYDOWN, в котором wParam - это виртуальный код ключа. Бывает, что ALT имеет тот же код VK, что и константа для WM_QUIT (0x12).

Кроме того, вы также переводите и отправляете WM_QUIT перед выходом. Вы можете справиться с обоими из них, имея один уровень отступа с соответствующей проверкой:

while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) && msg.message != WM_QUIT)

Как указано в комментарии, это чище с GetMessage:

while (GetMessage(&msg, nullptr, 0, 0) > 0)
3 голосов
/ 19 октября 2019

Есть несколько проблем с вашим кодом.

Во-первых, вы должны использовать GetMessage(), а не PeekMessage(). Принципиальное отличие состоит в том, что PeekMessage() не является блокирующим, и, следовательно, ваша программа будет использовать 100% ЦП, на котором выполняется этот цикл.

Кроме того, поскольку внутренний цикл может проходить или не проходить по нескольким сообщениям встрока, проверка вещей во внешнем цикле, как вы делаете, будет хитом или промахом и не проверит все сообщения. Вместо этого вам следует проверять каждое сообщение во внутреннем цикле.

Но в этом случае это необязательно, поскольку этот цикл завершится, если окно все равно будет закрыто. Эта проверка, которую вы делаете, бессмысленна.

Есть несколько других несоответствий с вашим кодом, wc.hInstance должно быть hInstance, что вы получили в качестве параметра в WinMain(). Нет необходимости искать эту информацию с помощью API.

Кроме того, CreateWindow() должен снова получить hInstance в качестве второго по значению параметра, а не nullptr.

И, наконец, как указано chris 'answer , вы должны искать тип сообщения в msg.message, а не в msg.wParam.

В дополнение ко всему, здесь не место делать"Custom WindowProc". Если вы хотите создать пользовательский WndProc, вы должны установить wc.lpfnWndProc для своей собственной функции вместо DefWindowProc, и там вы можете определить свое поведение для своего окна.

Например:

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CLOSE:
    case WM_DESTROY:
        // do nothing
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

Обратите внимание, что нет необходимости проверять WM_QUIT, так как это сообщение будет появляться, только если ваше приложение вызывает PostQuitMessage().

...