Моя цель — создать значок уведомления оболочки и заставить его отображать всплывающую подсказку при необходимости. Я написал следующий код.
bool SystemTrayIcon::Create(const std::wstring & Tip,
HWND hWndParent,
const GUID & Guid,
UINT IdCallback,
HICON hIcon,
TYPE Type,
bool bSound,
bool bSharedIcon,
bool bHidden,
bool bLargeIcon,
bool bRespectQuiteTime)
{
NotifyIconData.cbSize = sizeof(NotifyIconData);
NotifyIconData.hWnd = hWndParent;
NotifyIconData.uID = 0; // Use GUID instead. (NIF_GUID)
NotifyIconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_STATE | NIF_GUID | NIF_REALTIME | NIF_SHOWTIP;
NotifyIconData.uCallbackMessage = IdCallback;
NotifyIconData.hIcon = hIcon;
if (Tip.length() > MAX_TIP)
{
std::wcsncpy(NotifyIconData.szTip, Tip.c_str(), MAX_TIP);
NotifyIconData.szTip[MAX_TIP] = wchar_t(0);
}
else
{
std::wcsncpy(NotifyIconData.szTip, Tip.c_str(), Tip.length() + 1);
}
NotifyIconData.dwState = (bSharedIcon ? NIS_SHAREDICON : 0)
| (bHidden ? NIS_HIDDEN : 0);
NotifyIconData.dwStateMask = NIS_SHAREDICON | NIS_HIDDEN;
NotifyIconData.uVersion = NOTIFYICON_VERSION_4;
DWORD dwType;
switch (Type)
{
case TYPE::STI_INFO:
dwType = NIIF_INFO;
break;
case TYPE::STI_WARNING:
dwType = NIIF_WARNING;
break;
case TYPE::STI_ERROR:
dwType = NIIF_ERROR;
break;
}
NotifyIconData.dwInfoFlags = dwType | NIIF_USER
| (bSound ? 0 : NIIF_NOSOUND)
| (bLargeIcon ? NIIF_LARGE_ICON : 0)
| (bRespectQuiteTime ? NIIF_RESPECT_QUIET_TIME : 0);
NotifyIconData.guidItem = Guid;
return bInitialized = Shell_NotifyIconW(NIM_ADD, &NotifyIconData);
}
void SystemTrayIcon::Balloon( const std::wstring & Title,
const std::wstring & Message,
HICON hBalloonIcon)
{
if (!bInitialized) return;
if (Title.length() > MAX_TITLE)
{
std::wcsncpy(NotifyIconData.szInfoTitle, Title.c_str(), MAX_TITLE);
NotifyIconData.szInfoTitle[MAX_TITLE] = wchar_t(0);
}
else
{
std::wcsncpy(NotifyIconData.szInfoTitle, Title.c_str(), Title.length() + 1);
}
if (Message.length() > MAX_MESSAGE)
{
std::wcsncpy(NotifyIconData.szInfo, Message.c_str(), MAX_MESSAGE);
NotifyIconData.szInfo[MAX_MESSAGE] = wchar_t(0);
}
else
{
std::wcsncpy(NotifyIconData.szInfo, Message.c_str(), Message.length() + 1);
}
NotifyIconData.hBalloonIcon = hBalloonIcon;
NotifyIconData.dwInfoFlags |= NIF_INFO;
Update();
}
void SystemTrayIcon::Update()
{
Shell_NotifyIconW(NIM_MODIFY, &NotifyIconData);
}
Я вызываю эти функции-члены в коде так:
TrayIcon.Create(/*const std::wstring & Tip*/ L"Tip",
/*HWND hWndParent*/ Window.hWnd,
/*const GUID & Guid*/ GUID {0x7f0f02e3, 0x479b, 0x4a09, {0xbf, 0x99, 0xd3, 0x39, 0xe9, 0x3a, 0x8b, 0x22}},
/*UINT IdCallback*/ ID_TRAYICON,
/*HICON hIcon*/ (HICON) LoadImageW(Status::hInstance, L"icon1.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE),
/*TYPE Type*/ SystemTrayIcon::TYPE::STI_INFO,
/*bool bSound*/ true,
/*bool bSharedIcon*/ false,
/*bool bHidden*/ false,
/*bool bLargeIcon*/ true,
/*bool bRespectQuiteTime*/ false);
Sleep(10000);
TrayIcon.Balloon( L"New Title",
L"New Message",
(HICON) LoadImageW(Status::hInstance, L"icon2.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE));
Значок отображается правильно после вызова Create()
метод. Но Balloon()
метод не имеет никакого эффекта. Не отображается наконечник баллона.
Я могу заставить его отображать воздушный шар при создании, добавив NIF_INFO
постоянный uFlags
и заполняя szInfoTitle
а также szInfo
члены. Но я пытаюсь показать это в любое произвольное время, вызывая Balloon()
метод.
Что мне здесь не хватает?
Я решил много проблем в моем коде. Теперь он работает отлично и как я хотел. Ниже мой новый код. Обратите внимание на изменения.
bool SystemTrayIcon::Create(const std::wstring & Tip,
HWND hWndParent,
const GUID & Guid,
UINT IdCallback,
HICON hIcon,
bool bSharedIcon,
bool bHidden)
{
if (bInitialized) return false;
NotifyIconData.cbSize = sizeof(NotifyIconData);
NotifyIconData.hWnd = hWndParent;
NotifyIconData.uID = 0; // Use GUID instead. (NIF_GUID)
NotifyIconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_STATE | NIF_GUID | NIF_SHOWTIP;
NotifyIconData.uCallbackMessage = IdCallback;
NotifyIconData.hIcon = hIcon;
if (Tip.length() > MAX_TIP)
{
std::wcsncpy(NotifyIconData.szTip, Tip.c_str(), MAX_TIP);
NotifyIconData.szTip[MAX_TIP] = wchar_t(0);
}
else
{
std::wcsncpy(NotifyIconData.szTip, Tip.c_str(), Tip.length() + 1);
}
NotifyIconData.dwState = (bSharedIcon ? NIS_SHAREDICON : 0)
| (bHidden ? NIS_HIDDEN : 0);
NotifyIconData.dwStateMask = NIS_SHAREDICON | NIS_HIDDEN;
NotifyIconData.guidItem = Guid;
bInitialized = Shell_NotifyIconW(NIM_ADD, &NotifyIconData);
NotifyIconData.uVersion = NOTIFYICON_VERSION_4;
bLastResult = Shell_NotifyIconW(NIM_SETVERSION, &NotifyIconData);
return bInitialized;
}
void SystemTrayIcon::Balloon( const std::wstring & Title,
const std::wstring & Message,
HICON hBalloonIcon,
BALLOON_ICON_TYPE IconType,
UINT Timeout, // In milliseconds.
bool bSound,
bool bLargeIcon,
bool bRespectQuiteTime)
{
if (!bInitialized) return;
if (Title.length() > MAX_TITLE)
{
std::wcsncpy(NotifyIconData.szInfoTitle, Title.c_str(), MAX_TITLE);
NotifyIconData.szInfoTitle[MAX_TITLE] = wchar_t(0);
}
else
{
std::wcsncpy(NotifyIconData.szInfoTitle, Title.c_str(), Title.length() + 1);
}
if (Message.length() > MAX_MESSAGE)
{
std::wcsncpy(NotifyIconData.szInfo, Message.c_str(), MAX_MESSAGE);
NotifyIconData.szInfo[MAX_MESSAGE] = wchar_t(0);
}
else
{
std::wcsncpy(NotifyIconData.szInfo, Message.c_str(), Message.length() + 1);
}
DWORD dwType;
switch (IconType)
{
case BALLOON_ICON_TYPE::BIT_NONE:
dwType = 0;
break;
case BALLOON_ICON_TYPE::BIT_INFO:
dwType = NIIF_INFO;
break;
case BALLOON_ICON_TYPE::BIT_WARNING:
dwType = NIIF_WARNING;
break;
case BALLOON_ICON_TYPE::BIT_ERROR:
dwType = NIIF_ERROR;
break;
case BALLOON_ICON_TYPE::BIT_USER_DEFINED:
dwType = NIIF_USER; // Use the "hBalloonIcon" parameter.
break;
}
NotifyIconData.dwInfoFlags = dwType
| (bSound ? 0 : NIIF_NOSOUND)
| (bLargeIcon ? NIIF_LARGE_ICON : 0)
| (bRespectQuiteTime ? NIIF_RESPECT_QUIET_TIME : 0);
NotifyIconData.uTimeout = Timeout;
NotifyIconData.hBalloonIcon = hBalloonIcon;
NotifyIconData.uFlags = NIF_INFO | NIF_GUID;
Update();
}
void SystemTrayIcon::Update()
{
bLastResult = Shell_NotifyIconW(NIM_MODIFY, &NotifyIconData);
}
Использование в коде:
TrayIcon.Create(/*const std::wstring & Tip*/ L"Tip",
/*HWND hWndParent*/ Window.hWnd,
/*const GUID & Guid*/ GUID {0x7f0f02e4, 0x479b, 0x4a09, {0xbf, 0x99, 0xd3, 0x39, 0xe9, 0x3a, 0x8b, 0x22}},
/*UINT IdCallback*/ ID_TRAYICON,
/*HICON hIcon*/ (HICON) hImage,
/*bool bSharedIcon*/ false,
/*bool bHidden*/ false);
// ...
TrayIcon.Balloon( L"Button 2",
L"You have just clicked the Button #2.",
(HICON) hImage,
SystemTrayIcon::BALLOON_ICON_TYPE::BIT_USER_DEFINED,
20000U,
true,
true,
false);
Других решений пока нет …