.NET Compact Framework (CF) 缺少 NotifyIcon 控制項。參考桌面版用 Shell_NotifyIcon + MessageWindow 實作,發現 CF 同樣支援:
Microsoft.WindowsCE.Forms.MessageWindow:提供視窗程序 WndProc 接收訊息。coredll.dll 匯出 Shell_NotifyIcon:WinCE 核心 DLL 包含該 API。
[StructLayout(LayoutKind.Sequential)]
internal struct NOTIFYICONDATA
{
internal int cbSize; // 結構大小,CF 固定 152
internal IntPtr hWnd; // 接收訊息的視窗控制代碼
internal uint uID; // 圖示識別碼
internal uint uFlags; // 有效欄位標記
internal uint uCallbackMessage; // 回呼訊息代碼
internal IntPtr hIcon; // 圖示控制代碼
}
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using Microsoft.WindowsCE.Forms;
public class NotifyIcon : IDisposable
{
public event EventHandler Click;
private readonly MessageWindow _msgWin;
private readonly uint _uid = 5000;
private Icon _icon;
public NotifyIcon()
{
_msgWin = new MessageWindow();
_msgWin.WndProc += MsgWin_WndProc;
}
public Icon Icon { set => _icon = value; }
public void Add() => Add(_icon?.Handle ?? IntPtr.Zero);
public void Add(Icon icon) => Add(icon.Handle);
public void Add(IntPtr hIcon) => Notify(NIM_ADD, hIcon);
public void Remove() => Notify(NIM_DELETE, IntPtr.Zero);
public void Modify(IntPtr hIcon) => Notify(NIM_MODIFY, hIcon);
private void Notify(int msg, IntPtr hIcon)
{
NOTIFYICONDATA nid = new NOTIFYICONDATA
{
cbSize = 152,
hWnd = _msgWin.Hwnd,
uID = _uid,
uFlags = NIF_MESSAGE | NIF_ICON,
uCallbackMessage = WM_NOTIFY_TRAY,
hIcon = hIcon
};
Shell_NotifyIcon(msg, ref nid);
}
private void MsgWin_WndProc(ref Message m)
{
if (m.Msg == WM_NOTIFY_TRAY && (int)m.LParam == WM_LBUTTONDOWN && (int)m.WParam == _uid)
Click?.Invoke(this, EventArgs.Empty);
}
public void Dispose() { Remove(); _msgWin.Dispose(); }
// P/Invoke
private const int NIF_MESSAGE = 0x1, NIF_ICON = 0x2;
private const int NIM_ADD = 0, NIM_MODIFY = 1, NIM_DELETE = 2;
private const int WM_LBUTTONDOWN = 0x201;
private const int WM_NOTIFY_TRAY = 0x400 + 2001;
[DllImport("coredll.dll")] private static extern int Shell_NotifyIcon(int msg, ref NOTIFYICONDATA nid);
}
NotifyIcon tray = new NotifyIcon();
tray.Icon = new Icon(@"\Windows\alarm.ico");
tray.Click += (s, e) => MessageBox.Show("托盤圖示被點擊!");
tray.Add();
// 程式結束時
tray.Dispose();
MessageWindow 需在 UI 執行緒建立,否則 Hwnd 無效。LoadIcon(GetModuleHandle(null), "#201547")。