C++ 通知图标接收WM_lbuttondblck,但不接收WM_CONTEXTMENU
我在基于对话框的应用程序中添加了一个通知图标,当双击图标时,它会收到WM_lbuttondblck,但当右键单击图标或用键盘突出显示图标并按下上下文菜单键时,它不会收到WM_CONTEXTMENU。我基于Windows7.1SDK示例中的示例使用通知图标。所以,我不知道我哪里出了问题,也不知道为什么这不起作用 注意:如果我将WM_CONTEXTMENU更改为WM_RBUTTONUP,它将接收事件,但光标坐标是错误的C++ 通知图标接收WM_lbuttondblck,但不接收WM_CONTEXTMENU,c++,visual-c++-2010,winapi,C++,Visual C++ 2010,Winapi,我在基于对话框的应用程序中添加了一个通知图标,当双击图标时,它会收到WM_lbuttondblck,但当右键单击图标或用键盘突出显示图标并按下上下文菜单键时,它不会收到WM_CONTEXTMENU。我基于Windows7.1SDK示例中的示例使用通知图标。所以,我不知道我哪里出了问题,也不知道为什么这不起作用 注意:如果我将WM_CONTEXTMENU更改为WM_RBUTTONUP,它将接收事件,但光标坐标是错误的 /***************************************
/******************************************************************************/
/* Menu Resource */
/******************************************************************************/
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDR_TRAYMENU MENU
{
POPUP ""
{
MENUITEM "&Show Status Window", IDM__SHOW_STATUS_WINDOW
MENUITEM "&About", IDM__ABOUT
MENUITEM SEPARATOR
MENUITEM "&Exit", IDM__EXIT
}
}
/******************************************************************************/
/* WinMain() */
/******************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
// ... code unrelated to icon
// Enable Visual Styles
InitCommonControls();
// create the main dialog
if( NULL == (hWnd=CreateDialog(hInstance,MAKEINTRESOURCE(IDD_MAINDLG),NULL,(DLGPROC)WndProc)) )
{
MessageBox( NULL, "Error creating the main dialog!", NULL, MB_OK | MB_ICONERROR );
return -1;
}
// ... code unrelated to icon
MSG msg;
while( GetMessage(&msg,NULL,0,0) && IsWindow(hWnd) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
/******************************************************************************/
/* WndProc() */
/******************************************************************************/
BOOL CALLBACK WndProc(HWND hWndDlg, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_INITDIALOG:
{
// ... code unrelated to icon
hIcon = (HICON)LoadImage( GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_DDCMP), IMAGE_ICON, 16, 16, LR_DEFAULTSIZE );
// Setup the system tray icon
memset( &nid, 0, sizeof(NOTIFYICONDATA) );
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWndDlg;
nid.uID = 0xDDC;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_SHOWTIP;
nid.uCallbackMessage = WM_APP + 0xDDC;
nid.hIcon = hIcon;
strcpy( nid.szTip, "DDCMP Driver" );
Shell_NotifyIcon( NIM_ADD, &nid );
// ... code unrelated to icon
return true;
} break;
case WM_APP + 0xDDC:
{
switch( LOWORD(lParam) )
{
case WM_CONTEXTMENU:
{
MessageBox( hWndDlg, "This message box never shows up.", NULL, MB_OK | MB_SYSTEMMODAL );
HMENU hMenu = LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_TRAYMENU));
if( hMenu )
{
HMENU hSubMenu = GetSubMenu(hMenu,0);
if( hSubMenu )
{
SetForegroundWindow( hWndDlg );
POINT pt = { LOWORD(wParam), HIWORD(wParam) };
UINT uFlags = TPM_RIGHTBUTTON;
if( 0 != GetSystemMetrics(SM_MENUDROPALIGNMENT) )
uFlags |= TPM_RIGHTALIGN;
else
uFlags |= TPM_LEFTALIGN;
TrackPopupMenuEx( hSubMenu, uFlags, pt.x, pt.y, hWndDlg, NULL );
}
DestroyMenu( hMenu );
}
} break;
case WM_LBUTTONDBLCLK:
if( IsWindowVisible(hWndDlg) )
ShowWindow( hWnd, SW_HIDE );
else
ShowWindow( hWnd, SW_SHOW );
break;
}
return true;
} break;
case WM_CLOSE:
ShowWindow( hWndDlg, SW_HIDE );
break;
case WM_DESTROY:
case WM_QUIT:
{
Shell_NotifyIcon( NIM_DELETE, &nid );
// ... code unrelated to icon
return true;
} break;
}
return false;
}
这是Windows7.1SDK示例中的WndProc
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND s_hwndFlyout = NULL;
static BOOL s_fCanShowFlyout = TRUE;
switch (message)
{
case WM_CREATE:
// add the notification icon
if (!AddNotificationIcon(hwnd))
{
MessageBox(hwnd,
L"Please read the ReadMe.txt file for troubleshooting",
L"Error adding icon", MB_OK);
return -1;
}
break;
case WM_COMMAND:
{
int const wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_LOWINK:
ShowLowInkBalloon();
break;
case IDM_NOINK:
ShowNoInkBalloon();
break;
case IDM_PRINTJOB:
ShowPrintJobBalloon();
break;
case IDM_OPTIONS:
// placeholder for an options dialog
MessageBox(hwnd, L"Display the options dialog here.", L"Options", MB_OK);
break;
case IDM_EXIT:
DestroyWindow(hwnd);
break;
case IDM_FLYOUT:
s_hwndFlyout = ShowFlyout(hwnd);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
break;
case WMAPP_NOTIFYCALLBACK:
switch (LOWORD(lParam))
{
case NIN_SELECT:
// for NOTIFYICON_VERSION_4 clients, NIN_SELECT is prerable to listening to mouse clicks and key presses
// directly.
if (IsWindowVisible(s_hwndFlyout))
{
HideFlyout(hwnd, s_hwndFlyout);
s_hwndFlyout = NULL;
s_fCanShowFlyout = FALSE;
}
else if (s_fCanShowFlyout)
{
s_hwndFlyout = ShowFlyout(hwnd);
}
break;
case NIN_BALLOONTIMEOUT:
RestoreTooltip();
break;
case NIN_BALLOONUSERCLICK:
RestoreTooltip();
// placeholder for the user clicking on the balloon.
MessageBox(hwnd, L"The user clicked on the balloon.", L"User click", MB_OK);
break;
//
//
// As you can very plainly see, the Windows SDK Sample ONLY used WM_CONTEXTMNEU
//
//
case WM_CONTEXTMENU:
{
POINT const pt = { LOWORD(wParam), HIWORD(wParam) };
ShowContextMenu(hwnd, pt);
}
break;
}
break;
case WMAPP_HIDEFLYOUT:
HideFlyout(hwnd, s_hwndFlyout);
s_hwndFlyout = NULL;
s_fCanShowFlyout = FALSE;
break;
case WM_TIMER:
if (wParam == HIDEFLYOUT_TIMER_ID)
{
// please see the comment in HideFlyout() for an explanation of this code.
KillTimer(hwnd, HIDEFLYOUT_TIMER_ID);
s_fCanShowFlyout = TRUE;
}
break;
case WM_DESTROY:
DeleteNotificationIcon();
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
我认为您应该尝试将
notifyicontada
结构的uVersion
成员更改为NOTIFYICON\u VERSION\u 4
,该成员值表示在传递给回调函数时,uCallbackMessage
参数将如何解释
您还可以查看以下内容:
我做了一些研究,以下内容应该对您有用:
memset( &nid, 0, sizeof(NOTIFYICONDATA) );
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWndDlg;
nid.uID = 0xDDC;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_SHOWTIP;
nid.uCallbackMessage = WM_APP + 0xDDC;
nid.hIcon = hIcon;
nid.uVersion = NOTIFYICON_VERSION_4;
strcpy( nid.szTip, "DDCMP Driver" );
Shell_NotifyIcon( NIM_ADD, &nid );
Shell_NotifyIcon(NIM_SETVERSION, &nid);
NIM_设置版本(MSDN):
仅限Shell32.dll版本5.0及更高版本。指示通知
根据中指定的版本号进行操作的区域
lpdata指向的结构的uVersion成员。版本
数字指定识别哪些成员
通知图标多年来已经改变了行为。出于与现有代码兼容的原因,您必须选择使用新的行为。如果您不选择加入,则不会收到发送的
WM\u CONTEXTMENU
消息。相反,您必须响应WM\u RBUTTONUP
。即使您从键盘调用上下文菜单,系统仍会发送WM_RBUTTONUP
。您必须通过调用GetCursorPos
来获取光标位置,以便知道在何处显示菜单
通过在NIM\u ADD
调用后调用Shell\u NotifyIcon
传递NIM\u SETVERSION
,您可以选择加入中所述的新行为(和WM\u CONTEXTMENU
)。您正在查看的SDK示例可能在某个地方实现了这一点。我猜这就是您的代码中缺少的内容
文档的关键摘录在备注部分:
从Windows 2000(Shell32.dll版本5.0)起,Shell\u NotifyIcon鼠标和键盘事件的处理方式与Microsoft Windows NT 4.0、Windows 95和Windows 98上的早期Shell版本不同。这些差异包括:
- 如果用户使用键盘选择notify图标的快捷菜单,Shell现在会向相关应用程序发送WM_CONTEXTMENU消息。早期版本发送WM_RBUTTONDOWN和WM_RBUTTONUP消息
- 如果用户使用键盘选择通知图标,并使用空格键或ENTER键激活该图标,则5.0版Shell会向相关应用程序发送NIN_KEYSELECT通知。早期版本发送WM_RBUTTONDOWN和WM_RBUTTONUP消息
- 如果用户用鼠标选择notify图标并用ENTER键激活它,Shell现在会向关联的应用程序发送NIN_SELECT通知。早期版本发送WM_RBUTTONDOWN和WM_RBUTTONUP消息
@汉帕桑。是的,它有一个舱单<代码>@Hans我不认为通用控件清单对shell和
ShellNotify_图标
有任何影响。是吗?@David-你说得对,看起来是notifyiconda.uVersion做的。如果他使用NOTIFYICON\u VERSION\u 4
,就像我在帖子中说的。的确如此。NIM_SETVERSION是缺少的。代码项目代码也没有它。我猜它依赖于switch语句fall-through,是WM\u RBUTTONDOWN
完成了这项工作;Shell_NotifyIcon(NIM_SETVERSION和nid)在我调用NIM_ADD
之后,code>直接添加,但这并没有解决问题。事实上,它还破坏了WM_lbuttondblck
,这在评论中很难做到,而且没有完整的代码。但由于您的原始代码根本没有设置版本,因此它根本不会接收WM_CONTEXTMENU。这就是系统的工作原理。通过监听WM\u RBUTTONUP
,通知在该模式下操作的图标处理上下文菜单。当您使用键盘调用上下文菜单时,系统甚至会发送这些信息。尝试并查看(当您删除NIM\u SETVERSION
code时)。我同意我最初的回答没有提到NIM_SETVERSION,这很糟糕。我现在已经纠正了这一点。我感谢你们在这方面的持续帮助,我取消了投票,并为你们两人投了赞成票。我使用GetCursorPos()
和WM\u RBUTTONUP
使其工作。然而,我仍然不明白为什么将其设置为版本4不起作用。我真的很想让它这样工作,因为后来我打算使用气球提示。我不相信你提供的古代码项目链接是非常有用的。它不使用NIM_SETVERSION
,它处理WM_RBUTTONDOWN
,我打赌这就是实际的工作。似乎仍然中断了通知图标的所有消息。好吧,显然我的眼睛无法分辨NOTIFYICON_VERSION
和NOTIFYICON_VERSION_4
之间的区别。在我修复了WM_CONTEXTMENU的预期效果之后。关于堆栈交换,我最讨厌的一点是,您似乎无法接受多个答案。你的两个答案都有效!我应该能够接受他们两个,给你们两个代表点。现在,我将把公认的答案留给@DavidHeffernan,因为我现在知道WM_CONTEXTMENU在所有平台上都不完全可靠。不过,我浏览了你的所有评论,并对其投了赞成票!对我来说,这很有趣(=)这两个NOTIFY_VERSION
和NOTIFY_VERSION_4
都有效?@KristerAndersson:NOTIFYICON\u VERSION