托盘图标使用函数 Shell_NotifyIcon 创建、修改和删除,参数主要使用 NOTIFYICONDATA 结构。
任务栏启动时会给所有顶层窗口发送 TaskbarCreated 消息,由于不同系统消息标识不一样,所以需要使用 RegisterWindowMessage 向系统获取消息标识。
程序在VS2015 Win32编译通过,XP SP3测试通过。Win10气泡无反应,或者我该用 NOTIFYICON_VERSION_4 ?希望哪位能告知一二……
最后发现Win10需要打开操作中心,并且允许应用通知,Win10已把气泡消息整合到里面去了。可怜偶调试了三天……
下面是简介和本人被坑过的地方,其他可查看VS自带帮助。
一、定义:(概览\(^o^)/)
BOOL Shell_NotifyIcon(
_In_ DWORD dwMessage,
_In_ PNOTIFYICONDATA lpdata
);
其中 dwMessage 常用的选项如下:(其他略\(^o^)/)
NIM_ADD | 添加托盘图标。 |
NIM_MODIFY | 修改图标,也可弹出气泡图标。 |
NIM_DELETE | 删除图标,应在整个程序结束时也调用一次。 |
第二个参数为指向 NOTIFYICONDATA 的指针,常用参数如下:(其他再略\(^o^)/)
cbSize | NOTIFYICONDATA 占用的空间大小,要注意一定要先判断 Shell32.dll 版本号(除非你不想用于多个版本的系统),来对其赋值,具体见例程。 | |||
hWnd | 窗口句柄。 | |||
uID | 创建的图标标识,与 hWnd 组合定位托盘图标。 | |||
hIcon | 图标句柄,一般使用 LoadIcon(hInst, MAKEINTRESOURCE(IDI_WIN32TEST)) 赋予。 | |||
uVersion | 版本,Win2000后一般使用 NOTIFYICON_VERSION 保证兼容性,注意它与 uTimeout 共享内存(union), NOTIFYICON_VERSION_4 适用于Vista以后的系统。 | |||
uTimeout | 气泡自动消失的时间,Vista无效(VC2015帮助原文:【This member is deprecated as of Windows Vista. Notification display times are now based on system accessibility settings.】,我以前在Win7+VS2008测试时有效,所以不确定Win7以上是否无效) | |||
uCallbackMessage |
| |||
uFlags | 标识,指出有效的成员并且指出托盘图标显示的方式, NIF_MESSAGE 使 uCallbackMessage 有效, NIF_ICON 使 hIcon 有效, NIF_TIP 使 szTip 有效, NIF_INFO 使 szInfo 、 szInfoTitle 、 dwInfoFlags 、 uTimeout 有效。 | |||
szTip | 鼠标指向托盘图标时显示的提示消息,注意长度。 | |||
szInfo | 气泡提示内容,注意长度。 | |||
szInfoTitle | 气泡标题,为空时 dwInfoFlags 无效,注意长度。 | |||
dwInfoFlags | 气泡图标,NIIF_NONE 表示无图标,NIIF_INFO 表示【提示】,NIIF_WARNING 表示【警告】,NIIF_ERROR 表示【错误】。(其他略\(^o^)/) |
二、例程:(还是概览\(^o^)/)
头文件:
class CTrayIcon
{
public:
CTrayIcon();
~CTrayIcon();
BOOL CreateTray(HWND, HICON, UINT, LPCTSTR = _T(""));
BOOL ChangeTray(LPCTSTR, UINT = 3000);
BOOL DeleteTray();
private:
ULONGLONG GetVersion(LPCTSTR);
DWORD GetSize_NotifyIconData();
NOTIFYICONDATA m_Notify;
};
获取cbsize,这里要特别注意,具体可参考《关于NOTIFYICONDATA的一些新特性》和《正确使用DllGetVersion》:
ULONGLONG CTrayIcon::GetVersion(LPCTSTR lpszDllName)
{
HINSTANCE hinstDll;
ULONGLONG dwVersion = 0;
hinstDll = LoadLibrary(lpszDllName);
if (hinstDll)
{
DLLGETVERSIONPROC pDllGetVersion;
pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstDll, "DllGetVersion");
if (pDllGetVersion)
{
DLLVERSIONINFO dvi;
HRESULT hr;
ZeroMemory(&dvi, sizeof(dvi));
dvi.cbSize = sizeof(dvi);
hr = (*pDllGetVersion)(&dvi);
if (SUCCEEDED(hr))
{
dwVersion = MAKEDLLVERULL(dvi.dwMajorVersion, dvi.dwMinorVersion,
dvi.dwBuildNumber, dvi.dwPlatformID);
}
}
FreeLibrary(hinstDll);
}
return dwVersion;
}
DWORD CTrayIcon::GetSize_NotifyIconData()
{
TCHAR lpszDllName[128];
GetWindowsDirectory(lpszDllName, _TRUNCATE);
_tcsncat_s(lpszDllName, _T("\\System32\\Shell32.dll"), _TRUNCATE);
ULONGLONG NIDdllVer = GetVersion(lpszDllName);
// before windows 2000
if (NIDdllVer < MAKEDLLVERULL(5, 0, 0, 0)) {
return NOTIFYICONDATA_V1_SIZE;
}
// Windows 2000
else if (NIDdllVer < MAKEDLLVERULL(6, 0, 0, 0)) {
return NOTIFYICONDATA_V2_SIZE;
}
// Windows XP or 2003
else if (NIDdllVer < MAKEDLLVERULL(6, 0, 6000, 0)) {
return NOTIFYICONDATA_V3_SIZE;
}
// Windows Vista and later
else {
return sizeof(NOTIFYICONDATA);
}
}
创建:
BOOL CTrayIcon::CreateTray(HWND hWnd, HICON hIcon, UINT uCallbackMessage, LPCTSTR szTitle)
{
m_Notify.cbSize = GetSize_NotifyIconData();
m_Notify.hIcon = hIcon;
m_Notify.hWnd = hWnd;
m_Notify.uCallbackMessage = uCallbackMessage;
m_Notify.uVersion = NOTIFYICON_VERSION;
m_Notify.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
m_Notify.uID = 1;
_tcscpy_s(m_Notify.szTip, szTitle);
return Shell_NotifyIcon(NIM_ADD, &m_Notify);
}
气泡:
BOOL CTrayIcon::ChangeTray(LPCTSTR msg, UINT uTimeout)
{
m_Notify.uFlags = NIF_INFO;
m_Notify.dwInfoFlags = NIIF_NONE;
// m_Notify.uTimeout = uTimeout;
_tcscpy_s(m_Notify.szInfo, msg);
return Shell_NotifyIcon(NIM_MODIFY, &m_Notify);
}
删除:
BOOL CTrayIcon::DeleteTray() {
return Shell_NotifyIcon(NIM_DELETE, &m_Notify);
}
定义托盘图标响应消息:
#define WM_ICON_NOTIFY WM_USER+1001
注册 TaskbarCreated 消息:
const UINT WM_TASKBARCREATED = ::RegisterWindowMessage(_T("TaskbarCreated"));
消息处理&调用(Win32):
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// Restore the tray-icon after the explorer's recreation
if (message == WM_TASKBARCREATED) {
if (!IsWindowVisible(hWnd))
trayIcon.CreateTray(hWnd, LoadIcon(hInst, MAKEINTRESOURCE(IDI_WIN32TEST)), WM_ICON_NOTIFY, szTitle);
return DefWindowProc(hWnd, message, wParam, lParam);
}
switch (message)
{
case WM_SIZE:
switch (wParam)
{
case SIZE_RESTORED: // Restore the window and delete the tray-icon
ShowWindow(hWnd, SW_SHOW);
trayIcon.DeleteTray();
break;
case SIZE_MINIMIZED: // Hide the window and create the tray-icon
ShowWindow(hWnd, SW_HIDE);
trayIcon.CreateTray(hWnd, LoadIcon(hInst, MAKEINTRESOURCE(IDI_WIN32TEST)), WM_ICON_NOTIFY, szTitle);
break;
default:
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
case WM_COMMAND:
// ...
break;
case WM_PAINT:
// ...
break;
case WM_ICON_NOTIFY:
switch (lParam)
{
case WM_LBUTTONDOWN:
SendMessage(hWnd, WM_SYSCOMMAND, SC_RESTORE, lParam);
SetForegroundWindow(hWnd);
break;
default:
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}