0
votes

I made a little app in C++ and I have two pairs of menus; one for the main window, and one for the tray icon I put there. I'm trying to put a checkmark next to a specific menu item in the tray icon context menu, but I can't get this to work.

if (!isCheckmarked)
{
    CheckMenuItem(cSubMenu, IDC_STARTWIN, MF_CHECKED);
    OutputDebugString(_T("Checkmarked!\n"));
    _RPT2(_CRT_WARN, "Menu Handles: %i, %i\n", cMenu, cSubMenu);

    isCheckmarked = TRUE;
}
else
{
    //CheckMenuItem(hMenu, IDC_STARTWIN, MF_UNCHECKED);
    OutputDebugString(_T("Uncheckmarked!\n"));
    //_RPT2(_CRT_WARN, "Menu Handles: %i, %i\n", cMenu, cSubMenu);

    isCheckmarked = FALSE;
}
break;

It works fine, if I use the menu handle of the main window to set a checkmark on one of those items, but I can't get it to work on the tray icon context menu.

void ShowContextMenu(HWND hWnd, POINT pt)
{
    cMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDC_CONTEXT_MENU));
    if (cMenu)
    {
        cSubMenu = GetSubMenu(cMenu, 0);
        if (cSubMenu)
        {
            // our window must be foreground before calling TrackPopupMenu or the menu will not disappear when the user clicks away
            SetForegroundWindow(hWnd);

            // respect menu drop alignment
            UINT uFlags = TPM_RIGHTBUTTON;
            if (GetSystemMetrics(SM_MENUDROPALIGNMENT) != 0)
            {
                uFlags |= TPM_RIGHTALIGN;
            }
            else
            {
                uFlags |= TPM_LEFTALIGN;
            }

            TrackPopupMenuEx(cSubMenu, uFlags, pt.x, pt.y, hWnd, NULL);
        }

        DestroyMenu(cMenu);
    }
1
I am not clear about what is "tray icon" you are talking about. Could you show some snapshots like what you have got and what you expected? - Rita Han
@RitaHan-MSFT My application uses Shell_NotifyIcon() to iconify to the system tray. This iconified icon has a context menu and on one of the menu items, I want to set a check mark. (I'm using the NotificationIcon sample (from the Window 7 SDK samples). I'm having problems with setting the check mark. (doesn't show up). - Kees Spierings
@RitaHan-MSFT Context menu image: link - Kees Spierings
ShowContextMenu never calls CheckMenuItem so it's not surprising that nothing is checked. - Raymond Chen
@KeesSpierings Does the answer work for you? - Rita Han

1 Answers

0
votes

Based on the official NotificationIcon Sample modify ShowContextMenu function as below work for me. You can have a try.

    BOOL mOptionsChecked = FALSE;
    
    void ShowContextMenu(HWND hwnd, POINT pt)
    {
        UINT menuItemId = 0;
    
        HMENU hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDC_CONTEXTMENU));
        if (hMenu)
        {
            HMENU hSubMenu = GetSubMenu(hMenu, 0);
            if (hSubMenu)
            {
                // our window must be foreground before calling TrackPopupMenu or the menu will not disappear when the user clicks away
                SetForegroundWindow(hwnd);
    
                // If the menu item has checked last time set its state to checked before the menu window shows up.
                if (mOptionsChecked)
                {
                    //CheckMenuItem(hSubMenu, IDM_OPTIONS, MF_BYCOMMAND | MF_CHECKED);

                    MENUITEMINFO mi = { 0 };
                    mi.cbSize = sizeof(MENUITEMINFO);
                    mi.fMask = MIIM_STATE;
                    mi.fState = MF_CHECKED;
                    SetMenuItemInfo(hSubMenu, IDM_OPTIONS, FALSE, &mi);
                }
    
                // respect menu drop alignment
                UINT uFlags = TPM_RIGHTBUTTON;
                if (GetSystemMetrics(SM_MENUDROPALIGNMENT) != 0)
                {
                    uFlags |= TPM_RIGHTALIGN;
                }
                else
                {
                    uFlags |= TPM_LEFTALIGN;
                }
    
                // Use TPM_RETURNCMD flag let TrackPopupMenuEx function return the menu item identifier of the user's selection in the return value.
                uFlags |= TPM_RETURNCMD;
                menuItemId = TrackPopupMenuEx(hSubMenu, uFlags, pt.x, pt.y, hwnd, NULL);
    
                // Toggle the menu item state. 
                if (IDM_OPTIONS == menuItemId)
                {
                    if(mOptionsChecked)
                        mOptionsChecked = FALSE;
                    else
                        mOptionsChecked = TRUE;
                }
    
            }
            DestroyMenu(hMenu);
        }
    }

Result:

enter image description here

Tips:

  1. Set menu item state before the menu window shows up.
  2. CheckMenuItem may be altered or unavailable in subsequent versions. Instead, use SetMenuItemInfo.