Archive: Tray icon


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


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


Shell_NotifyIcon is the API call...


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


I know hardly anything about using System plugin let alone VB.

Help would be much appreciated!

-Stu


Can anyone help me on this one please :p

-Stu :)


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! :D


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


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.

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


Thank you :)

#me awaits patiently

-Stu


I notice brainsucker is online atm :)...

-Stu :p


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


I notice brainsucker is online atm :)...
;)

wow! it's easy...easier than Visual Basic ;)
Cool dude :up:


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


Ok, also it seems that if I hover my mouse over the tray icon, it dissapears too.

-Stu


Where do you put:


System::Call 'Shell32::Shell_NotifyIcon(i ${NIM_DELETE}, i r0) i.r1'
System::Free $0

I have placed it in my abort/instsuccess functions.

-Stu


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 :D

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 :(


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


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.


Well, the code seems to work on Win98SE, but on WinXP the icon just dissappears on mouse-over.

-Stu


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. :)


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.


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.


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. :D

"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. ;)


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


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).


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 :o :) :)


Originally posted by brainsucker

2. System does nothing with the letter A at the proc name end
Just to be clear: I used the term "A" for the conversion from
Visual Basic 4/5/6 API declare function to system plugin syntax :)

brainsucker,

You certainly are an energetic person! :)

Really, be careful with the A/W thing - in general, the A/W naming convention *is* the rule in Win32 system API calls that have any dealings with text, whether as parameters, or in this case, in a structure that is a parameter.

As it happens, for *some* of the API calls, an additional entry point (without A/W) is defined to be the same as the entry point for the "A" version of the call... but not all of them!

So, while Shell_NotifyIcon does have the "extra" entry point, others do not (e.g., ShellAbout and ShellExecute).

Hmmm... might you want to include the strategy on failed GetProcAdress calls that I mentioned earlier (you would only need to make this change in one place)? If you/we can convince yourself/ourselves that the "A" version is probably what the NSIS scripter actually meant to use, this *could* save some confusion - at the cost of further obscuring how things actually work, of course. :D


Afrow UK: I'm thinking about right click menu, but it'll have a little sense anyway (there are 2 ways I see, and both are ugly: 1. assign some variable some value on menu selection, and then check it thru the script 2. Pool some plugin function which will return menu status). Any ideas about additional functionality?

RDaneel: :)
"Really, be careful with the A/W thing"
:) I've just forgotten that damn letter!!!! ;) :)

System+A: ok... good idea.


I think it wouldn't be possible for nsis programs to recieve the values from the menu.
Because NSIS only runs the codes in different places (in oninit, after a page etc) not constantly...

We can forget the return values I suppose.
It's just up to the dll now to bring the program on-top when the user clicks on the sys tray icon.
You could allow additional defines when calling the plugin (no idea what plugin is called but,)

TrayIcon::Load "Icon" "Hover title"
TrayIcon::Menu "TI_MINIMIZE, TI_OPEN" "Menu header text"
TrayIcon::Close

Going over the top would be, I dunno...

TrayIcon::Menu "SubMenu('Readme'), Menu('Open Readme', exec $INSTDIR\readme.txt)"

This would create a submenu, which on moueover brings up a second menu which inturn has a button to open the installer readme.

lol

-Stu :)


Afrow, where did you put the creation code? It must not be in .onInit because in there $HWNDPARENT is not valid.


Thanks, but after moving it to GUIInit or one of my custom pages, the installer would just crash onInit, and wouldn't even reach any dialogs.

-Stu


May I ask how the plugin is going?
I have till next weekend to prepare for the release of my 12 map D-Day campaign, along with the release of my NSIS installer.

It would be nice to get the tray icon working by then, but I can always release the installer (program) again later (It has built in updater).

-Stu


Sorry... I've got some immediate work (programming USB device).... so ASAP. ;(

BTW, would you like to remove program from taskbar on minimize only, or at any time?


Well, it at the moment I've used System code to remove the taskbar item perminantly for the settings tab (which is executed with ExecWait)
But, indeed yes, it would be nice if the taskbar item dissapeared on minimize.

-Stu


Hide on minimize is 10000000 times easier :) I've f*cked all the Sunday of the last week with hiding at normal state (WS_EX_TOOLBOX sux - make new styles and so on, and other techiques work hard with nsis window).
I'll release tomorrow (i think) minimal version with hide on minimize and no right click menues (but with balloon tooltips for example ;).


Archive: Tray icon


Now, thinking about it, will it be able to work like this:

Installer is ran, and sys tray icon is made (installer is also shown, and task bar item)
User clicks on sys tray icon to show installer ui and show the task bar item.
Sys tray icon stays until installer is closed.
On installer minimization, task bar item dissappears (along with installer ui) Sys tray icon stays.

Thanks for everything!

-Stu


Is it the question? Yes, it will be able. That is the most natural behaviour, I think.


Did this plugin ever get made? Sounds pretty useful for my purposes. I basically have two installs (one that downloads the second) and it would be nice to have a tray icon that shows progress (and options) for while the second setup is downloading.


Brainsucker is still working on it (I assume)

I went and released my program (installer) b1 without the Task Bar functionality.
When the plugin is finished, I can simply upload the new version of my program (using the plugin), and when everyone runs my program it will download the update for them.

-Stu


Is this still being worked on?

-Stu :confused:


Afrow :) Hope you'll forgive me that delay... I've got so many immediate work... If I'll finish it (work) tomorrow (today) (in basic), I'll try to bring plugin online this evening (there is nothing to do with it actually, in simpliest form (hide on minimize) at last). I'm really sorry...


No theres honestly no rush.
I was just hoping that it hadn't been forgotten!

Thanks for showing that it's still there!

-Stu :)


Anyone home!
Just posting to keep this topic... Alive.

-Stu :eek:


So... finally... My conscience won the fight with me :)
Sorry again for such a long delay...
Hope it will satisfy all your needs.


brainsucker:
Your Notify Icon Plugin looks awesome!


why is the traybar called 'taskbar notification area'? Regular taskbar also notifies that some program is running.

Show me the light! :)


Who knows... You probably should sue Microsoft ;)


Great work, and thanks.
Right now however, when calling NotifyIcon::Icon r, my installer crashes.

-Stu


Which system you are using? works fine for me under winxp. will check under 98.


I am also on Windows XP-Pro.
See attached script.

I'm using the remove call in .onInstSuccess .onUserAbort and my custom Abort function.

-Stu


What about demo script?


Never unload UI plug-ins from .onUserAbort and .onInstSuccess, use .onGUIEnd.


Testing script
\/


Ah thanks Kichik, I shall try that.

-Stu


Well, after using it in .onGUIEnd, the icon isn't removed at all.

Updated testing attachment

-Stu


It's probably because the window is already destroyed. The plug-in should check to see if the window is destroyed and self-desrtuct if that's the case. For now remove it in the last section.


What about when the user clicks cancel; use it in the custom page function if IO pops cancel?

-Stu


Huh, I will discuss with Kichik what to do... Problem found.


There is also a problem that the installer doesn't close automatically, so the tray icon will get distroyed before the install has properly finished.

-Stu


Well, the good news is that it doesn't crash when called inside the custom page after the user clicks cancel.
Now, I'll wait for the self-distruct sequence :)

-Stu


Afrow, could you please test BrowseForFolder and BrowseForFolderNew rountines separately (be sure to update the system and exehead to latest cvs versioun).

p.s. updated NotifyIcon.


Afrow UK: a small tip: you could skip constant parameters, for example if you use the same icon every time you could skip "i" "103". The same goes for tip at your dday.

Also, IMHO: poping up a info balloon message for every file you are downloading could be a little disturbing for user, may be you should move that info to tip, and popup only on "completed" or "failed" messages?


Thanks for the tips.
They are good ideas!

-Stu


Well, it seems that the problem is fixed.
I am now calling the plugin to remove the notifyicon from .onGUIEnd only, and it works fine, without a crash.

Many D-Dayers are looking forward to the new installer.
Thanks for writing this excellent plugin!

-Stu


Mind writing an archive page for it Afrow? I'll upload the zip to the archive.

[edit] uploaded to http://nsis.sourceforge.net/archive/...NotifyIcon.zip [/edit]


http://nsis.sourceforge.net/archive/...02&instances=0

-Stu


it appears, that the systray icon does not get displayed properly.

my icon file consists of various sizes (including 16x16 pixels). the script uses the icon from the executable (103). the icon in the systray looks like a badly downsampled version of a larger icon. why doesn't it simply display the included 16x16 icon?


having opened the .exe in a resource editor, i figured 103 is the id of the icon. now is there a way to further specify the icon size to use for the systray?


Originally posted by n0On3
why is the traybar called 'taskbar notification area'? Regular taskbar also notifies that some program is running.

Show me the light! :)
Find out here.

mmm.... those reasons didn't convince me.

I suspect this is another lost war.

He can join Richard Stallman who fights to make people call open-source "free software" and Linux "GNU/Linux".

Thanks for the link, interesting read.


That's one of Windows 95 developers, you won't find a better answer ;)


killahbite: 103 is the number of icon group. and i know no particular way to specify which icon from group to use (the approriate icon should be selected by windows).


the current version downsizes the 32x32 icon to 16x16. it should load the default 16x16 icon instead!


killahbite :) sorry, i couldn't help you. Create additional icon group from one 16x16 icon (it shouldn't take much space) and use it as NotifyIcon icon.


Specifying 16x16 in the desired size should do it. According to Wine source code, LoadImage searches for the best match.


Archive: Tray icon


bright idea Kichik :)
I'll check and update a bit later...


Fixed. Now uses 16x16 as default icon size. The previous behaviour could be selected by '.' flag before f, s, or i.


Uploaded.


My icon file has a 16x16 icon in it too, but it shows up correctly on the older dll.
Maybe it's the program you used to create the icon.
Also, I'm sure the order of the icons inside the file can affect which icon(s) is used.

-Stu


would it be possible to add a flag, that minimizes the installer to the tray when one clicks on the minimize icon?


Would it be possible to add a feature that when you click on the balloon it calls a function? I have a balloon tip appear when an app. is run silently, and I would like that when you click on the tip it shows a message box asking the user if they would like to restart.


Originally posted by flyakite
Would it be possible to add a feature that when you click on the balloon it calls a function?
I would love so such an option.

I think I found a bug:
When I run NotifyIcon::Icon /NOUNLOAD in the .onInit or with SilentInstall enabled, at the moment the mouse goes over the trayicon, it simply disappears.

I think it's already mentioned in this topic (or in the readme I can't remember) but you can't call the plugin in .onInit because at that point the GUI has not been initialised yet. Notification icons are tied with a Windows GUI and therefore you should call the plugin while the window is in memory - in .onGUIInit. Also, to remove it call in .onGUIEnd.

-Stu


Where does it access the icon from?
With the default it works but not with my custom one
Does the icon need to be extracted with File


If you don't specify the default icon (105) you specify a full path to an icon file which logically you'd need to extract :).

-Stu


Instead of using X:\t could I use \t ?


Just extract the icon to $PLUGINSDIR and give it that path.

-Stu


Still doesn't work
I have extracted to C:\icon.ico
but still doesn't work
Using
NotifyIcon::Icon /NOUNLOAD "fpb" "C:\icon.ico" "START" "Balloon!" "Cool!"


Oops
Working now
Forgot to add y
:)


When you use this in conjuction with wansis, the skin window stays up.
Is there a way to fix this???


Originally posted by rmccue
When you use this in conjuction with wansis, the skin window stays up.
Is there a way to fix this???
Hey rmccue I knew it would be you when I saw the topic title on the NSIS homepage!

Hi Steve
But can anyone answer my q?


Maybe call a custom function on minimize and maximize


My program notfies the user if something happens and displays it in a balloon (yeah,.. really! :P)

But I want that if the user click on the balloon a certain action is performed, how do I do that?


There isn't a way I'm afraid.

-Stu


So I wonder how that (annoying) "Take the Windows Tour" balloon and the "Windows Update" ballon do it then, they launch Wizards/applications when you click on them...

I think this is the functionality that is sought.

I might take a look, it would be interesting to know its done.

Duncan


There is no way via a run-time plugin to call an internal NSIS function from some event. For this to be possible we'd need modifications to the original NSIS source code, or perhaps when compiler plugin support is added this will be possible. I doubt it will get implemented because this would add to installer overhead no doubt.

-Stu


Actually, you can already call NSIS functions from plug-ins. ExecuteCodeSegment is exported to plug-ins through the extra_parameters structure passed on as the fifth function argument. However, the scripting engine is not multi-threaded, so it's up to the plug-in to synchronize it.


Anyway, how would I get it to shrink the wansis window? I'm using FindWindow, ShowWindow in a custom function.


I need some help here... the plugin doesn't allow me to HideWindow and I can't get "p" nor "!p" params to work with the NotifyIcon.nsi that comes in zip file (v0.2).


I need to show the system tray icon during an upgrade process. The upgrade will be triggered using the silent switch to make it silent.
Is this feasible using the NotifyIcon plugin ? If not what are my options.


It's been a while since I looked at the code but it probably doesn't show any notification icon if the installer is silent. If that is the case you would need to modify the plugin to allow a force show option or something that overrides this behaviour. If you don't use the plugin you'll be using System with a lot of SendMessage lines (which the Win32 macros use internally) so it'd be pretty painful.

Stu


Yes it is a nice switch to have because on silent , this can be a kind of notification to the user .
I'm surely in dire need of this.