简体   繁体   English

创建系统托盘右键菜单 C++

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

I am trying to create Systemtray icon in Unreal Engine 4. I am not a c++ expert.我正在尝试在虚幻引擎 4 中创建 Systemtray 图标。我不是 C++ 专家。 This is what i have scalped code from internet so far到目前为止,这是我从互联网上剥取的代码

#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;
}

Icon gets created but i cant rightclick and getpopup menu from it Also i cant figure out how LRESULT CALLBACK WndProc() function gets triggered.图标已创建,但我无法右键单击并从中获取弹出菜单我也无法弄清楚 LRESULT CALLBACK WndProc() 函数是如何被触发的。

Can any1 help Thanks任何人都可以帮助谢谢

You are not initializing the NOTIFYICONDATA correctly.您没有正确初始化NOTIFYICONDATA Specifically, you are not setting its cbSize or uVersion members, which directly influence how Shell_NotifyIcon() interacts with your app through the message you assign to the uCallbackMessage member.具体来说,您没有设置其cbSizeuVersion成员,这会直接影响Shell_NotifyIcon()通过您分配给uCallbackMessage成员的消息与您的应用程序交互的方式。 This is discussed in detail in the following MSDN documentation:以下 MSDN 文档对此进行了详细讨论:

Notifications and the Notification Area: Define the NOTIFYICONDATA Version 通知和通知区域:定义 NOTIFYICONDATA 版本

Shell_NotifyIcon: Remarks Shell_NotifyIcon:备注

NOTIFYICONDATA structure NOTIFYICONDATA 结构

Also, you say you want to display the popup menu on a right-click , but your WndProc() is looking for a left double-click instead.此外,您说您想在右键单击时显示弹出菜单,但您的WndProc()正在寻找左键双击

But more importantly, you need to associate your WndProc() with the HWND that you give to Shell_NotifyIcon() , so that you can actually receive your NOTIFICATION_TRAY_ICON_MSG message at all.但更重要的是,您需要将您的WndProc()与您提供给Shell_NotifyIcon()HWND相关联,以便您可以真正接收您的NOTIFICATION_TRAY_ICON_MSG消息。 Since you are trying to use an HWND that you are not the creator of, UE4 is the creator, you will have to subclass the window , eg:由于您尝试使用的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);
}

That being said, you really should create your own window to handle the interaction with the System Tray.话虽如此,您确实应该创建自己的窗口来处理与系统托盘的交互。 You can call CreateWindowEx() directly to create a hidden message-only window and then associate your icon's WndProc() with that window.您可以直接调用CreateWindowEx()来创建一个隐藏的仅消息窗口,然后将您的图标的WndProc()与该窗口相关联。 You DO NOT need to use the UE4 window:您不需要使用 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