Skip to content
⌘ NSIS Forum Archive

Tray icon

113 posts

Afrow UK#

Tray icon

It would be great if anyone can show me how to get the installer to display in the System Tray area on the Windows task bar.
I doubt this is possible, but it would sure be nice for my program - it downloads updates for my game, which can take hours (if many updates)

Thanks

-Stu
Vytautas#
You should be able to do it using the APIs and system plugin. Not sure of the actual call but will check it out.

Vytautas
Vytautas#
I found some info about Shell_NotifyIcon at this site. I know it's for VB but someone should be able to convert it to system plugin code.

Vytautas
Afrow UK#
I know hardly anything about using System plugin let alone VB.

Help would be much appreciated!

-Stu
RDaneel#
Well, probably the best thing I can do for you (besides writing your installer for you 🙂 ) is to give you a conceptual model for "tray stuff".

First off, things are fairly simple, and do indeed revolve around the Shell_NotifyIcon API call... the one problem I can see has, I think, been discussed here before - how to receive [Windows] messages sent to your NSIS installer process.

Anyway, at its simplest, when you want to go into the tray, you set your app (NSIS installer in this case) to be invisible by doing a Win32 API call of ShowWindow(SW_HIDE), and immediately tell Windows to display your icon in the tray, using the Shell_NotifyIcon call.

Flipping back to non-tray operation is just the reverse - set your main window back to the visible state, and tell Windows to delete your icon from the tray.

Now, the tricks - when you first go into the tray, along with an icon handle, you tell Windows to use some user-defined Windows message of your choice to inform you of things the user does to your tray icon, like left- or right- clicking it etc. Clearly, if you are unable to get your hands on this message when Windows sends it to your NSIS installer, you will have a problem communicating with your user. 🙁 Hopefully someone else (Joost?) can assist you with this...

Finally, you will need to feel comfortable using the System plugin, both for simple calls, and for creating/interpreting the data structures used with the Shell_NotifyIcon API call... not to mention checking out the documentation on the handful of Windows API calls involved:

* Shell_NotifyIcon
* ShowWindow
* LoadImage (for getting your icon handle, although you might have some other access to your icon already buried in your NSIS installer).

Good luck! 😁
Afrow UK#
Thanks for your help!
The reason I cannot start to properly understand the System plugin, is due to the fact that I know nothing about C++, C or hardly any VB!

I know that Brainsucker would have the ultimate solution to this straight off, but he seems to be away atm 🙁

-Stu
Joel#
The thing is in this part:

Public Type NOTIFYICONDATA
cbSize As Long
hWnd As Long
uID As Long
uFlags As Long
uCallbackMessage As Long
hIcon As Long
szTip As String * 64
End Type
is important for the API call:
Declare Function Shell_NotifyIcon Lib "shell32.dll" \ Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Long
I don't think that's possible with NSIS...
A less, as you wrote, Mr. Brain popup a good example code solution.
Vytautas#
I am 99% sure that this will be posible with nsis. The declaration can be done using the system dll as it only allocates memory. It's too late tonight for me to this this through, almost 03:30 in the morning. I'll have another look tomorrow.

Vytautas
brainsucker#
You could create taskbar icon, modify or delete it, but it is hard to react to it. However:


; ---------- Some declarations -----------
;typedef struct _NOTIFYICONDATA {
; DWORD cbSize;
; HWND hWnd;
; UINT uID;
; UINT uFlags;
; UINT uCallbackMessage;
; HICON hIcon;
; TCHAR szTip[64];
;}
!define stNOTIFYICONDATA '(&l4, i, i, i, i, i, &t64) i'

!define NIF_MESSAGE 0x00000001
!define NIF_ICON 0x00000002
!define NIF_TIP 0x00000004
!define NIM_ADD 0x00000000
!define NIM_MODIFY 0x00000001
!define NIM_DELETE 0x00000002

; ----------- To Add icon ---------------
; use [t "iconfilename"] instead of [i 32514] to specify your icon,
; or if you already have your icon handle you can use it instead of r2
; at structure creation time
System::Call 'User32::LoadIconA(i 0, i 32514) i .r2'
System::Call '*${stNOTIFYICONDATA}(, $HWNDPARENT, 0, ${NIF_TIP}|${NIF_ICON}, 0, r2, "How do you like this?") .r0'
System::Call 'Shell32::Shell_NotifyIcon(i ${NIM_ADD}, i r0) i.r1'

; ----------- To Modify icon ---------------
System::Call '*$0${stNOTIFYICONDATA}(,,,,,, "Another icon tip...")'
System::Call 'Shell32::Shell_NotifyIcon(i ${NIM_MODIFY}, i r0) i.r1'

; ----------- To Delete icon ---------------
System::Call 'Shell32::Shell_NotifyIcon(i ${NIM_DELETE}, i r0) i.r1'
System::Free $0
Afrow UK#
Hmm, theres a problem with the code to unload the tray icon.
Sometimes it works, sometimes it doesn't, but it always brings up a crash.

Can anyone see whats wrong with it?

Thanks, this is excellent!

-Stu
Joel#
Where do you put:

System::Call 'Shell32::Shell_NotifyIcon(i ${NIM_DELETE}, i r0) i.r1'
System::Free $0
RDaneel#
Well, brainsucker *is* Mr System plug-in, as I understand it, but the rest of us aren't, so there may be some less-obvious things to look at here 🙂

1) so we are all clear on what is happening, the Shell_NotifyIcon API call needs a NOTIFYICONDATA data structure passed in to it EVERY time... since $0 is being used to hang on to a pointer to this structure, you must make sure that $0 is not overwritten by any other code during the time between the NIM_ADD and NIM_DELETE calls

2) while the example shown is apparently using some magic in the System plug-in to allocate (and fill in) this data structure the first time (just prior to the NIM_ADD call), note that if you use the example code for the NIM_DELETE call, this data structure is released with the System::Free, and the whole initial sequence (the setup code for the NIM_ADD) must be executed again

3) when initializing the structure, the first element *must* be filled in with the size in BYTES of the entire structure... this should be happening with the "&l4" in the structure def, but has the actual value been verified? Actually, there are some semi-trick cases to consider here, since the size specified is used by Windows to decide which version of the Shell_NotifyIcon API to offer/use... the example code will *probably* make the system think that you are only using the "ancient" Win95/WinNT features of this API, which would mean that the example structure will work 😉

4) the NIM_MODIFY sequence will (as shown) modify the TOOLTIP, not the ICON (either or both are possible)... just a comment on the comment 😁

5) finally, *don't* blow off brainsucker's first line of the example post - the "but it is hard to react to it" is echoing my earlier remarks about receiving the Windows messages sent back to your NSIS installer to tell you when the user "does something" to your tray icon... if it is your intention to use the tray completely non-interactively, fine - otherwise, this issue will have to be addressed 🙁
Afrow UK#
The idea was so that the installer would not be listed on the task bar, but be instead an icon on the task bar instead.
The user would be able to right/left click to open the installer again.

I have changed it to use $4 instead (haven't used that in my script)
It now does not crash, but it still dissapears on mouseover.

Thanks

-Stu
Afrow UK#
Ops,

The idea was so that the installer would not be listed on the task bar, but be instead an icon on the sys tray instead.
Afrow UK#
Well, the code seems to work on Win98SE, but on WinXP the icon just dissappears on mouse-over.

-Stu
RDaneel#
You haven't mentioned whether you think the system is just disappearing your tray icon on you, or your code to make it go away is being invoked... when the icon goes away (on XP), does your app go away too (i.e., it's no longer on the system tasklist)?

Why don't you put debug output to the NSIS log page when *any* of the Shell_NotifyIcon calls are made - this is a way to get more data on what may be happening. Also, if you are worried about being able to *see* the log because your NSIS installer is invisible, just don't turn off visibility to start with when you first make the icon show in the tray. 🙂
Afrow UK#
The tray icon dissappears on mouseover (like I said) while the program is running, not when it has been shut down.
This happens on WinXP only.
The icon shows it's label correctly (displays the text) on mouseover on Win98/NT.
Joel#
Ok...
according to my recent research about system plugin...
Shell_NotifyIcon it's a call like Visual Basic handles..
Shell_NotifyIconA is the called for the plugin.
RDaneel#
Ummm, "Major Dude", get the trace/debug info as suggested above. It is more likely that your NSIS code is [inadvertently] removing the tray icon than that XP is spontaneously doing it. 😁

"Forum King", the real deal is that most of the Win32 API calls that handle text actually have *2* entry points: one with "A" appended, and one with "W".

In this particular case, then, the Shell32 DLL has both Shell_NotifyIconA and Shell_NotifyIconW. There *is* no "Shell_NotifyIcon" version of the call in reality - in programming land, your development environment maps this generic version of the name to one of the real ones... either the "A" version for ASCII text, or the "W" version for Unicode.

So, if things work at all as shown in brainsucker's example, I would expect it is because the System plug-in, when it fails on a GetProcAddress call, automatically retries with "A" appended to the supplied API entry point. 😉
Afrow UK#
After placing brainsuckers' code into an empty script, that does not use any variables (except for the System code itself) my problem persists where the icon just dissappears on mouse-over.

-Stu
brainsucker#
Afrow UK: It's the most likely you've forgotten to add

SetPluginUnload alwaysoff

option at the script start (or /nounload to every system call).
Don't forget to add

SetPluginUnload manual

before the last system call (or fake System::Free 0 call).

RDaneel:
0. thanx for you comments 🙂
1. I've spent to many time debuggin &l option, so there is no one chance it'll fail!!! 😉
2. System does nothing with the letter A at the proc name end, I've just forgotten to add it... The way it works?... Hmm.. Shell32.dll contains proc version without any letters, may be because it could determine which structure (unicode or ascii) passed to it by cbSize member (there are no other string params, as you see).

P.S. I'll post notifyicon plugin ASAP, which will solve all the problems (the icons at TNA and removing the window from taskbar).
Afrow UK#
OMG BRAINSUCKER!!!!
/me saw the last P.S.

You are the most amazing guy on the net - seriously, you writing a plugin just like that wow!!

So, will this plugin have support for simple sys tray icon click - opens program, or even more!?

-Stu 😳 🙂 🙂