Проблема с активацией меню окна Win32Api

#c #windows #winapi #win32gui #win32-process

#c #Windows #winapi #win32gui #win32-процесс

Вопрос:

Запуск моей программы выполняется, и из-за того, что у меня есть меню с ВЫХОДОМ, чтобы уничтожить окно, которое оно запускает и немедленно выходит из окна. Не уверен, как исправить мою проблему здесь при компиляции программы, чтобы она не запускала функцию WindowProcedure и не передавала аргумент EXITMENU, в результате чего окно уничтожается.

* .CPP

 #include <windows.h>
#define HELPMENU 1
#define HIGHSCROREMENU 2
#define EXITMENU 3

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int ncmdshow) {
    WNDCLASS wc = { 0 }; // WNDCLASSW is a structure
    LPCWSTR title = L"Window"; // Long Pointer Constant Wide (UTF-16) String 

    wc.hbrBackground = (HBRUSH)COLOR_WINDOW; // Background
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_HAND); // Sets Cursor
    wc.hInstance = hInst; // Instance of window
    wc.lpszClassName = L"windowClass"; // Class name
    wc.lpfnWndProc = WindowProcedure; // Pointer to the function // Controller of window handle

    if (!RegisterClassW(amp;wc)) { // Registers the window class
        return -1;
    }

    //                                                   | binary combination value, posX, posY, Width, Height

    // Creates the window
    CreateWindow(wc.lpszClassName, title, WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_BORDER, 100, 100, 800, 600, NULL, NULL, NULL, NULL);

    MSG msg = { 0 };


    while (GetMessage(amp;msg, NULL, NULL, NULL) > 0) { // Keeps the window running
        TranslateMessage(amp;msg);
        DispatchMessage(amp;msg);
    }

    return 0;
}

/* Event Paths */
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
    switch (msg) {
    case WM_CREATE: // On window creation
        AddControls(hWnd);
        AddMenu(hWnd);
        break;
    case WM_LBUTTONDOWN: // Left Mouse button
        break;
    case WM_DESTROY: // Makes GetMessage Function return false, closing the window
        PostQuitMessage(0);
        return 0;
    case EXITMENU:
        DestroyWindow(hWnd); // This part of the code shouldn't run on creation
        break;
    default:
        return DefWindowProc(hWnd, msg, wp, lp);
    }
}

/* Creates menu */
void AddMenu(HWND hWnd) {
    hMenu = CreateMenu(); // Creates menu object
    // AppendMenu(Menu Instance, Usage Type, Argument, String info);
    AppendMenu(hMenu, MF_STRING, HELPMENU, L"Help - F1");
    AppendMenu(hMenu, MF_STRING, HIGHSCROREMENU, L"Highscores - F2"); // Menu Created
    AppendMenu(hMenu, MF_STRING, EXITMENU, L"Exit - ESC");
    // SetMenu(Window Handle , Menu Instance);
    SetMenu(hWnd, hMenu); // Sets menu for window // 
} 

 

Комментарии:

1. #define EXITMENU 3 Почему? 3 WM_MOVE определяется в winuser.h.

2. EXITMENU не является сообщением. Совпадение с WM_MOVE не является веской причиной для уничтожения окна. Используйте WM_COMMAND для обнаружения команд меню.

3. Спасибо dxiv и @Hans Passant, не понял, что он уже переопределяет определенное значение. Вместо этого я рассмотрю выполнение WM_COMMAND. Все еще пытаюсь понять Win32Api в целом.

Ответ №1:

Вы неправильно обрабатываете команды меню в своем WindowProcedure() .

Вы определили EXITMENU как 3, что соответствует тому же значению, WM_MOVE что и сообщение. Итак, в вашем switch случае вы уничтожаете свое окно, как только оно получает WM_MOVE сообщение во время создания окна.

Вместо этого вам необходимо обрабатывать команды меню через WM_COMMAND сообщение, согласно документации:

О меню: сообщения, используемые с меню

Когда пользователь выбирает командный элемент из меню, система отправляет WM_COMMAND сообщение оконной процедуре. Младшее слово параметра WM_COMMAND сообщения wParam содержит идентификатор выбранного элемента. Оконная процедура должна проверить идентификатор и соответствующим образом обработать сообщение.

Попробуйте это вместо:

 LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
    switch (msg) {
        ...
        case WM_COMMAND:
            switch (wp) {
                case HELPMENU: {
                    ...
                    return 0;
                }
                case HIGHSCROREMENU: {
                    ...
                    return 0;
                }
                case EXITMENU: {
                    DestroyWindow(hWnd);
                    return 0;
                }
            }
            break;
        }
        ...
    }

    return DefWindowProc(hWnd, msg, wp, lp);
}
 

ОБНОВЛЕНИЕ: при этом рассмотрите EXITMENU возможность использования вашего обработчика SendMessage(WM_CLOSE) вместо DestroyWindow() . Если ваше приложение поддерживает данные, которые должны быть сохранены при закрытии приложения пользователем, вы можете добавить WM_CLOSE обработчик для выполнения этого действия независимо от того, как закрывается окно (ваше меню выхода, X кнопка закрытия и Alt-F4т. Д.). DefWindowProc() уничтожает окно при обработке WM_CLOSE .

 LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
    switch (msg) {
        ...
        case WM_CLOSE: {
            if (data has been modified) {
                prompt user to save data...
                if (cancelled) {
                    return 0;
                }
                if (should save) {
                    save data ...
                }
            }
            break;
        }

        case WM_COMMAND:
            switch (wp) {
                ...
                case EXITMENU: {
                    SendMessage(hWnd, WM_CLOSE, 0, 0);
                    return 0;
                }
            }
            break;
        }
        ...
    }

    return DefWindowProc(hWnd, msg, wp, lp);
}
 

Комментарии:

1. Потрясающе, именно то, что я только что сделал, благодаря вам и @Hans Passant.

2. Похожие: Почему редакторы диалоговых окон начинают назначать идентификаторы элементов управления со 100?