Click to See Complete Forum and Search --> : VB6 System tray icon / systray
Ellis Dee
Dec 15th, 2009, 09:39 PM
The solution attached to this post allows for basic system tray functionality. You can create your systray icon (and change it on the fly) from a form icon or by loading/drawing an image on a 32x32 pixel picturebox. There is easy support for a popup menu, as well as showing standard balloon tips. That's all there is to basic systray icons.
If that's all you need, the attached demo project is for you. No dlls or ocxs; it's all pure native VB6, meaning fewer headaches for the developer. The logic is contained in a class, and is exposed to the developer in a form.
On to the demo:
Ellis Dee
Dec 15th, 2009, 09:40 PM
Overview
As we can see from basDemo.bas, firing up the system tray couldn't be simpler:Option Explicit
Private Sub Main()
If App.PrevInstance Then Exit Sub
Load frmSysTray
End SubYou pretty much never want two instances of a tray app running, so we use Previnstance to cancel multiple instances. If you decide to abandon the Sub Main approach and just make frmSysTray your startup form, add the following line of code to the very beginning of the Form_Load event:
If App.PrevInstance Then Unload Me
Events
The systray class fires messages directly to frmSysTray, so when you want to capture feedback from the tray icon, add event handlers to the form as if you were working with any regular control. Select "SysTray" from the left code dropdown -- where it typically starts with "(General)" -- and then choose any of the events you like from the code dropdown on the right. Supported events are:
BalloonClicked()
BalloonHide()
BalloonTimeout()
DoubleClick()
LeftClick()
RightClick()
The RightClick() event is where you typically open a popup menu, which is exactly what the demo does. Define your tray icon's popup menu in frmSysTray and handle the events from it there as well, just as with any regular menu.
Note that LeftClick() can supercede DoubleClick(), so basically figure you can support one or the other.
Methods / Properties
In addition to the tray icon talking to your app, your app will want to talk to the tray icon. From within frmSysTray, you can access the SysTray class using the following methods/properties:
SysTray.Init
Call this once in frmSysTray's Form_Load event to connect the class to the form. Optionally send a tooltip to display if the user hovers their mouse over the tray icon.
SysTray.MouseMove
This is an internal method you don't need to (and shouldn't) mess with. It is how the class captures messages from Windows, which in turn get interpreted and sent back to the form for you to use.
SysTray.ShowBalloonTip
Works the same as a msgbox. Send it a message, icon and title, plus optionally send the number of milliseconds it should stay on the screen before closing itself. Default is 30 seconds.
SysTray.SetIcon
Send this method a form and the tray icon will use that form's icon.
SysTray.DrawIcon
Send this method a picturebox and the tray icon will convert the picture into an icon. Optionally send a color to be used for transparency. This lets you draw the icon yourself using Line() commands if you need fine control, like say an activity indicator. Or you can use LoadPicture to work with image files. Note that the picturebox is 32x32 and the tray icon is typically only 16x16, so your images will likely get squished.
SysTray.TooltipText
Simple property to set the tooltip text if you need to change it during runtime.
As written, the SysTray object is only available from within frmSysTray. If you want to access the tray in a different form or from a module or class, change the declaration at the top of frmSysTray to public:
Public WithEvents SysTray As clsSysTray
Now you can access it directly from anywhere in your project by first specifying the form. eg:
frmSysTray.SysTray.ShowBalloonTip "Hello, world!"
Ellis Dee
Dec 15th, 2009, 09:41 PM
For more information on working with the system tray:
Using the System Tray (http://www.codeguru.com/columns/VB/article.php/c6547/) by Paul Kimmel (CodeGuru.com)
Animated system tray (http://www.vbforums.com/showthread.php?t=300765) by Wokawidget
MSN Messenger Style Systray Notification Messages (http://www.vbforums.com/showthread.php?t=320639) by Wokawidget
Showing Balloon Tips (http://www.vbaccelerator.com/home/VB/Code/Libraries/Shell_Projects/SysTray_-_The_Easy_Way/article.asp) by Steve McMahon (vbAccelerator.com)
Here (http://www.vbforums.com/showpost.php?p=3681584&postcount=5) is a sample application using the code from this thread.
LaVolpe
Dec 16th, 2009, 01:34 PM
If you want some tips on Vista/Win7 compatibility, here are a few. I've been doing some research on this topic recently.
1. Vista offers users option to display a popup window instead of a tooltip. In Vista, hover over your Sound icon and the new "tip" should show. In order to know that the window should be displayed, new msgs were added: NIN_POPUPOPEN and NIN_POPUPCLOSE. Additionally, Vista can send the mouse coordinates back with the message.
:: The above requires at least two modifications
a. There is now a NOTIFYICON_VERSION_4 = 4 constant vs just version 3
b: Subclassing is required now, because one can no longer use VB's MouseMove events to trap the messages. With v4, wParam contains both icon id and message, lParam contains the X,Y coords
2. Vista offers a couple of other balloon options too. One can select a 32x32 icon or 16x16 icon for the balloon. In fact, the balloon icon can now be any icon you want and is no longer limited to those in WinXP and earlier. Some new constants for Vista
NIIF_LARGEICON = &H20
NIIF_RESPECT_QUIET_TIME = &H80
NIF_REALTIME = &H40
NIF_SHOWTIP = &H80
3. The NOTIFYICONDATA structure grew by 4 bytes in Vista. The balloon timeout is no longer honored/used
Some comments on your project, if you don't mind.
1. There are more messages that can be received
WM_CONTEXTMENU, all buttonclicks for the MiddleButton and XButton, NIN_KEYSELECT & NIN_SELECT
2. NIIF_USER is not defined in you BalloonIconEnum. If this option is chosen (XP and higher), the app icon is used.
3. FYI: You can offer a HideBalloon method if desired. Simply show a balloon with a null message and it will kill an existing balloon for the same icon.
4. Though not commonly used, it could be easy for you to offer multiple icons (i.e., 2 icons for same app displayed at same time) if you chose to do so.
Condomx
Dec 16th, 2009, 09:27 PM
if i want to change the icon in the system tray where should i go and what should i edit?
Ellis Dee
Dec 17th, 2009, 12:11 AM
if i want to change the icon in the system tray where should i go and what should i edit?Set the form icon in the form frmSysTray, and then from inside the form call SysTray.SetIcon Me.
Some comments on your project, if you don't mind.
1. There are more messages that can be received
WM_CONTEXTMENU, all buttonclicks for the MiddleButton and XButton, NIN_KEYSELECT & NIN_SELECT
2. NIIF_USER is not defined in you BalloonIconEnum. If this option is chosen (XP and higher), the app icon is used.
3. FYI: You can offer a HideBalloon method if desired. Simply show a balloon with a null message and it will kill an existing balloon for the same icon.
4. Though not commonly used, it could be easy for you to offer multiple icons (i.e., 2 icons for same app displayed at same time) if you chose to do so.By all means. I just discovered this technique a couple days ago, so I'm far from an expert or anything.
1. What is ContextMenu, and how does it differ from RightClick? KeySelect? How do you use the keyboard with the system tray? I don't really understand any of the constants from this point; a little help?
3. Sweet, I looked around for how to do that. Clever. It won't disappear until it's been open at least 10 seconds, but still better than nothing.
4. What's the thinking behind having two icons display at the same time? I don't follow.
LaVolpe
Dec 17th, 2009, 08:22 AM
1. What is ContextMenu, and how does it differ from RightClick? KeySelect? How do you use the keyboard with the system tray? I don't really understand any of the constants from this point; a little help?
With WinXP+, WM_ContextMenu was added & simply means rightclick. You still get the right down/up, but get WM_ContextMenu also.
KeySelect is odd. Here is how you can test it in XP.
:: Click that tray icon/circle that shows/hides tray icons. Leave mouse over the circle/icon
:: Use right arrow and move over the various icons. Pressing Space or Enter will trigger a KeySelect. Honestly, why would someone navigate the system tray that way?
3. Sweet, I looked around for how to do that. Clever. It won't disappear until it's been open at least 10 seconds, but still better than nothing.With Vista, it is immediate. Maybe setting both the balloon title & message may make it immediate in XP and below? Curiosity.. will test this myself later.
4. What's the thinking behind having two icons display at the same time? I don't follow.Not many apps do this. Avast anti-virus app does. One is used primarily for database notifications/actions while the other is used for app settings. Avast was smart enough to allow user to combine both icons to a single icon. Personally, I don't want an app adding multiple icons to my tray, but IMO should be a user's choice. I think in your project, just creating another systray form would do the trick. In my classes, I use the .UID member of the tray structure to identify each tray icon created.
Here are 3 MSDN reference I used for most of my research:
The NOTIFYICONDATA structure/description (http://msdn.microsoft.com/en-us/library/bb773352%28VS.85%29.aspx)
The Shell_Notify API call and added remarks (http://msdn.microsoft.com/en-us/library/bb762159%28VS.85%29.aspx)
Tray Message meanings (http://msdn.microsoft.com/en-us/library/bb762159%28VS.85%29.aspx)
Ellis Dee
Dec 17th, 2009, 09:20 AM
With Vista, it is immediate. Maybe setting both the balloon title & message may make it immediate in XP and below? Curiosity.. will test this myself later.On second thought, I don't actually know that it isn't immediately cleared on XP if you send a blank balloon. I was reacting to the one-balloon-at-a-time functionality of the system tray, where if you stack up a bunch of messages they will only appear one at a time, waiting the minimum time (10 seconds) before closing each. If you send a blank balloon it may well simply close the currently open one. I'll test it and update the project with a new method if it does.
I really appreciate the feedback, especially those MSDN links. I wanted to create a good codebank thread for simple system tray functionality. The ones I found were all super-advanced (animated? Messenger?) and not practical for those who just want a little icon to show up and be clickable. heh. This thread should serve that need well, as a nice jumping off point for all things systray.
Ellis Dee
Dec 17th, 2009, 09:23 AM
:: Use right arrow and move over the various icons. Pressing Space or Enter will trigger a KeySelect. Honestly, why would someone navigate the system tray that way?Accessibility for the disabled. Microsoft was probably required by law to add that functionality.
Edgemeal
Dec 19th, 2009, 04:13 AM
Is it possible to show the balloon without that exit button in the top-right corner?
In one of my apps the balloon only pops up to notify the user, clicking on the balloon doesn't do anything except close the balloon and set focus back on the form that was in use.
The problem is setting focus to a form after receiving the balloon "exit" click message, setfocus calls are ignored. If the user clicks the balloon setfocus works fine. What gives?
EDIT:
I tried this but when the balloon exit button is clicked the forms titlebar just flashes.
Case BalloonClick, BalloonExit
If Form1.WindowState <> 1 Then SetForegroundWindow Form1.hwnd
Ellis Dee
Dec 19th, 2009, 11:09 AM
Not sure offhand, but my gut reaction is the standard tried-and-true work-around: timers. Kludgy I know, but for a temporary solution, consider using a timer with an interval of around 100. Have the BalloonExit event enable the timer, and have the timer do the setfocus and then turn itself off. Whatever it is about the event procedure that ignores the setfocus call will get purged as that event is allowed to end naturally. The timer then does its own independent thing, meaning it should be able to setfocus without issue.
Hopefully that will work well enough to tide you over until a real solution can be found.
Ellis Dee
Dec 30th, 2009, 07:17 PM
Is it possible to show the balloon without that exit button in the top-right corner?After playing around with it for a bit for an app I'm writing, yes, just don't send a title. When you don't send a title the icon is ignored too and the only thing displayed is the message text.
On an unrelated note, the timeout setting seems to be ignored and it just stays open forever. I've added a second timer to frmSysTray that sends a blank message, immediately clearing the balloon tip. I then added three lines to the end of clsSysTray.ShowBalloonTip that allows leaving the balloontip open for any amount of time you like up to a minute:frmSysTray.tmrHide.Enabled = False
frmSysTray.tmrHide.Interval = plngTimeout
frmSysTray.tmrHide.Enabled = TrueExpect an updated attachment in a week or two after I've worked out all the kinks to everything.
Edgemeal
Dec 31st, 2009, 05:13 PM
After playing around with it for a bit for an app I'm writing, yes, just don't send a title. When you don't send a title the icon is ignored too and the only thing displayed is the message text.
I tried that with my balloon code and it does get rid of the exit button and the balloon auto closes after about 5-10 seconds if I do something, otherwise it seems to just stay open forever like you say which is actually how I'd want it to work anyway. I never even tried no title, good catch! :thumb:
vbeeeeer
Mar 5th, 2010, 09:59 PM
mods go ahead and delete
Condomx
Mar 7th, 2010, 09:51 AM
this is a nice thing from Ellis Dee.,kep up da gud work man.CHEER!
jeffrey4u
Jun 21st, 2010, 04:52 AM
i tried practicing it at home.
when i right-click on the icon at the taskbar after running the project, nothing happen. the only thing that keeps working is the tooltip n nothing more.
am using VISTA version of windows and i don't know if the windows has got something to do with it.
any help?
Edgemeal
Jun 21st, 2010, 11:48 AM
when i right-click on the icon at the taskbar after running the project, nothing happen. the only thing that keeps working is the tooltip n nothing more.
am using VISTA version of windows and i don't know if the windows has got something to do with it.
any help?
Don't have Vista here to test but one possible problem I see is the code expects the form to be set to pixel scalemode, if not then you need to convert X for the SysTray.MouseMove calls, maybe something like,..
Dim msg As Single
msg = ScaleX(X, ScaleMode, vbPixels)
SysTray.MouseMove Button, msg, Me
Ellis Dee
Jun 22nd, 2010, 04:54 AM
Upthread LaVolpe says that subclassing is required in Vista. Subclassing makes me wet myself, so I'm afraid I won't be much help with Vista support. If I can manage to get my hands on a Vista machine I'll try to take a look.
Edgemeal
Jun 22nd, 2010, 06:47 AM
I think LaVolpe is saying subclass is needed if you want to use a popup window instead of a tooltip in Vista. ?
Might want to try using a pic box for the tray handle and mouse_move events instead of the form, years ago I ran into unexpected results using the form for the tray, been using a pic box ever since and haven't had a problem/complaint.
jeffrey4u
Jun 22nd, 2010, 07:00 AM
ok am waiting .
try it on a VISTA mchine n help me solve mine.
thz
Ellis Dee
Jun 22nd, 2010, 10:30 AM
Might want to try using a pic box for the tray handle and mouse_move events instead of the form, years ago I ran into unexpected results using the form for the tray, been using a pic box ever since and haven't had a problem/complaint.jeffrey, to try this, replace the Init() function in clsSysTray with this:Public Function Init(ppic As PictureBox, pstrTooltip As String) As Boolean
Const NIF_MESSAGE = &H1
Const WM_MOUSEMOVE = &H200
Const NIM_ADD = &H0
With mtypIcon
.cbSize = Len(mtypIcon)
.hwnd = ppic.hwnd
.hIcon = ppic.Parent.Icon
.uID = vbNull
.uFlags = NIF_MESSAGE
.uCallbackMessage = WM_MOUSEMOVE
End With
Shell_NotifyIcon NIM_ADD, mtypIcon
SetIcon pfrm
Me.TooltipText = pstrTooltip
End Function
Then change Form_Load() in frmSysTray to this:Private Sub Form_Load()
Set SysTray = New clsSysTray
Me.WindowState = vbMinimized
DoEvents
Me.Hide
SysTray.Init Me.pic, "System Tray demo"
End Sub
Edgemeal
Jun 22nd, 2010, 05:14 PM
Ellis, you'll get an error since you are no longer passing the form to the Init func., maybe like this?...
Public Sub SetIcon(hIcon As Long)
mtypIcon.hIcon = hIcon
RefreshIcon
End Sub
Public Function Init(ppic As PictureBox, pstrTooltip As String) As Boolean
Const NIF_MESSAGE = &H1
Const WM_MOUSEMOVE = &H200
Const NIM_ADD = &H0
With mtypIcon
.cbSize = Len(mtypIcon)
.hwnd = ppic.hwnd
.hIcon = ppic.Parent.Icon
.uID = vbNull
.uFlags = NIF_MESSAGE
.uCallbackMessage = WM_MOUSEMOVE
End With
Shell_NotifyIcon NIM_ADD, mtypIcon
SetIcon ppic.Parent.Icon 'pfrm
Me.TooltipText = pstrTooltip
End Function
Ellis Dee
Jun 23rd, 2010, 04:17 AM
Good catch, thanks. I should know better than to post code freehand without actually trying it in VB.
I would have probably left the SetIcon() function alone and just sent ppic.Parent to it, but either way works.
sinac
Jan 12th, 2012, 01:01 PM
Hi, How to change font and font-size balloon?
Ellis Dee
Jan 14th, 2012, 07:40 PM
Hi, How to change font and font-size balloon?No clue, sorry.
vbforums.com
Copyright Internet.com Inc., All Rights Reserved.