Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C++ Win32 Program, How to modifier the menu's title?

Tags:

c++

I created a popup menu using c++ win32. The source code is:

IDR_POPUP_MENU MENU DISCARDABLE
BEGIN
POPUP "POPUP"
BEGIN
    MENUITEM "Turn On"                          IDM_STATUS
    POPUP "Preferences"         
    BEGIN
        MENUITEM "Turn Autostart Off"                           IDM_AUTOSTART 
        MENUITEM "Turn Lock Screen Off"                         IDM_LOCKSCREEN
    END
    MENUITEM "Exit",                        IDM_EXIT
END
END

Now I want to change the title "Turn LockScreen Off" into "Turn LockScreen On" when I clicked it.

The code in .cpp is:

case IDM_LOCKSCREEN:
{
    if(lockscreen)
    {
        lockscreen = FALSE;
        HMENU hMenu = LoadMenu(NULL, MAKEINTRESOURCE(IDR_POPUP_MENU));
        hMenu = GetSubMenu(hMenu, IDM_LOCKSCREEN);
        ModifyMenu(hMenu, IDM_LOCKSCREEN, MF_BYCOMMAND | MF_CHECKED, IDM_LOCKSCREEN, "Turn LockScreen Off");
    }

    break;
}

But I could not get the hMenu with this method.

The pointer of hMenu is empty. I put a break point there and get (*hMenu).unused:CXX0030:Error: expression cannot be evaluated!

Could somebody explain to me how to do with this error?

like image 953
cindywmiao Avatar asked Nov 10 '22 20:11

cindywmiao


1 Answers

The reason your code fails is because you are replacing hMenu with GetSubMenu. Your menu should have been loaded at the beginning within the WM_CREATE case. The menu you are modifying is the recently loaded menu and it is NOT added to the current window so you aren't seeing any changes.. For ModifyMenu, you NEED to specify the MF_STRING flag to change the title!

If the menu is dynamic and created upon Right-Click, then you don't need to use SetMenu to set the menu and it can be loaded on the fly and changed.. but remember, you do not need GetSubMenu for this because you are using defined ID's for each menu. If the menu is to be retrieved by indexed position starting at 0, GetSubMenu would help.

Also, in the below code, I chose to save the menu handle into a variable. You do not need this static variable. You can also use GetMenu within the case statement that needs a MenuHandle.

Resources.h:

#ifndef RESOURCES_HPP_INCLUDED
#define RESOURCES_H_INCLUDED

#define IDR_POPUP_MENU 1001
#define IDM_STATUS 1002
#define IDM_AUTOSTART 1003
#define IDM_LOCKSCREEN 1004
#define IDM_EXIT 1005

#endif // RESOURCES_H_INCLUDED

Resources.rc:

#include "Resources.h"

IDR_POPUP_MENU MENU DISCARDABLE
BEGIN
POPUP "POPUP"
BEGIN
    MENUITEM "Turn On", IDM_STATUS
    POPUP "Preferences"
    BEGIN
        MENUITEM "Turn Autostart Off", IDM_AUTOSTART
        MENUITEM "Turn Lock Screen Off", IDM_LOCKSCREEN
    END
    MENUITEM "Exit", IDM_EXIT
END
END

main.cpp:

#include <windows.h>
#include "Resources.h"

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static HMENU hMenu = NULL;

    switch(message)
    {
        case WM_CREATE:
        {
            hMenu = LoadMenu(NULL, MAKEINTRESOURCE(IDR_POPUP_MENU));
            SetMenu(hwnd, hMenu);

        }
        break;

        case WM_COMMAND:
        {
            switch(wParam)
            {
                case IDM_LOCKSCREEN:
                {
                    static bool locked = true;

                    if (locked)
                    {
                        //You can use HMENU = GetMenu(hwnd); if you want.. instead of a static variable..
                        ModifyMenu(hMenu, IDM_LOCKSCREEN, MF_BYCOMMAND | MF_STRING, IDM_LOCKSCREEN, "Turn LockScreen On");
                    }
                    else
                    {
                        ModifyMenu(hMenu, IDM_LOCKSCREEN, MF_BYCOMMAND | MF_STRING | MF_CHECKED, IDM_LOCKSCREEN, "Turn LockScreen Off");
                    }

                    locked = !locked;
                }
                break;
            }
        }
        break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    HWND hwnd;
    MSG messages;

    WNDCLASSEX wincl;
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = "CodeBlocksWindowsApp";
    wincl.lpfnWndProc = WindowProcedure;
    wincl.style = CS_DBLCLKS;
    wincl.cbSize = sizeof (WNDCLASSEX);
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;
    wincl.cbClsExtra = 0;
    wincl.cbWndExtra = 0;
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    if (!RegisterClassEx (&wincl))
        return 0;

    hwnd = CreateWindowEx (0, "CodeBlocksWindowsApp", "Code::Blocks Template Windows App", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, NULL, hThisInstance, NULL);
    ShowWindow (hwnd, nCmdShow);

    while (GetMessage (&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }
    return messages.wParam;
}
like image 192
Brandon Avatar answered Nov 15 '22 05:11

Brandon