Основное создание окна - PullRequest
0 голосов
/ 02 июня 2018

У меня проблема с обработкой окна Windows, хотя я делал это один раз раньше, и он работал нормально.После прочтения наиболее распространенных предложений по этой проблеме, он все еще остается.Может кто-нибудь сказать мне, почему обработка ввода нарушена?

Намеренное поведение:

  1. создать окно с названием 'FirstTry'
  2. Сделать его фон черным, используя PatBlt
  3. Показать окно сообщения при первом вводе основного цикла и после нажатия кнопки 'w'.
  4. Закрыть окно при нажатии клавиш Alt + F4, Escape или кнопки закрытия,отображение закрывающего сообщения.

Наблюдаемое поведение:

  1. по назначению
  2. по назначению
  3. MessageBox появляется в первый раз, ноне перезапускается с помощью 'w'
  4. Окно не закрывается, кроме как с помощью TaskManager (один раз он показывал 'закрывающий Application-MessageBox', как и предполагалось, но только один раз)
    • окно можно перетаскивать допервый «введенный цикл» - MessageBox закрывается, после чего его фиксированный
    • маленький синий «занятый» круг windows10 отображается постоянно, после первого MessageBox

Вывод: Обработка сообщений iсломанИ я не могу понять, почему ...


Система:

  • Windows 10, версия 1803 (сборка 17134.81), 64-разрядная

Компилятор из VS 2017 Community Edition:

  • vcvarsall.bat amd64

  • cl -MTd -nologo -FC -Zi -W4 -WX -wd4100 -wd4312 FirstTry.cpp / link User32.lib Gdi32.lib


#include "windows.h"

static bool bAppIsRunning = false;
static bool bMessageAlreadyShown = false;

LRESULT CALLBACK win_MainWNDCallback(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam){
    LRESULT result = 0;
    switch(msg){
        case WM_SYSKEYDOWN:
        case WM_SYSKEYUP:
        case WM_KEYDOWN:
        case WM_KEYUP:{
            WPARAM vKeyCode = wParam;
            bool bWasDown = ((lParam & (1 << 30)) != 0);
            bool bIsDown = ((lParam & (1 << 31)) == 0);
            if (bWasDown != bIsDown)
            {
                switch (vKeyCode)
                {
                    case VK_ESCAPE:{
                        bAppIsRunning = false;
                    }break;
                    default:{
                        result = DefWindowProc(wnd,msg,wParam,lParam);
                    }break;
                }
            }
        }break;
        default:{
            result = DefWindowProc(wnd,msg,wParam,lParam);
        }break;
    }

    return result;
}

int CALLBACK WinMain(HINSTANCE HInstance, HINSTANCE HPrevInstance, LPSTR LpCmdLine, int NCmdShow){

    WNDCLASSA wndCLass = {};
    wndCLass.style = CS_HREDRAW | CS_VREDRAW;
    wndCLass.lpfnWndProc = win_MainWNDCallback;
    wndCLass.hInstance = HInstance;
    wndCLass.lpszClassName = (LPCSTR)"WindowClass";

    if(RegisterClassA(&wndCLass)){

        HWND wnd = CreateWindowExA(
            0, wndCLass.lpszClassName, (LPCSTR)"FirstTry", 
            WS_OVERLAPPEDWINDOW | WS_VISIBLE, 
            CW_USEDEFAULT, CW_USEDEFAULT, 
            1240, 720,
            0, 0, HInstance, 0);

        if(wnd){
            bAppIsRunning = true;

            HDC DeviceContext = GetDC(wnd);
            PatBlt(DeviceContext, 0, 0, 1240, 720, BLACKNESS);
            ReleaseDC(wnd, DeviceContext);

            while(bAppIsRunning){

                if(!bMessageAlreadyShown){
                    MessageBoxA(NULL, (LPCSTR)"Successfully entered loop.", (LPCSTR)"Success!", MB_ICONINFORMATION | MB_OK);
                    bMessageAlreadyShown = true;
                }

                MSG msg;
                while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)){
                    switch(msg.message){
                        case WM_SYSKEYDOWN:
                        case WM_SYSKEYUP:
                        case WM_KEYDOWN:
                        case WM_KEYUP:{
                            WPARAM vKeyCode = msg.wParam;
                            bool bWasDown = ((msg.lParam & (1<<30)) != 0);
                            bool bIsDown = ((msg.lParam & (1<<31)) != 0);
                            if(bIsDown != bWasDown){
                                switch(vKeyCode){
                                    case 'W':{
                                        bMessageAlreadyShown = false;
                                    }break;
                                    default:{
                                        TranslateMessage(&msg);
                                        DispatchMessageA(&msg);
                                    }break;
                                }
                            }
                        }
                    }
                }
            }
            MessageBoxA(NULL, (LPCSTR)"Closing Application.", (LPCSTR)"Bye bye!", MB_ICONINFORMATION | MB_OK);
        }
    }
    return ERROR_SUCCESS;
}

1 Ответ

0 голосов
/ 03 июня 2018

Основная проблема с вашим кодом заключается в том, что вы звоните TranslateMessage() и DispatchMessage() только при получении определенных сообщений нажатия клавиш.Вам нужно вызывать их в основном цикле сообщений для ВСЕХ сообщений.И вам следует обрабатывать ВСЕ сообщения в вашем обратном вызове WndProc.

Вы также используете API на основе TCHAR, но неправильно используете типы типов LPCTSTR.Вместо этого вам нужно использовать макрос TEXT() при приведении литералов string / char к TCHAR.

Вместо этого попробуйте что-то вроде этого:

#include <windows.h>

static bool bMessageAlreadyShown = false; 

LRESULT CALLBACK win_MainWNDCallback(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;

        case WM_SYSKEYDOWN:
        case WM_SYSKEYUP:
        case WM_KEYDOWN:
        case WM_KEYUP: {
            WPARAM vKeyCode = wParam;
            bool bWasDown = ((lParam & (1 << 30)) != 0);
            bool bIsDown = ((lParam & (1 << 31)) == 0);
            if (bWasDown != bIsDown) {
                switch (vKeyCode) {
                    case 'W':
                    case VK_ESCAPE:
                        DestroyWindow(wnd);
                        return 0;
                }
            }
            break;
        }

        case WM_ERASEBKGND:
            PatBlt((HDC)wParam, 0, 0, 1240, 720, BLACKNESS);
            return 0;
    }

    return DefWindowProc(wnd, msg, wParam, lParam);;
}

int CALLBACK WinMain(HINSTANCE HInstance, HINSTANCE HPrevInstance, LPSTR LpCmdLine, int NCmdShow) {
    WNDCLASS wndCLass = {};
    wndCLass.style = CS_HREDRAW | CS_VREDRAW;
    wndCLass.lpfnWndProc = win_MainWNDCallback;
    wndCLass.hInstance = HInstance;
    wndCLass.lpszClassName = TEXT("WindowClass");

    if (RegisterClass(&wndCLass)) {
        HWND wnd = CreateWindowEx( 0, wndCLass.lpszClassName, TEXT("FirstTry"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 1240, 720, 0, 0, HInstance, 0);
        if (wnd) {
            MSG msg;
            while (GetMessage(&msg, 0, 0, 0)) {
                if (!bMessageAlreadyShown) {
                    bMessageAlreadyShown = true;
                    MessageBox(NULL, TEXT("Successfully entered loop."), TEXT("Success!"), MB_ICONINFORMATION | MB_OK);
                }
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }

    MessageBox(NULL, TEXT("Closing Application."), TEXT("Bye bye!"), MB_ICONINFORMATION | MB_OK);

    return ERROR_SUCCESS;
}

Обратите внимание, что я удалил вашу переменную bAppIsRunning, так как она стала избыточной после того, как цикл обработки сообщений обработал сообщение WM_QUIT.

Я также убрал обработку ALT-F4 , поскольку ОС обрабатывает это автоматически.Он закрывает окно, вызывая сообщение WM_CLOSE.По умолчанию DefWindowProc() обрабатывает WM_CLOSE, разрушая окно, которое вызывает сообщение WM_DESTROY.

Я также добавил обработку для WM_ERASEBKGND, чтобы нарисовать фон в окне.Рисование извне цикла сообщений является неправильным.Как только окно будет обновлено на экране, все ваши чертежи будут потеряны, поэтому вам придется перерисовывать все в ответ на WM_ERASEBKGND и WM_PAINT.

...