You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UE4使用C++创建系统托盘右键菜单功能异常问题求助

问题修复与原理说明

右键无弹出菜单的修复

你遇到的问题有4个核心原因,对应修复方案如下:

  1. 未处理右键事件:当前代码只监听了WM_LBUTTONDBLCLK(左键双击)事件,右键点击对应的WM_RBUTTONUP事件完全没有处理
  2. 自定义WndProc未挂载到UE4窗口:UE4的原生窗口有默认的窗口处理函数,你自行编写的WndProc如果没有绑定到对应窗口句柄,系统永远不会调用它,所有托盘事件都会被UE4默认逻辑吞掉
  3. 弹出菜单前未设置前台窗口:Win32要求调用TrackPopupMenu前必须将所属窗口设为前台窗口,否则菜单会出现无法弹出、点击空白处无法关闭的异常
  4. NOTIFYICONDATA未初始化大小:Win32要求所有结构体必须先初始化cbSize成员,否则跨系统版本调用时会出现不可预期的错误

修复后的完整代码参考:

#define NOTIFICATION_TRAY_ICON_MSG (WM_USER + 0x100)
// 存储原UE4窗口过程的指针,必须保留,否则UE4原生窗口逻辑会失效
WNDPROC OriginalWndProc = nullptr;
const int IDM_EXIT = 100;

LRESULT CALLBACK CustomWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case NOTIFICATION_TRAY_ICON_MSG:
    {
        switch (lParam)
        {
        // 处理右键抬起事件
        case WM_RBUTTONUP:
        // 保留你原来的左键双击逻辑
        case WM_LBUTTONDBLCLK:
        {
            POINT pt;
            GetCursorPos(&pt);
            HMENU hmenu = CreatePopupMenu();
            InsertMenu(hmenu, 0, MF_BYPOSITION | MF_STRING, IDM_EXIT, L"Exit");
            // 必须先设置前台窗口
            SetForegroundWindow(hWnd);
            TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_BOTTOMALIGN, pt.x, pt.y, 0, hWnd, NULL);
            // 销毁菜单避免内存泄漏
            DestroyMenu(hmenu);
            return 0;
        }
        }
        break;
    }
    // 处理菜单点击事件
    case WM_COMMAND:
    {
        if (LOWORD(wParam) == IDM_EXIT)
        {
            // 这里写退出逻辑,比如调用UKismetSystemLibrary::QuitGame
            return 0;
        }
        break;
    }
    }
    // 所有未处理的消息必须交给原UE4窗口过程处理,否则会导致输入失效等问题
    return CallWindowProc(OriginalWndProc, hWnd, message, wParam, lParam);
}

void AddTrayIcon(HWND hWnd, UINT uID, UINT uCallbackMsg, UINT uIcon) {
    NOTIFYICONDATA  nid = {0};
    // 必须初始化结构体大小
    nid.cbSize = sizeof(NOTIFYICONDATA);
    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);
    wcscpy_s(nid.szTip, L"Tool Tip");
    Shell_NotifyIcon(NIM_ADD, &nid);
    
    // 挂载自定义窗口过程,保存原有窗口过程
    OriginalWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)CustomWndProc);
}

WndProc触发机制说明

WndProc是Win32平台的窗口过程函数,属于Windows消息驱动模型的核心:

  • 每个Windows窗口创建时都会绑定一个窗口过程函数指针,系统会通过这个函数通知窗口所有发生的事件
  • 你在NOTIFYICONDATA中设置了uCallbackMessage为自定义的NOTIFICATION_TRAY_ICON_MSG后,每当用户操作托盘图标时,系统就会给你绑定的hWnd发送这条自定义消息,消息的lParam存储具体的操作类型(左键点击、右键点击、双击等)
  • 你之前编写的WndProc没有绑定到UE4的窗口上,因此系统只会调用UE4自带的窗口过程,你的逻辑永远不会被触发,这是右键无响应的核心原因之一

内容的提问来源于stack exchange,提问作者sandy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 04:00:04