系統匣 (Taskbar Notification Area) 圖示不需 VCL TApplication 主視窗,僅需一個隱藏視窗處理回呼訊息 (WM_USER+1000),配合 Shell_NotifyIcon API 即可實現極小體積 (約 20KB) 的常駐程式。
RegisterClass 登記視窗類別,CreateWindow 建立隱藏視窗 (WS_OVERLAPPEDWINDOW + SW_HIDE)。Shell_NotifyIcon(NIM_ADD, ...) 註冊圖示、工具提示、回呼訊息號。GetMessage/TranslateMessage/DispatchMessage。WM_DESTROY (退出)、WM_COMMAND (選單項目)、自訂回呼 WM_MYCALLBACK (滑鼠左/右鍵點擊圖示)。SHGetDesktopFolder/IEnumIDList) 動態建立,另加「離開」項目。ShellExecute 執行。Shell_NotifyIcon(NIM_DELETE) 移除圖示。
const WM_MYCALLBACK = WM_USER + 1000;
CM_EXIT = 100; CM_ABOUT = 101;
var MainWindow: HWND; IconData: array[1..100] of String;
function WndProc(Wnd: HWND; Msg, wParam, lParam: Integer): Integer; stdcall;
begin
Result := 0;
case Msg of
WM_NCCREATE: Result := 1;
WM_DESTROY: PostQuitMessage(0);
WM_COMMAND:
if wParam = CM_EXIT then PostMessage(Wnd, WM_DESTROY, 0, 0)
else if wParam = CM_ABOUT then MessageBox(0, 'About...', 'Tray', MB_OK)
else OpenDesktopIcon(wParam - CM_ABOUT);
WM_MYCALLBACK:
if lParam = WM_LBUTTONDOWN then ShowIconPopupMenu
else if lParam = WM_RBUTTONDOWN then ShowAboutPopupMenu;
else Result := DefWindowProc(Wnd, Msg, wParam, lParam);
end;
end;
procedure AddTrayIcon;
var NID: TNotifyIconData;
begin
FillChar(NID, SizeOf(NID), 0);
NID.cbSize := SizeOf(NID);
NID.Wnd := MainWindow;
NID.uID := 0;
NID.uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP;
NID.uCallbackMessage := WM_MYCALLBACK;
NID.hIcon := LoadIcon(HInstance, 'MYICON');
StrCopy(NID.szTip, 'My Tray App');
Shell_NotifyIcon(NIM_ADD, @NID);
end;
TTrayIcon (Delphi 2009+) 或第三方元件 (如 TrayIcon 元件),開發效率高但體積較大。