How to prevent overlap of my context menu with the system menu in the Windows notification area? - c++

I've seen a lot of "unofficial" workarounds to bypass this visual bug, but none of them seem to work correctly for me. Let me explain.
Say, I display my own system tray icon in the Windows notification area (by the clock.)
My program also supports displaying a context menu when a user right-clicks my tray icon. I implement it by trapping the WM_RBUTTONDOWN notification from the message handler specified in the uCallbackMessage parameter of the NOTIFYICONDATA. I then processing it as such:
//Show menu (ask to return results here)
int nRes = TrackPopupMenu(hMenu, TPM_RIGHTALIGN | TPM_TOPALIGN |
TPM_LEFTBUTTON | TPM_VERPOSANIMATION | TPM_HORNEGANIMATION | TPM_RETURNCMD,
pnt.x, pnt.y, 0, this->GetSafeHwnd(), NULL);
Unfortunately the code above, all by itself, does not allow the menu to be dismissed after a left-click somewhere outside of it.
To resolve this, the solution I found was this:
//Need this to bypass a glitch in Windows to remove popup menu from
//System Tray after mouse click outside of it
::SetForegroundWindow(this->GetSafeHwnd());
//Show menu (ask to return results here)
int nRes = TrackPopupMenu(hMenu, TPM_RIGHTALIGN | TPM_TOPALIGN |
TPM_LEFTBUTTON | TPM_VERPOSANIMATION | TPM_HORNEGANIMATION | TPM_RETURNCMD,
pnt.x, pnt.y, 0, this->GetSafeHwnd(), NULL);
PostMessage(WM_NULL, 0, 0);
But the "fix" above introduces an occasional additional bug.
For instance, here's a screenshot from Windows 8. Sometimes, I think it depends on what window had focus prior to this, when I right-click on my tray icon my context menu is displayed on top of the Windows default context menu, that looks like this:
Is there any way to resolve this visual bug of overlapping context menus?

Related

Shell_NotifyIcon: Tray icon show both - popup menu and taskbar menu [duplicate]

I create a notification icon with:
notifyIcon.cbSize = sizeof(NOTIFYICONDATA);
notifyIcon.hWnd = mainWnd;
notifyIcon.uID = 100;
notifyIcon.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
notifyIcon.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_LOGO));
notifyIcon.dwState = NIS_SHAREDICON;
notifyIcon.uVersion = NOTIFYICON_VERSION;
notifyIcon.uTimeout = 15000;
notifyIcon.uCallbackMessage = APP_MSG_TRAY;
wcscpy_s(notifyIcon.szTip, 127, WTXT_APP_TRAY_TOOLTIP);
Shell_NotifyIcon(NIM_ADD, &notifyIcon);
Shell_NotifyIcon(NIM_SETVERSION, &notifyIcon);
And have a context menu popup on WM_RBUTTONDOWN and WM_CONTEXTMENU like this:
MENUITEMINFO separatorBtn = {0};
separatorBtn.cbSize = sizeof(MENUITEMINFO);
separatorBtn.fMask = MIIM_FTYPE;
separatorBtn.fType = MFT_SEPARATOR;
HMENU hMenu = CreatePopupMenu();
if(hMenu) {
InsertMenu(hMenu, -1, MF_BYPOSITION, APP_OPEN_OPTIONS, WTXT_OPTIONS);
InsertMenuItem(hMenu, -1, FALSE, &separatorBtn);
InsertMenu(hMenu, -1, MF_BYPOSITION, APP_MSG_EXIT, WTXT_EXIT);
POINT pt;
GetCursorPos(&pt);
SetForegroundWindow(mainWnd);
TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, mainWnd, NULL);
PostMessage(mainWnd, WM_NULL, 0, 0);
DestroyMenu(hMenu);
}
It works fine, but the context menu doesn't disappear always. Sometimes (often) if you have ie. winamp and my app icons in system tray, if you right click my app and winamp afterwards, bot menus will appear, and my menu won't disappear automatically until you click an item.
Any ideas?
thanks...
To display a context menu for a notification icon, the current window must be the foreground window before the application calls TrackPopupMenu or TrackPopupMenuEx. Otherwise, the menu will not disappear when the user clicks outside of the menu or the window that created the menu (if it is visible).
SetForegroundWindow(hDlg);
TrackPopupMenu( hSubMenu,
TPM_RIGHTBUTTON,
pt.x,
pt.y,
0,
hDlg,
NULL);
Do not catch WM_RBUTTONDOWN but WM_RBUTTONUP. And of course do not handle both WM_RBUTTONUP and WM_CONTEXTMENU, since they will both get handled and you'd show the context menu twice for every right-click.
Showing the menu twice would have the effect you describe: the menu shows up, but doesn't seem to disappear (because it shows up again right away a second time).
There are apps to try to hack around the restrictions of the notification area (tray) API. They'll hook the Explorer window and listen for Windows messages. That lets them do stuff that isn't otherwise possible but it inevitably destabilizes other apps. Getting two context menus is a sure sign of this kind of trouble.
You've got a good lead on what kind of program may do this, it's got an icon. Kill them one by one until you find the evil-doer. Not much you can do about it probably, other than not running it or complaining to the vendor.
You seem to already have both of the documented bugfixes (SetForegroundWindow & WM_NULL) I'd say anything beyond this is a bug in windows.
If you really want to do hacky things, you could probably get the menu window handle in WM_INITMENU* (And I don't mean the HMENU, but the HWND for the menu) and hide that window.

Visual C++ open Dialog Box when button clicked

So I am new to programming in C++ and new to using Visual Studio 2010. Basically I have a FLIR thermal camera; and I need to edit a GUI provided in an eBUS SDK that suits my needs.
What I want to do is open a new dialog box when I click the settings button. I am just not sure what code to use in the button handler to make the dialog box open. I have put different code in the button handler to test it and the settings button works fine.
This is the button handler that the code needs to go into.
void PvSimpleUISampleDlg::OnBnClickedSettings()
{
}
This is the dialog box in the resource file that I want to connect the button to. It is called IDD_SETTINGS. The actual button is called IDB_SETTINGS, not sure if that's relevant.
IDD_SETTINGS DIALOGEX 0, 0, 506, 300
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,449,279,50,14
END
I am not sure what other code to add, but I am completely new so any help/advice you can give no matter how small would be greatly appreciated.
If you are using the MFC framework (the CDialog class), then you can create a new CDialog object using the settings-dialog resource you've created.
The CDialog::DoModal() function is what you want, if you want a simple popup box that grabs your attention until it is dismissed with OK or Cancel.
In your source file:
void PvSimpleUISampleDlg::OnBnClickedSettings()
{
CDialog mySettings( IDD_SETTINGS );
INT_PTR returnCode = -1;
returnCode = mySettings.DoModal();
switch( returnCode ) {
case IDOK :
//gather your input fields here
break;
case IDCANCEL :
//do something
break;
case -1:
default:
//error creating box
}
}
Here is a link for using the CDialog class as a starting point for extracting information from the box once OK is clicked:
https://msdn.microsoft.com/en-us/library/619z63f5.aspx

How to show CDockablePane after it has been closed

I understand CDockablePanes remember their state when the program is closed and then opened again, but I don't understand how I'm supposed to show a CDockablePane that has been closed in a previous use.
This is my initialisation code :
DWORD dwPaneStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_FLOAT_MULTI;
MyPane.Create(_T("MyPane"), this, CRect(0, 0, 0, 120), TRUE, ID_VIEW_MYPANE, dwPaneStyle | CBRS_BOTTOM));
MyPane.ShowPane(TRUE, FALSE, TRUE);
So this would create my pane and then set it to be shown, but for some reason I can't see it in my main frame... What am I missing?
Also, I would like to be able to show the pane when a certain button is pushed. I already have my MessageMap and OnButtonFct() ready. I just need to know how to show the pane.
Thanks!
I found it... it seems MFC saves the entire state of how the program was left in. So when the app is launched, the panel is shown, but then the app loads the last state and hides the panel. I was able to make it visible again by using the same line :
MyPane.ShowPane(TRUE, FALSE, TRUE);
on a button push event instead of during the creation.
There seems to also be a way to disable the automatic "Load last state" behaviour by adding the following in the CWinAppEx constructor.
m_bSaveState = FALSE;

How to run command radiobutton inside a container in a window?

How to run command radiobutton inside a container in a window?
I was looking for weeks on the internet but I do not think I conosco forums can help me with a library as sophisticated as windows.h. So I come to this forum for professional help.
I know how to create a radiobutton within the main program window. I also know how to create a radiobutton inside a container of radiobuttons, but I want to run the radiobutton command that is contained within the container.
It turns out that my program requires that when a radiobutton is selected style WM_GRAYED put an EDIT control.
The problem is not how to execute commands from a control contained in a container of controls within a main window.
My code:
hOptEnc = CreateWindowEx (
            0,
            "BUTTON",
            "Type input",
            WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
            264,
            296
            100,
            64,
            hWndParent,
            (HMENU) CM_GROUPS,
            hInstance,
            NULL
            );
hRadioAssci = CreateWindowEx (
            0,
            "BUTTON",
            "Input Assci"
            WS_VISIBLE | WS_CHILDWINDOW | BS_AUTORADIOBUTTON,
            10
            17
            75,
            20
            hOptEnc,
            (HMENU) CM_RADIOASSI,
            hInstance,
            NULL
            );
hRadioHex = CreateWindowEx (
            0,
            "BUTTON",
            "Hex Input"
            WS_VISIBLE | WS_CHILDWINDOW | BS_AUTORADIOBUTTON,
            10
            37,
            75,
            20
            hOptEnc,
            (HMENU) CM_RADIOHEX,
            hInstance,
            NULL
            );
And each time the user dials an option as hex input, edit controls would change the coding. So I need the radiobutton run your command in the main window procedure function.
The container (the group box) has no effect on the radio button. It is for visual clarity only. Pass you main window to the radio buttons as their parent window.

System tray context menu doesn't disappear

I create a notification icon with:
notifyIcon.cbSize = sizeof(NOTIFYICONDATA);
notifyIcon.hWnd = mainWnd;
notifyIcon.uID = 100;
notifyIcon.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
notifyIcon.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_LOGO));
notifyIcon.dwState = NIS_SHAREDICON;
notifyIcon.uVersion = NOTIFYICON_VERSION;
notifyIcon.uTimeout = 15000;
notifyIcon.uCallbackMessage = APP_MSG_TRAY;
wcscpy_s(notifyIcon.szTip, 127, WTXT_APP_TRAY_TOOLTIP);
Shell_NotifyIcon(NIM_ADD, &notifyIcon);
Shell_NotifyIcon(NIM_SETVERSION, &notifyIcon);
And have a context menu popup on WM_RBUTTONDOWN and WM_CONTEXTMENU like this:
MENUITEMINFO separatorBtn = {0};
separatorBtn.cbSize = sizeof(MENUITEMINFO);
separatorBtn.fMask = MIIM_FTYPE;
separatorBtn.fType = MFT_SEPARATOR;
HMENU hMenu = CreatePopupMenu();
if(hMenu) {
InsertMenu(hMenu, -1, MF_BYPOSITION, APP_OPEN_OPTIONS, WTXT_OPTIONS);
InsertMenuItem(hMenu, -1, FALSE, &separatorBtn);
InsertMenu(hMenu, -1, MF_BYPOSITION, APP_MSG_EXIT, WTXT_EXIT);
POINT pt;
GetCursorPos(&pt);
SetForegroundWindow(mainWnd);
TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, mainWnd, NULL);
PostMessage(mainWnd, WM_NULL, 0, 0);
DestroyMenu(hMenu);
}
It works fine, but the context menu doesn't disappear always. Sometimes (often) if you have ie. winamp and my app icons in system tray, if you right click my app and winamp afterwards, bot menus will appear, and my menu won't disappear automatically until you click an item.
Any ideas?
thanks...
To display a context menu for a notification icon, the current window must be the foreground window before the application calls TrackPopupMenu or TrackPopupMenuEx. Otherwise, the menu will not disappear when the user clicks outside of the menu or the window that created the menu (if it is visible).
SetForegroundWindow(hDlg);
TrackPopupMenu( hSubMenu,
TPM_RIGHTBUTTON,
pt.x,
pt.y,
0,
hDlg,
NULL);
Do not catch WM_RBUTTONDOWN but WM_RBUTTONUP. And of course do not handle both WM_RBUTTONUP and WM_CONTEXTMENU, since they will both get handled and you'd show the context menu twice for every right-click.
Showing the menu twice would have the effect you describe: the menu shows up, but doesn't seem to disappear (because it shows up again right away a second time).
There are apps to try to hack around the restrictions of the notification area (tray) API. They'll hook the Explorer window and listen for Windows messages. That lets them do stuff that isn't otherwise possible but it inevitably destabilizes other apps. Getting two context menus is a sure sign of this kind of trouble.
You've got a good lead on what kind of program may do this, it's got an icon. Kill them one by one until you find the evil-doer. Not much you can do about it probably, other than not running it or complaining to the vendor.
You seem to already have both of the documented bugfixes (SetForegroundWindow & WM_NULL) I'd say anything beyond this is a bug in windows.
If you really want to do hacky things, you could probably get the menu window handle in WM_INITMENU* (And I don't mean the HMENU, but the HWND for the menu) and hide that window.