簡體   English   中英

NOTIFY ICON 點擊c++中的Win32 Api

[英]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()文檔中:

NOTIFYICONDATA結構

NIF_MESSAGE (0x00000001)
uCallbackMessage成員有效

u回調消息
類型:UINT

應用程序定義的消息標識符。 系統使用此標識符向hWnd中標識的 window 發送通知消息。 圖標的邊界矩形中發生鼠標事件或 hover 時,當使用鍵盤選擇或激活圖標時,或者當氣球通知中發生這些操作時,將發送這些通知消息。

uVersion成員為 0 或 NOTIFYICON_VERSION 時,消息的wParam參數包含事件發生的任務欄圖標的標識符。 這個標識符的長度可以是 32 位。 lParam參數保存與事件關聯的鼠標或鍵盤消息。 例如,當指針移到任務欄圖標上時, lParam設置為 WM_MOUSEMOVE。

uVersion成員為 NOTIFYICON_VERSION_4 時,應用程序繼續通過uCallbackMessage成員以應用程序定義消息的形式接收通知事件,但對該消息的lParamwParam參數的解釋更改如下:

  • 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 錨點坐標。

添加通知圖標時,您需要:

  1. 指定將從圖標接收通知的hWnd

  2. 指定一個nIDguidItem來標識圖標。 如果您使用guidItem並顯示多個圖標,通知將無法告訴您哪個圖標在通知您,因此您必須為每個圖標使用單獨的 HWND。 此外, guidItem實際上在功能上比nID更受限制,並且導致的問題多於它解決的問題,因此我強烈建議完全遠離guidItem並始終僅使用nID

  3. 啟用NIF_MESSAGE標志,並提供自定義uCallbackMessage消息 ID。

每當用戶與圖標交互時,HWND 的 window 過程就會收到消息 ID。 消息的WPARAMLPARAM值將描述操作。

例如:

#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, &notifyIconData)
    defer shellDll.ShellNotifyIcon(w32.NIM_DELETE, &notifyIconData)

    // 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM