簡體   English   中英

創建系統托盤右鍵菜單 C++

[英]Creating system tray right click menu C++

我正在嘗試在虛幻引擎 4 中創建 Systemtray 圖標。我不是 C++ 專家。 到目前為止,這是我從互聯網上剝取的代碼

#define NOTIFICATION_TRAY_ICON_MSG (WM_USER + 0x100)
AddTrayIcon(hwnd, 1, NOTIFICATION_TRAY_ICON_MSG, 0);
void AddTrayIcon(HWND hWnd, UINT uID, UINT uCallbackMsg, UINT uIcon) {

    //CREATE SYSTEN TRAY ICON.---------------------------------------------------------------------

    NOTIFYICONDATA  nid;

    nid.hWnd = hWnd;

    nid.uID = uID;

    nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;

    nid.uCallbackMessage = uCallbackMsg;
    FString ThePath = FPaths::ConvertRelativePathToFull(FPaths::RootDir()) ;
    FString GameName = FApp::GetName();
    
    ThePath.Append(GameName);
    ThePath.Append(".exe");
    GEngine->AddOnScreenDebugMessage(-1, 12.f, FColor::White, ThePath);
    WORD id = 0;
    nid.hIcon = ExtractAssociatedIcon(nullptr, ThePath.GetCharArray().GetData(),&id);
    //LPCWSTR iconfile = "C:/Temp/icon.ico";
    //ExtractIconEx(iconfile, 0, NULL, &(nid.hIcon), 1);

    //strcpy(nid.szTip, "Tool Tip");

    //SEND MESSAGE TO SYSTEM TRAY TO ADD ICON.--------------------------------------------

     Shell_NotifyIcon(NIM_ADD, &nid);
    

}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {

    case NOTIFICATION_TRAY_ICON_MSG:
    {
        // This is a message that originated with the
        // Notification Tray Icon. The lParam tells use exactly which event
        // it is.
        switch (lParam)
        {
        case WM_LBUTTONDBLCLK:
        {
            const int IDM_EXIT = 100;
            POINT pt;
            GetCursorPos(&pt);
            HMENU hmenu = CreatePopupMenu();
            InsertMenu(hmenu, 0, MF_BYPOSITION | MF_STRING, IDM_EXIT, L"Exit");
            TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_BOTTOMALIGN, pt.x, pt.y, 0, GetActiveWindow(), NULL);
            break;
        }
        }
    }
    }
    return 0;
}

圖標已創建,但我無法右鍵單擊並從中獲取彈出菜單我也無法弄清楚 LRESULT CALLBACK WndProc() 函數是如何被觸發的。

任何人都可以幫助謝謝

您沒有正確初始化NOTIFYICONDATA 具體來說,您沒有設置其cbSizeuVersion成員,這會直接影響Shell_NotifyIcon()通過您分配給uCallbackMessage成員的消息與您的應用程序交互的方式。 以下 MSDN 文檔對此進行了詳細討論:

通知和通知區域:定義 NOTIFYICONDATA 版本

Shell_NotifyIcon:備注

NOTIFYICONDATA 結構

此外,您說您想在右鍵單擊時顯示彈出菜單,但您的WndProc()正在尋找左鍵雙擊

但更重要的是,您需要將您的WndProc()與您提供給Shell_NotifyIcon()HWND相關聯,以便您可以真正接收您的NOTIFICATION_TRAY_ICON_MSG消息。 由於您嘗試使用的HWND不是您的創建者,UE4 是創建者,因此您必須對window進行子類化,例如:

#define NOTIFICATION_TRAY_ICON_MSG (WM_USER + 0x100)

void AddTrayIcon(HWND hWnd, UINT uID, UINT uCallbackMsg, UINT uIcon);
void RemoveTrayIcon(HWND hWnd, UINT uID);
LRESULT CALLBACK SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);

...

HWND hwnd = ...; // GetActiveWindow(), etc
if (SetWindowSubclass(hwnd, &SubclassProc, 1, 0))
    AddTrayIcon(hwnd, 1, NOTIFICATION_TRAY_ICON_MSG, 0);

...

void AddTrayIcon(HWND hWnd, UINT uID, UINT uCallbackMsg, UINT uIcon) {

    //CREATE SYSTEM TRAY ICON.---------------------------------------------------------------------

    NOTIFYICONDATA nid = {};
    nid.cbSize = sizeof(nid);
    nid.hWnd = hWnd;
    nid.uID = uID;
    nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
    nid.uCallbackMessage = uCallbackMsg;
    nid.uVersion = NOTIFYICON_VERSION_4;

    FString ThePath = FPaths::ConvertRelativePathToFull(FPaths::RootDir()) ;
    FString GameName = FApp::GetName();
    
    ThePath.Append(GameName);
    ThePath.Append(".exe");
    GEngine->AddOnScreenDebugMessage(-1, 12.f, FColor::White, ThePath);

    WORD id = 0;
    nid.hIcon = ExtractAssociatedIcon(nullptr, ThePath.GetCharArray().GetData(), &id);
    //LPCWSTR iconfile = L"C:/Temp/icon.ico";
    //ExtractIconEx(iconfile, 0, NULL, &(nid.hIcon), 1);

    //strcpy(nid.szTip, "Tool Tip");

    //SEND MESSAGE TO SYSTEM TRAY TO ADD ICON.--------------------------------------------

    if (Shell_NotifyIcon(NIM_ADD, &nid))
        Shell_NotifyIcon(NIM_SETVERSION, &nid);
}

void RemoveTrayIcon(HWND hWnd, UINT uID) {

    //REMOVE SYSTEM TRAY ICON.---------------------------------------------------------------------

    NOTIFYICONDATA nid = {};
    nid.cbSize = sizeof(nid);
    nid.hWnd = hWnd;
    nid.uID = uID;

    //SEND MESSAGE TO SYSTEM TRAY TO REMOVE ICON.--------------------------------------------

    Shell_NotifyIcon(NIM_DELETE, &nid);
}

LRESULT CALLBACK SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    switch (uMsg)
    {
        case WM_NCDESTROY:
            RemoveTrayIcon(hWnd, 1);
            RemoveWindowSubclass(hWnd, &SubclassProc, uIdSubclass);
            break;

        case NOTIFICATION_TRAY_ICON_MSG:
        {
            // This is a message that originated with the
            // Notification Tray Icon. The lParam tells use exactly which event
            // it is.
            switch (LOWORD(lParam))
            {
                case NIN_SELECT:
                case NIN_KEYSELECT:
                case WM_CONTEXTMENU:
                {
                    const int IDM_EXIT = 100;

                    POINT pt;
                    GetCursorPos(&pt);

                    HMENU hmenu = CreatePopupMenu();
                    InsertMenu(hmenu, 0, MF_BYPOSITION | MF_STRING, IDM_EXIT, L"Exit");

                    SetForegroundWindow(hWnd);

                    int cmd = TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_BOTTOMALIGN | TPM_NONOTIFY | TPM_RETURNCMD, pt.x, pt.y, 0, hWnd, NULL);

                    PostMessage(hWnd, WM_NULL, 0, 0);

                    if (cmd == IDM_EXIT)
                    {
                        ...
                    }

                    break;
                }
            }

            return 0;
        }
    }

    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

話雖如此,您確實應該創建自己的窗口來處理與系統托盤的交互。 您可以直接調用CreateWindowEx()來創建一個隱藏的僅消息窗口,然后將您的圖標的WndProc()與該窗口相關聯。 您不需要使用 UE4 窗口:

LRESULT CALLBACK SysTrayWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

...

LPCTSTR SysTrayWndClass = TEXT("MySysTrayWnd");

HINSTANCE hInst = ...; // GetModuleHandle(NULL), etc

WNDCLASS wc = {};
wc.lpfnWndProc = &SysTrayWndProc;
wc.hInstance = hInst;
wc.lpszClassName = SysTrayWndClass;
RegisterClass(&wc);

HWND hSysTrayIconWnd = CreateWindowEx(0, SysTrayWndClass, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInst, NULL);
if (hSysTrayIconWnd) {
    AddTrayIcon(hSysTrayIconWnd, 1, NOTIFICATION_TRAY_ICON_MSG, 0);
}
...
if (hSysTrayIconWnd) {
    RemoveTrayIcon(hSysTrayIconWnd, 1);
    DestroyWindow(hSysTrayIconWnd);
}

...

LRESULT CALLBACK SysTrayWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case NOTIFICATION_TRAY_ICON_MSG:
        {
            // This is a message that originated with the
            // Notification Tray Icon. The lParam tells use exactly which event
            // it is.
            switch (LOWORD(lParam))
            {
                case NIN_SELECT:
                case NIN_KEYSELECT:
                case WM_CONTEXTMENU:
                {
                    const int IDM_EXIT = 100;

                    POINT pt;
                    GetCursorPos(&pt);

                    HMENU hmenu = CreatePopupMenu();
                    InsertMenu(hmenu, 0, MF_BYPOSITION | MF_STRING, IDM_EXIT, L"Exit");

                    SetForegroundWindow(hWnd);

                    int cmd = TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_BOTTOMALIGN, pt.x, pt.y, 0, hWnd, NULL);

                    PostMessage(hWnd, WM_NULL, 0, 0);

                    break;
                }
            }

            return 0;
        }

       case WM_COMMAND:
           if (lParam == 0 && LOWORD(wParam) == IDM_EXIT)
           {
               ...
           }
           break;
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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