c++windowswinapiwin32guiwin32-process

Win32Api Window Menu Activating issue


Running my program it runs and due to me having a menu with EXIT to Destroy the window it runs and immediately exits the window. Unsure how to fix my issue here on compiling the program to have it not run the WindowProcedure function and passing the argument EXITMENU resulting in the Window being destroyed.

*.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(&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(&msg, NULL, NULL, NULL) > 0) { // Keeps the window running
        TranslateMessage(&msg);
        DispatchMessage(&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 // 
} 


Solution

  • You are not handling the menu commands correctly in your WindowProcedure().

    You have defined EXITMENU as 3, which is the same value as the WM_MOVE message. So, in your switch, you are destroying your window as soon as it receives a WM_MOVE message during window creation.

    You need to instead handle the menu commands via the WM_COMMAND message, per the documentation:

    About Menus: Messages Used With Menus

    When the user chooses a command item from a menu, the system sends a WM_COMMAND message to the window procedure. The low-order word of the WM_COMMAND message's wParam parameter contains the identifier of the chosen item. The window procedure should examine the identifier and process the message accordingly.

    Try this instead:

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

    UPDATE: That being said, consider having your EXITMENU handler use SendMessage(WM_CLOSE) instead of DestroyWindow(). If your app maintains data that should be saved when the app is closed by the user, you can add a WM_CLOSE handler to perform that action regardless of how the window is being closed (your exit menu, X close button, Alt-F4, etc). DefWindowProc() destroys a window when processing 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);
    }