MFC CMenu strange draw background behavior - c++11

I tried to draw the menu background in MFC Dlg App.
But I found if I declare CMenu subMenu in OnInitDialog(), the background color works well.
If I declare CMenu subMenu in Head file or like CMenu* subMenu=new CMenu; in OnInitDialog(), the Item's background will not be changed.This is weird and seems to be related to the CMenu lifetime.
Variable:
CMenu m_accountMenu;
CMenu subMenu;
CMFCApplication3Dlg::OnInitDialog()
......some code
// TODO: Add extra initialization here
m_accountMenu.CreateMenu();
subMenu.CreatePopupMenu();
m_accountMenu.AppendMenuW(MF_BYPOSITION | MF_POPUP | MF_STRING , (UINT)subMenu.m_hMenu, _T("Sub Info"));
subMenu.AppendMenuW(/*MF_MENUBREAK|*/ MF_STRING | MF_ENABLED , 1001, _T("sub Info1")); // note: MF_MENUBREAK can make it work
subMenu.AppendMenuW(MF_STRING | MF_ENABLED , 1002, _T("sub Info2"));
CBrush cBrush;
cBrush.CreateSolidBrush(RGB(255, 0, 0));
MENUINFO mi = { 0 };
mi.cbSize = sizeof(MENUINFO);
mi.fMask = MIM_BACKGROUND;
mi.hbrBack = cBrush;
SetMenuInfo(m_accountMenu.GetSubMenu(0)->GetSafeHmenu(), &mi);
cBrush.Detach();
SetMenu(&m_accountMenu);
Can someone help me unravel the mystery? Any useful information will be appreciated.

Related

CGEventTapCreate callback is not running

I have some C++ code that looks like this:
CFRunLoopRef ref = CFRunLoopGetCurrent();
CGEventMask mask = CGEventMaskBit(kCGEventLeftMouseDown) |
CGEventMaskBit(kCGEventLeftMouseUp) |
CGEventMaskBit(kCGEventRightMouseDown) |
CGEventMaskBit(kCGEventRightMouseUp) |
CGEventMaskBit(kCGEventMouseMoved) |
CGEventMaskBit(kCGEventLeftMouseDragged) |
CGEventMaskBit(kCGEventRightMouseDragged) |
CGEventMaskBit(kCGEventScrollWheel);
CFMachPortRef tap =
CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap,
kCGEventTapOptionListenOnly, mask, OnMouseEvent, this);
CFRunLoopSourceRef source =
CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0);
CFRunLoopAddSource(ref, source, kCFRunLoopCommonModes);
CGEventTapEnable(tap, true);
CFRunLoopRun();
CGEventTapEnable(tap, false);
CFRunLoopRemoveSource(ref, source, kCFRunLoopCommonModes);
CFRelease(source);
CFRelease(tap);
OnMouseEvent is not being called when I move the mouse around, click, or scroll. Why not?
Make sure the application that's running this code is added to accessibility in security and privacy. In this screenshot, iterm is added, and so running this program from iterm will work.
Here's a github issue that includes code for running sample code you've mentioned, that only works when accessibility is turned on.

WINAPI, remove popup menu from menu

I would like to have dynamic menu in my application. This dynamic menu should contain popupmenus which will be added and removed on the fly. For the first approach I made dynamic menu created with single menu items.
AppendMenu(menu, MF_STRING, item_id, "TEST");
I have created algorithm which generate item_id and store them in array, so I could remove them by
DeleteMenu(menu, id_to_be_deleted, MF_BYCOMMAND);
I do not see any pitfalls of this implementation and I am happy with it. But then stuck with final implementation. I would like my menus would be popup menus.
new_popup_menu = CreatePopupMenu();
AppendMenu(new_popup_menu, MF_STRING, 1, "TEST1");
AppendMenu(new_popup_menu, MF_STRING, 2, "TEST2");
AppendMenu(new_popup_menu, MF_STRING, 3, "TEST3");
AppendMenu(menu, MF_STRING|MF_POPUP,
(UINT_PTR)new_popup_menu, "dynamic menu");
This code works as expected, but I have no idea how to remove "new_popup_menu" from "menu" since the "UINT_PTR uIDNewItem" parameter of AppendMenu now is used as handle to submenu, not ID and cannot be used with DeleteMenu+MF_BYCOMMAND.
Is there any way to remove this submenu item other then DeleteMenu+MF_BYPOSITION?
Is there a way to get menu item position by handle which is returned by CreatePopupMenu())?
I feel implementation algorithm of tracking which menu is on which position is pain in the ass. Since Windows has API to insert the menu after other specific menu, recreating whole menu tree is a waste of CPU time.
If you want to create a menu item that opens a submenu and has an ID then create it with InsertMenuItem(...) rather than AppendMenu(...). InsertMenuItem(...) lets you fill in a struct that specifies all of the properties you want to be set on the menu item you are creating, including ID and submenu. A lot of Win32 works this way: AppendMenu(...) is like a shorthand version for the more verbose version of the same function. When you run into situations in which you can't do something reasonable with a certain Win32 call, look for a synonymous call that takes a *INFO structure.
Code below:
...
HMENU menu_bar = GetMenu(hWnd);
HMENU new_menu = CreateMenu();
AppendMenu(menu_bar, MF_POPUP, (UINT_PTR)new_menu, "foobar");
AppendMenu(new_menu, MF_ENABLED | MF_STRING, 1002, "item1");
AppendMenu(new_menu, MF_ENABLED | MF_STRING, 1003, "item2");
HMENU dynamic_popup = CreatePopupMenu();
AppendMenu(dynamic_popup, MF_ENABLED | MF_STRING, 1004, "mumble");
AppendMenu(dynamic_popup, MF_ENABLED | MF_STRING, 1005, "quux");
// Below will add an item named "dynamic menu" to the end of new_menu
// that has an ID of 1006.
MENUITEMINFO mii = { 0 };
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_SUBMENU | MIIM_STRING | MIIM_ID;
mii.dwTypeData = (LPSTR)"dynamic menu";
mii.hSubMenu = dynamic_popup;
mii.wID = 1006;
InsertMenuItem(new_menu, 0, FALSE, &mii);
//DeleteMenu(new_menu, 1006, MF_BYCOMMAND);
...

how to prevent drop-down menu disappearing after adding transparant layer

I have built an application that adds on-screen application help in context of an windows desktop application. When the object of help relates to a drop-down menu I am encountering problems that the drop-down menu disappears when adding a transparant overlay. What attributes should I use to keep the drop-down menu visible? Please see the following code where I define the window to draw on top of the current foreground window:
exStyle = win32con.WS_EX_COMPOSITED | win32con.WS_EX_LAYERED | win32con.WS_EX_NOACTIVATE | win32con.WS_EX_TOPMOST | win32con.WS_EX_TRANSPARENT
style = win32con.WS_DISABLED | win32con.WS_POPUP | win32con.WS_VISIBLE
oWindow = win32gui.CreateWindowEx(
exStyle,
owndClassAtom,
'Per52Overlay', # WindowName
style,
winX1, # x
winY1, # y
#win32api.GetSystemMetrics(win32con.SM_CXSCREEN), # width
#win32api.GetSystemMetrics(win32con.SM_CYSCREEN), # height
winWidth, #width
winHeight, #height
hwnd, # hWndParent
None, # hMenu
hInstance,
None # lpParam
)
oWindowHndl = oWindow
# //msdn.microsoft.com/en-us/library/windows/desktop/ms633540(v=vs.85).aspx
win32gui.SetLayeredWindowAttributes(oWindow, 0x00ffffff, 255, win32con.LWA_COLORKEY | win32con.LWA_ALPHA)
hdc, paintStruct = win32gui.BeginPaint(oWindow)
hPen = win32gui.CreatePen(win32con.PS_SOLID,3, win32api.RGB(0,255,0))
win32gui.SelectObject(hdc, hPen)
win32gui.Rectangle(hdc, objX1, objY1, objX2, objY2)
win32gui.EndPaint(oWindow, paintStruct)
win32gui.SetWindowPos(oWindow, win32con.HWND_TOPMOST, winX1, winY1, winWidth, winHeight, win32con.SWP_DRAWFRAME | win32con.SWP_NOACTIVATE | win32con.SWP_NOSIZE | win32con.SWP_SHOWWINDOW)
win32gui.ShowWindow(oWindow, win32con.SW_SHOW)
win32gui.UpdateWindow(oWindow)
At some stage the window shall be drawn:
winCrd = win32gui.GetWindowRect(activeWindow)
objCrd = (startX, startY, endX, endY)
drawOnApp(activeWindow, winCrd, objCrd, message)
win32gui.BringWindowToTop(activeWindow)
My guess is that I am doing something wrong with the attributes in combination with what window should be on top / activated / to foreground etc. etc.
Can you give me some clues to dive more in this matter?

CMFCPopupMenu menu displayed without contents

I'm using the CMFCPopupMenu to create a right click popup menu. The problem is that the first time the menu is shown only the menu frame with shades is shown but the contents is white. The second time the menu is shown there are no problems. The code looks like this:
CPoint point;
::GetCursorPos (&point);
CMFCPopupMenu* pop = new CMFCPopupMenu();
pop->InsertItem(CMFCToolBarMenuButton(ID_COMMAND_1,NULL,-1,_T("Command 1")));
pop->InsertItem(CMFCToolBarMenuButton(ID_COMMAND_2,NULL,-1,_T("Command 2")));
pop->InsertItem(CMFCToolBarMenuButton(ID_COMMAND_3,NULL,-1,_T("Command 3")));
pop->InsertItem(CMFCToolBarMenuButton(ID_COMMAND_4,NULL,-1,_T("Command 4")));
pop->Create(this,point.x,point.y,NULL,0,true);
The parent class is based on CDialogEx.
Thanks.
I don't understand why my approach doesn't work but I found a way around it by defining the menu in the ressource and do like this:
CMenu menu;
menu.LoadMenu(IDR_SESSION_MENU);
HMENU hMenu = menu.GetSubMenu (0)->Detach ();
CMFCPopupMenu* pMenu = theApp.GetContextMenuManager()->ShowPopupMenu(hMenu, point.x, point.y, this, TRUE);
That Works and the only problem is that it's a bit more complicated to have a menu with dynamic entries depending on state and selection.
CMFCPopupMenu* pPopupMenu = new CMFCPopupMenu;
if (pPopupMenu->Create(pWndOwner, point.x, point.y, NULL, FALSE, TRUE))
{
pPopupMenu->InsertItem(CMFCToolBarMenuButton(57645, NULL, -1, _T("Command 1")), -1);
pPopupMenu->InsertItem(CMFCToolBarMenuButton(57646, NULL, -1, _T("Command 2")), -1);
pPopupMenu->RecalcLayout();
}
Need call RecalcLayout() after insert

how to enable popup-menu to communicate with WM_MENUCOMMAND instead of WM_COMMAND?

What I read is that the menu must have its MenuInfo.dwStyle flag set to MNS_NOTIFYBYPOS, what I did is:
MENUINFO MenuInfo;
memset(&MenuInfo,0, sizeof(MenuInfo));
MenuInfo.cbSize = sizeof(MenuInfo);
HMENU hPopupMenu = CreatePopupMenu();
GetMenuInfo(hPopupMenu, &MenuInfo);
MenuInfo.dwStyle |= MNS_NOTIFYBYPOS;
SetMenuInfo(hPopupMenu, &MenuInfo);
And next proceed with adding items:
InsertMenu(hPopupMenu, pos, MF_BYPOSITION, id , "do command");
Next track it:
TrackPopupMenu(hPopupMenu, TPM_CENTERALIGN | TPM_RETURNCMD, cursorPos.x, cursorPos.y, 0, hwnd, NULL);
But it has no effect, it compiles without error but the clicking event is till send as WM_COMMAND
You need to set the fMask member of the MENUINFO structure to tell the system which fields you want to set/get.
E.g.
MenuInfo.fMask = MIM_STYLE;
GetMenuInfo(hPopupMenu, &MenuInfo);
MenuInfo.dwStyle |= MNS_NOTIFYBYPOS;
SetMenuInfo(hPopupMenu, &MenuInfo);
Also note that the docs say:
MNS_NOTIFYBYPOS is a menu header style and has no effect when applied
to individual sub menus.
So it is possible that it won't work for you anyway with a popup menu.

Resources