[英]NOTIFY ICON Click Win32 Api in c++
我有这段代码可以在任务栏中设置一个图标,但是当有人右/左单击它时我不能。 有没有办法做到这一点?
//Notification
NOTIFYICONDATA nid = {};
nid.hWnd = hwnd;
nid.cbSize = sizeof(nid);
nid.uFlags = NIF_ICON | NIF_TIP | NIF_GUID;
// Note: This is an example GUID only and should not be used.
// Normally, you should use a GUID-generating tool to provide the value to
// assign to guidItem.
HICON hIcon = static_cast<HICON>(LoadImage(NULL,
TEXT("gui\\sample.ico"),
IMAGE_ICON,
0, 0,
LR_DEFAULTCOLOR | LR_SHARED | LR_DEFAULTSIZE | LR_LOADFROMFILE));
static const GUID myGUID =
{ 0x23977b55, 0x10e0, 0x4041,{ 0xb8, 0x62, 0xb1, 0x95, 0x41, 0x96, 0x36, 0x68 } };
nid.guidItem = myGUID;
nid.hIcon = hIcon;
// This text will be shown as the icon's tooltip.
StringCchCopy(nid.szTip, ARRAYSIZE(nid.szTip), title);
SendMessage(nid.hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
SendMessage(nid.hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
//TaskBar
// Show the notification.
Shell_NotifyIcon(NIM_ADD, &nid) ? S_OK : E_FAIL;
有人可以帮我吗? 谢谢
您要求的内容包含在 MSDN 的Shell_NotifyIcon()
文档中:
NIF_MESSAGE (0x00000001)
uCallbackMessage
成员有效
u回调消息
类型:UINT应用程序定义的消息标识符。 系统使用此标识符向
hWnd
中标识的 window 发送通知消息。 当图标的边界矩形中发生鼠标事件或 hover 时,当使用键盘选择或激活图标时,或者当气球通知中发生这些操作时,将发送这些通知消息。当
uVersion
成员为 0 或 NOTIFYICON_VERSION 时,消息的wParam
参数包含事件发生的任务栏图标的标识符。 这个标识符的长度可以是 32 位。lParam
参数保存与事件关联的鼠标或键盘消息。 例如,当指针移到任务栏图标上时,lParam
设置为 WM_MOUSEMOVE。当
uVersion
成员为 NOTIFYICON_VERSION_4 时,应用程序继续通过uCallbackMessage
成员以应用程序定义消息的形式接收通知事件,但对该消息的lParam
和wParam
参数的解释更改如下:
LOWORD(lParam)
包含通知事件,例如 NIN_BALLOONSHOW、NIN_POPUPOPEN 或 WM_CONTEXTMENU。
HIWORD(lParam)
包含图标 ID。 图标 ID 的长度限制为 16 位。
GET_X_LPARAM(wParam)
返回通知事件 NIN_POPUPOPEN、NIN_SELECT、NIN_KEYSELECT 以及 WM_MOUSEFIRST 和 WM_MOUSELAST 之间的所有鼠标消息的 X 锚点坐标。 如果这些消息中的任何一个是由键盘生成的,则wParam
将设置为目标图标的左上角。 对于所有其他消息,wParam
未定义。
GET_Y_LPARAM(wParam)
返回为 X 锚点定义的通知事件和消息的 Y 锚点坐标。
添加通知图标时,您需要:
指定将从图标接收通知的hWnd
。
指定一个nID
或guidItem
来标识图标。 如果您使用guidItem
并显示多个图标,通知将无法告诉您哪个图标在通知您,因此您必须为每个图标使用单独的 HWND。 此外, guidItem
实际上在功能上比nID
更受限制,并且导致的问题多于它解决的问题,因此我强烈建议完全远离guidItem
并始终仅使用nID
。
启用NIF_MESSAGE
标志,并提供自定义uCallbackMessage
消息 ID。
每当用户与图标交互时,HWND 的 window 过程就会收到消息 ID。 消息的WPARAM
和LPARAM
值将描述操作。
例如:
#define APPWM_ICONNOTIFY (WM_APP + 1)
...
HICON hIcon = static_cast<HICON>(LoadImage(NULL,
TEXT("gui\\sample.ico"),
IMAGE_ICON,
0, 0,
LR_DEFAULTCOLOR | LR_SHARED | LR_DEFAULTSIZE | LR_LOADFROMFILE));
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
//Notification
NOTIFYICONDATA nid = {};
nid.cbSize = sizeof(nid);
nid.hWnd = hwnd;
nid.uID = 1;
nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
nid.uCallbackMessage = APPWM_ICONNOTIFY;
nid.hIcon = hIcon;
// This text will be shown as the icon's tooltip.
StringCchCopy(nid.szTip, ARRAYSIZE(nid.szTip), title);
// Show the notification.
Shell_NotifyIcon(NIM_ADD, &nid);
...
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case APPWM_ICONNOTIFY:
{
switch (lParam)
{
case WM_LBUTTONUP:
//...
break;
case WM_RBUTTONUP:
//...
break;
}
return 0;
}
//...
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
ShellNotifyIcon只是帮你制作图标,右键菜单需要你自己定义。 当您启用NIF_MESSAGE
时,NOTIFYICONDATA。 UCallbackMessage
将有效。
这样WndProc.uMsg = NOTIFYICONDATA.UCallbackMessage
您可以在消息事件上创建一个新的 PopupMenu。
这里是使用go写的例子,但主要调用winapi。
func main() {
// prepare test data
var iInfo w32.ICONINFO
myHICON := w32.HICON(userDll.MustLoadImage(
0, // hInstance must be NULL when loading from a file
"testdata/img/golang.ico", // the icon file name
w32.IMAGE_ICON, // specifies that the file is an icon
0, 0, // cx, cy
w32.LR_LOADFROMFILE| // we want to load a file (as opposed to a resource)
w32.LR_DEFAULTSIZE| // default metrics based on the type (IMAGE_ICON, 32x32)
w32.LR_SHARED, // let the system release the handle when it's no longer used
))
userDll.GetIconInfo(myHICON, &iInfo)
defer gdiDll.DeleteObject(w32.HGDIOBJ(iInfo.HbmColor))
defer gdiDll.DeleteObject(w32.HGDIOBJ(iInfo.HbmMask))
// variable used for createWindow
chanWin := make(chan w32.HWND)
const WMNotifyIconMsg = w32.WM_APP + 123
go runWindow("classShellNotifyIcon", "windowShellNotifyIcon",
WMNotifyIconMsg,
chanWin)
hwndTarget, isOpen := <-chanWin
if !isOpen {
return
}
notifyIconData := w32.NOTIFYICONDATA{
CbSize: 968,
HWnd: hwndTarget,
UID: 888, // wparam
UFlags: 0 | // NIF: NotifyIcon Flag
w32.NIF_ICON | // HIcon // main Icon
w32.NIF_INFO | // SzInfo, SzInfoTitle
w32.NIF_TIP | // SzTip
w32.NIF_MESSAGE, // UCallbackMessage
DwInfoFlags: 0 | // NIF: NotifyIcon Info Flag
w32.NIIF_USER | w32.NIIF_LARGE_ICON | // HBalloonIcon
w32.NIIF_NOSOUND,
HIcon: myHICON,
HBalloonIcon: userDll.MustLoadIcon(0, w32.MakeIntResource(w32.IDI_QUESTION)),
UCallbackMessage: WMNotifyIconMsg,
}
copy(notifyIconData.SzInfo[:], utf16.Encode([]rune("SzInfo Body"+"\x00")))
copy(notifyIconData.SzInfoTitle[:], utf16.Encode([]rune("SzInfoTitle Title"+"\x00")))
copy(notifyIconData.SzTip[:], utf16.Encode([]rune("Hover message"+"\x00")))
_ = shellDll.ShellNotifyIcon(w32.NIM_ADD, ¬ifyIconData)
defer shellDll.ShellNotifyIcon(w32.NIM_DELETE, ¬ifyIconData)
// test
_ = userDll.PostMessage(hwndTarget, WMNotifyIconMsg, 123, w32.WM_LBUTTONUP)
_ = userDll.PostMessage(hwndTarget, WMNotifyIconMsg, 0, w32.WM_RBUTTONUP)
<-chanWin
}
func runWindow(wndClassName, wndWindowName string,
WMNotifyIconMsg w32.UINT,
ch chan<- w32.HWND,
) {
hInstance := w32.HINSTANCE(kernelDll.GetModuleHandle(""))
wndProcFuncPtr := syscall.NewCallback(w32.WndProc(func(hwnd w32.HWND, uMsg w32.UINT, wParam w32.WPARAM, lParam w32.LPARAM) w32.LRESULT {
switch uMsg {
// check:
// 1. uCallbackMessage: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#nif_showtip-0x00000080
// 2. NIN_.{...} https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyicona#remarks
case w32.WM_CLOSE:
if wParam != 123 {
log.Println("do not close the window.")
userDll.ShowWindow(hwnd, w32.SW_HIDE)
return 0
}
case w32.WM_DESTROY:
log.Println("WM_DESTROY")
userDll.PostQuitMessage(0)
return 0
case w32.WM_CREATE:
ch <- hwnd
case WMNotifyIconMsg:
log.Println("NOTIFYICONDATA.UID", wParam)
switch lParam {
case w32.WM_MOUSEMOVE:
log.Println("WMNotifyIconMsg WM_MOUSEMOVE")
case w32.NIN_BALLOONUSERCLICK:
log.Println("NIN_BALLOONUSERCLICK")
userDll.ShowWindow(hwnd, w32.SW_SHOW)
case w32.NIN_BALLOONSHOW:
log.Println("NIN_BALLOONSHOW")
case w32.NIN_BALLOONTIMEOUT:
log.Println("NIN_BALLOONTIMEOUT")
case w32.WM_LBUTTONUP:
log.Println("WMNotifyIconMsg->WM_LBUTTONUP")
case w32.WM_LBUTTONDBLCLK:
log.Println("WMNotifyIconMsg->WM_LBUTTONDBLCLK")
userDll.ShowWindow(hwnd, w32.SW_SHOWNORMAL) // SW_MAXIMIZE
case w32.WM_RBUTTONDBLCLK:
// exit program
if errno := userDll.DestroyWindow(hwnd); errno != 0 {
log.Printf("%s", errno)
return 0
}
case w32.WM_RBUTTONUP:
// show popup menu
log.Println("WMNotifyIconMsg->WM_RBUTTONUP")
hMenu := userDll.CreatePopupMenu()
_ = userDll.AppendMenu(hMenu, w32.MF_STRING, 1023, "Display Dialog")
_ = userDll.SetMenuDefaultItem(hMenu, 0, true)
_ = userDll.AppendMenu(hMenu, w32.MF_STRING, 1024, "Say Hello")
_ = userDll.AppendMenu(hMenu, w32.MF_STRING, 1025, "Exit program")
// Optional add icon for 1025
{
var menuItemInfo w32.MENUITEMINFO
menuItemInfo.CbSize = uint32(unsafe.Sizeof(menuItemInfo))
menuItemInfo.FMask = w32.MIIM_BITMAP
hIconError := userDll.MustLoadIcon(0, w32.MakeIntResource(w32.IDI_ERROR))
var iInfo w32.ICONINFO
userDll.GetIconInfo(hIconError, &iInfo)
menuItemInfo.HbmpItem = iInfo.HbmColor
_ = userDll.SetMenuItemInfo(hMenu, 1025, false, &menuItemInfo)
defer func() {
gdiDll.DeleteObject(w32.HGDIOBJ(iInfo.HbmColor))
gdiDll.DeleteObject(w32.HGDIOBJ(iInfo.HbmMask))
}()
}
defer userDll.DestroyMenu(hMenu)
var pos w32.POINT
_ = userDll.GetCursorPos(&pos)
userDll.SetForegroundWindow(hwnd)
// "Displays" a shortcut menu at the specified location and "tracks the selection of items on the menu".
_, _ = userDll.TrackPopupMenu(hMenu, w32.TPM_LEFTALIGN, pos.X, pos.Y, 0, hwnd, nil)
default:
log.Printf("WMNotifyIconMsg unknown lParam: %d\n", lParam)
}
return 1
case w32.WM_COMMAND:
id := w32.LOWORD(wParam)
switch id {
case 1023:
_ = userDll.PostMessage(hwnd, uint32(WMNotifyIconMsg), 0, w32.WM_LBUTTONDBLCLK)
case 1024:
log.Println("hello")
case 1025:
log.Println("1025")
_ = userDll.PostMessage(hwnd, w32.WM_DESTROY, 0, 0)
}
}
return userDll.DefWindowProc(hwnd, uMsg, wParam, lParam)
}))
userDll.RegisterClass(&w32.WNDCLASS{
Style: w32.CS_HREDRAW | w32.CS_HREDRAW,
HbrBackground: w32.COLOR_WINDOW,
WndProc: wndProcFuncPtr,
HInstance: hInstance,
// HIcon:
ClassName: &(utf16.Encode([]rune(wndClassName + "\x00")))[0],
})
defer func() {
userDll.UnregisterClass(wndClassName, hInstance)
close(ch)
}()
hwnd, _ := userDll.CreateWindowEx(0,
wndClassName,
wndWindowName,
w32.WS_OVERLAPPEDWINDOW,
// Size and position
w32.CW_USEDEFAULT, w32.CW_USEDEFAULT, w32.CW_USEDEFAULT, w32.CW_USEDEFAULT,
0, // Parent window
0, // Menu
hInstance,
0, // Additional application data
)
if hwnd == 0 {
return
}
var msg w32.MSG
for {
if status, _ := userDll.GetMessage(&msg, 0, 0, 0); status <= 0 {
break
}
userDll.TranslateMessage(&msg)
userDll.DispatchMessage(&msg)
}
}
注意:一个HWND可以创建多个ShellNotifyIcon,以UID区分,可以创建多个,只需要输入不同的NOTIFYICONDATA即可。
UIDs
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.