[英]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.