使用Windows API有条件地显示多个气球 - Delphi中的系统托盘图标

时间:2016-07-29 13:30:05

标签: delphi delphi-2009 system-tray balloon-tip

我编写了一个程序,可以识别Windows系统中过时的软件,并通过与用户交互来更新它们。

它有一个软件更新程序,显示系统托盘图标并显示有关系统中安装的可用/下载更新和软件的气球提示。

问题是当每个任务都由它处理时,它无法显示多个气球提示。例如,当软件的更新可用时,它应该记住用户显示类似An update for Software Name is available.的气球,当用户选择下载并再次将其最小化到系统托盘时,气球提示应该再次显示类似{{1 }}

但是,我想知道如何只使用一个系统托盘图标来完成此操作?

我可以反复使用Updates are downloading...Click to view the Progress of Downloads.标志根据程序的当前状态更改气球提示吗?

我搜索了这个,我发现了一些例子,但对于Visual Studio和C ++。

这就是我在程序运行时尝试显示多个提示的方法:

NIM_MODIFY

但是,这是失败的,当程序运行时,我一次又一次地获得相同的气球提示(第一个).......

我不知道如何正确使用unit MainForm-1; ... const NIF_INFO = $10; NIF_MESSAGE = 1; NIF_ICON = 2; NOTIFYICON_VERSION = 3; NIF_TIP = 4; NIM_SETVERSION = $00000004; NIM_SETFOCUS = $00000003; NIIF_INFO = $00000001; NIIF_WARNING = $00000002; NIIF_ERROR = $00000003; NIN_BALLOONSHOW = WM_USER + 2; NIN_BALLOONHIDE = WM_USER + 3; NIN_BALLOONTIMEOUT = WM_USER + 4; NIN_BALLOONUSERCLICK = WM_USER + 5; NIN_SELECT = WM_USER + 0; NINF_KEY = $1; NIN_KEYSELECT = NIN_SELECT or NINF_KEY; TRAY_CALLBACK = WM_USER + $7258; PNewNotifyIconData = ^TNewNotifyIconData; TDUMMYUNIONNAME = record case Integer of 0: (uTimeout: UINT); 1: (uVersion: UINT); end; TNewNotifyIconData = record cbSize: DWORD; Wnd: HWND; uID: UINT; uFlags: UINT; uCallbackMessage: UINT; hIcon: HICON; szTip: array [0..127] of Char; dwState: DWORD; / dwStateMask: DWORD; szInfo: array [0..255] of Char; DUMMYUNIONNAME: TDUMMYUNIONNAME; szInfoTitle: array [0..63] of Char; dwInfoFlags: DWORD; end; type MainForm-1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private IconData: TNewNotifyIconData; procedure SysTrayIconMessageHandler(var Msg: TMessage); message TRAY_CALLBACK; procedure AddSysTrayIcon; procedure ShowBalloonTips; procedure DeleteSysTrayIcon; public end; var MainForm-1: TForm; implementation uses ShellAPI...,.....,; procedure MainForm-1.SysTrayIconMessageHandler(var Msg: TMessage); begin case Msg.lParam of WM_MOUSEMOVE:; WM_LBUTTONDOWN:; WM_LBUTTONUP:; WM_LBUTTONDBLCLK:; WM_RBUTTONDOWN:; WM_RBUTTONUP:; WM_RBUTTONDBLCLK:; NIN_BALLOONSHOW:; NIN_BALLOONHIDE:; NIN_BALLOONTIMEOUT: NIN_BALLOONUSERCLICK:; end; end; procedure MainForm-1.AddSysTrayIcon; begin IconData.cbSize := SizeOf(IconData); IconData.Wnd := AllocateHWnd(SysTrayIconMessageHandler); IconData.uID := 0; IconData.uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP; IconData.uCallbackMessage := TRAY_CALLBACK; IconData.hIcon := Application.Icon.Handle; IconData.szTip := 'Software Updater is running'; if not Shell_NotifyIcon(NIM_ADD, @IconData) then ShowMessage('System Tray Icon cannot be created.'); end; procedure MainForm-1.DisplayBalloonTips; var TipInfo, TipTitle: string; begin IconData.cbSize := SizeOf(IconData); IconData.uFlags := NIF_INFO; if ssHelperState = UpdatesAvailable then TipInfo := 'Updates are available to the programs installed on your Computer' + ' Click to see details.'; if ssHelperState = UpdatesDownloading then TipInfo := 'Updates are downloading in the background. Click to view the details.'; strPLCopy(IconData.szInfo, TipInfo, SizeOf(IconData.szInfo) - 1); IconData.DUMMYUNIONNAME.uTimeout := 2500; if ssHelperState = UpdatesAvailable then TipTitle := 'Updates are Available...'; if ssHelperState = UpdatesDownloading then TipTitle := 'Downloading the Updates...'; strPLCopy(IconData.szInfoTitle, TipTitle, SizeOf(IconData.szInfoTitle) - 1); IconData.dwInfoFlags := NIIF_INFO; Shell_NotifyIcon(NIM_MODIFY, @IconData); {Following code is for testing purpose.} IconData.DUMMYUNIONNAME.uVersion := NOTIFYICON_VERSION; if not Shell_NotifyIcon(NIM_SETVERSION, @IconData) then ShowMessage('Setting the Version is Failed.'); end; procedure MainForm-1.DeleteSysTrayIcon; begin DeallocateHWnd(IconData.Wnd); if not Shell_NotifyIcon(NIM_DELETE, @IconData) then ShowMessage('Unable to delete System Tray Icon.'); end; procedure MainForm-1.FormCreate(Sender: TObject); begin AddSysTrayIcon; ShowBalloonTips; end; procedure MainForm-1.FormDestroy(Sender: TObject); begin DeleteSysTrayIcon; end; ... end. NIN_BALLOONSHOW标志。因此,在此先感谢您的重要帮助。

1 个答案:

答案 0 :(得分:1)

为什么要手动声明所有内容? Delphi 2009已经有Shell_NotifyIcon() API的声明。他们在ShellAPI单位。除了uVersion字段(在Delphi 2010中添加)之外,它声明了您尝试使用的所有内容。您没有使用guidItemhBalloonIcon字段,因此请不要在此担心。 uTimeout字段存在,并且由于它包含在与uVersion的联合中,因此数据大小不会更改,因此当您要使用{{1}时,可以使用uTimeout (或者您可以定义自己的联合并键入字段,但这是过度的)。您当然不需要重新声明整个API。

每次拨打uVersion时,您都会重复使用相同的IconData变量,这很好,但如果您的帮助状态不是您要清除Shell_NotifyIcon()szTip字段不是szInfoTitleUpdatesAvailable,因此托盘图标会一直显示您设置的最后一个提示/气球。当你不再需要提示/气球时,你需要清除这些字段。

UpdatesDownloadingNIN_BALLOONSHOW不是标志。它们是发送到托盘图标的已注册NIN_BALLOONHIDE的通知。要接收通知,您需要填写HWNDWnd字段并启用uCallbackMessage标记。

此外,您需要处理WM_TASKBARCREATED消息。如果资源管理器因任何原因重新启动(崩溃或被用户杀死),则会重新创建任务栏,因此您必须重新添加托盘图标。

此外,请确保您的消息处理程序将任何未处理的窗口消息传递给NIF_MESSAGE,或者您可以锁定系统,或者至少锁定您的应用程序。

最后,Delphi 2009是Delphi的Unicode版本,但是代码的某些部分没有正确处理Unicode。具体来说,使用DefWindowProc()填充szTipszInfoTitle时,您需要使用StrPLCopy()而不是Length()。副本以字符数表示,而不是字节数。

话虽如此,尝试更像这样的事情:

SizeOf()