[英]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.具体来说,您没有设置其cbSize
或uVersion
成员,这会直接影响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.