Click here to Skip to main content
Email Password   helpLost your password?

Overview

The Tray Icon Info application lets you enumerate your system tray icons and rearrange their positions, so that you can have your more frequently used icons positioned to the left most side (or right most depending on your personal preference). I wrote this as I got used to having the MSN Messenger icon on the left most side of the tray and found it annoying and inconvenient when newly added icons pushed it to the right. I had to exit and restart MSN Messenger to reposition it where I wanted. This application simplifies things for me.

Supported OS

This application only works on Windows XP. It may run on Windows 2003 too, but since I wasn't sure and since I didn't have the option to test it out, I have a version check and the program exits if it's a non-XP OS. If anyone's interested, they can comment out the version check and run it in on 2003 - but I have no idea as to whether it'll work or not.

Notes

Technical notes

The trick used here is to enumerate the buttons of the ToolbarWindow32 window that represents the system tray. The following code is used to locate this window (routine FindWindow/FindWindowEx stuff) :-

HWND FindTrayToolbarWindow()
{
    HWND hWnd = ::FindWindow(_T("Shell_TrayWnd"), NULL);
    if(hWnd)
    {
        hWnd = ::FindWindowEx(hWnd,NULL,_T("TrayNotifyWnd"), NULL);
        if(hWnd)
        {
            hWnd = ::FindWindowEx(hWnd,NULL,_T("SysPager"), NULL);
            if(hWnd)
            {                
                hWnd = ::FindWindowEx(hWnd, NULL,_T("ToolbarWindow32"), NULL);
            }
        }
    }
    return hWnd;
}

Now I retrieve the count of tray icons :-

int count = (int)::SendMessage(m_hTrayWnd, TB_BUTTONCOUNT, 0, 0);

The number won't match the number of visible icons because of some hidden icons inserted by Explorer + the Hide Inactive Icons setting may be enabled.

BTW to retrieve toolbar info for each button, I use my CProcessData class. [CProcessData is a template class that makes it easy to use data allocated in a different process, and is useful when making inter-process SendMessage/PostMessage calls]

The dwData member of each TBBUTTON structure of the toolbar points to an undocumented structure. The first few bytes of the structure are as follows (on XP anyway) :-

struct TRAYDATA
{
    HWND hwnd;                
    UINT uID;                
    UINT uCallbackMessage;    
    DWORD Reserved[2];        
    HICON hIcon;                
};

There's more info, but I am not sure what the rest of it means. Reserved[0] has something to do with the visibility state of an icon when the Hide Inactive Icons setting is enabled, but it's behavior was too sporadic for me to give it a proper meaning and since I didn't really want that info, I didn't bother too much. All my Google searches on this undocumented structure resulted in nothing. It's times like this when you wish Windows provided full source code :-(

Anyway here's the code I use to retrieve the rest of the information I require.

CProcessData<TBBUTTON> data(dwTrayPid);
TBBUTTON tb = {0};
TRAYDATA tray = {0};
TrayItemInfo tifo = {0};

for(int i=0; i<count; i++)
{        
    ::SendMessage(m_hTrayWnd, TB_GETBUTTON, i, (LPARAM)data.GetData());        
    data.ReadData(&tb);            
    data.ReadData<TRAYDATA>(&tray,(LPCVOID)tb.dwData);

    DWORD dwProcessId = 0;
    GetWindowThreadProcessId(tray.hwnd,&dwProcessId);

    tifo.sProcessPath = GetFilenameFromPid(dwProcessId);        

    wchar_t TipChar;
    wchar_t sTip[1024] = {0};
    wchar_t* pTip = (wchar_t*)tb.iString;        

    if(!(tb.fsState&TBSTATE_HIDDEN))
    {            
        int x = 0;
        do 
        {    
            if(x == 1023)
            {
                wcscpy(sTip,L"[ToolTip was either too long or not set]");    
                break;
            }
            data.ReadData<wchar_t>(&TipChar, (LPCVOID)pTip++); 
        }while(sTip[x++] = TipChar);
    }
    else
        wcscpy(sTip,L"[Hidden Icon]");                

    USES_CONVERSION;
    tifo.sTip = W2T(sTip);

    tifo.hwnd = tray.hwnd;
    tifo.uCallbackMessage = tray.uCallbackMessage;
    tifo.uID = tray.uID;

    tifo.bVisible = !(tb.fsState & TBSTATE_HIDDEN);

    int iconindex = 0;
    ICONINFO  iinfo;
    if(GetIconInfo(tray.hIcon,&iinfo) != 0)
    {            
        iconindex = m_Image16List.Add(tray.hIcon);
    }

For the rest of the code, see the included source code zip.

Thanks

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralNice demo app..
xsoftwerx
17:40 15 Feb '10  
Just for s&g I changed it allow Windows 7 -- still works... somewhat.
It enumerates the visible icons but, any on the overflow window are not shown.
GeneralWrong code and method
kilt
1:18 14 Sep '09  
The right method is to use internal Shell Structures and code injection in Explorer address space.
Internal Shell Structures had been published on Advanced Win32 newsgroup (news://comp.os.ms-windows.programmer.win32 or http://tinyurl.com/cmhb5g[^])
GeneralVista 32 and Vista 64
Chris Havelick
4:25 10 Apr '09  
I have created a similar program using VB.Net. I enumerate the system tray icons using the same method. I do this to automatically activate one of the programs associated with a system tray icon.

It works in both 32 bit and 64 bits Vista, so I expect that this program will also.
QuestionWhy right click menu are sometime sticky?
lerognon
10:26 21 Feb '09  
Sometimes when I use the right click button, the menu corresponding to the tray icon appears but also remains sticky even if I click elsewhere. Anyone having an idea why it is so or how to avoid this behavior?
AnswerRe: Why right click menu are sometime sticky?
Andreone
4:49 19 Aug '09  
Before showing the menu, call SetForegroundWindow on the owner window of the icon so the menu can be dismissed.
Maybe there's a better way, but this works in my applications.
GeneralCan we hide a particular icon in the system tray? [modified]
Kishore_Vuppala
18:54 4 Feb '09  
I need to hide or unhide certain bluetooth applications' icons that are there in system tray based on whether bluetooth is on/off. Can we hide/unhide the system tray icons? It's an urgent requirement!!

modified on Thursday, February 5, 2009 1:12 AM

Newsabout "GetIconInfo"
oneg661
6:26 5 Jan '09  
why D'Oh! the "GetIconInfo" return ZERO in some system's Trayicons that they is exist?
Generalnotes
jo0ls
2:50 16 Dec '08  
Looks like TRAYDATA is NOTIFYICONDATA without the cbsize field.
GETMODULEFILENAMEEX is an easier way to get the normal path from the device path.
Still works in Vista.
I'm doing it with managed code, but the TBBUTTON size varies between x64 and x86 - which is a pain as I can't see a way to lay it out that works with both.
Questionclass
gq_the_fallen_angel
7:49 16 Jun '08  
Hello,

I'd like to use this code in vb.net but have now idea what to get with it. Unfortunately i have no experience with C++ so if anyone could create a dll from this to be able to use these functions (to get the icons and manipulate them) from vb.net would be really appreciated.

Anyways, just needed to delete the windows version checking and works on Vista, too - i tried it.

Thanks;
GQ
Questionhide a single tray icon from system tray
Jayapal Chandran
1:27 15 Mar '08  
hi, i need to hide a particular tray icon from the system tray instead of using the reg key NoTrayItemsDisplay. i am with win32 api C style...

Today's Beautiful Moments are
Tomorrow's Beautiful Memories

GeneralSome icons' handle of tray buttions are invalid
gshine610
21:06 12 Aug '07  
Some icons' handle of tray buttions are invalid ?

When I ran the binary file(ShellTrayInfo.exe), I found that some tray buttons' icon were incorrect, such as MSN(Windows Live Messenger),Kaspersky Antivirus, etc.

After I debuged those codes, I found that some icons' handle of tray buttions are invalid.
In those cases, we will fail to call the GetIconInfo API and the error code got by GetLastError is 1402.

Is there any difference in those applications?
How can I solve this problem?

Hope to receive your reply soon.

Thanks in advance!



Kevin.
GeneralWorks on Vista
Thomassen
1:31 16 Jun '07  
This app seem to work on Vista. I had to put it in compatibility mode to bypass the version check, but I was able to reposition icons etc.

Maybe make the version check forward compatible? Only disallowing older OS's which is known not to work?
QuestionAnyone know of a similar program that just lists the systray icons?
badbob001
7:36 11 May '07  
I'm looking for a commandline utility to just list the icons and tooltips in the system tray and spit it out to a file or stdout so I can parse it. Before I try to tackle modifying this app's code to do what I want, is there already something like what I'm looking for?

Thanks!
AnswerRe: Anyone know of a similar program that just lists the systray icons?
lerognon
10:23 21 Feb '09  
Try http://exodusdev.com/products/windows-system-tray-scan-utility[^]
GeneralJust what I needed!
Hans Dietrich
2:14 9 Apr '07  
After last month's disastrous HD crash, I wanted to start keeping tabs on the temperatures for both of my HD drives. I use HDD Thermometer, a great free tool that shows the temps (one for each HDD) in the tray. Unfortunately, at startup the temps sometimes do not appear next to each other. Your utility is the perfect answer!

I agree with 5h17h34d - having Shell Tray Info run at startup would be very nice.

Thanks!

Best wishes,
Hans
GeneralRe: Just what I needed!
Nishant Sivakumar
2:54 9 Apr '07  
I've been meaning to update the source to VC++ 2005, and I guess when I do that I'll also add an installer that'll add this to the startup. Though I could avoid the installer and add an option within the app that'll allow people to specify if they want it to run on startup - it's always good to avoid installers.

Regards,
Nish
Nish’s thoughts on MFC, C++/CLI and .NET (my blog)
C++/CLI in Action (*E-Book is out, Print version April 6th*)
Fly on your way like an eagle
Fly as high as the sun
On your wings like an eagle
Fly and touch the sun

GeneralRe: Just what I needed!
Hans Dietrich
3:00 9 Apr '07  
Nishant Sivakumar wrote:
I could avoid the installer and add an option within the app that'll allow people to specify if they want it to run on startup

I agree - an option within the app would be better.

GeneralHowto make ShellTrayInfo work automatically at boot?
5h17h34d
18:19 13 Feb '07  
Like this little app except the fact that I must redo it after
every boot.

Perhaps I am missing something obvious?

Thank you for this little gem of a program for a utility
junky like me!

SH
GeneralRe: Howto make ShellTrayInfo work automatically at boot?
S.H.Bouwhuis
14:14 18 Jun '07  
My thoughts exactly!
Actually, a simple 'auto alphabetic sort' every 5 minutes or so would be enough.

Since the source code is supplied, it should be an easy thing.
I'm currently too busy/lazy to do this, but if there are people out there who REALLY want this, I'll consider it (PM me with request).
GeneralCompiling Error Help
swarup
1:28 9 Dec '06  
hi guys i am getting some errors while Compiling, can anyone help me out,

the errors are

Cerror C2552: 'tifo' : non-aggregates cannot be initialized with initializer list
Cerror C2275: 'TRAYDATA' : illegal use of this type as an expression
error C2275: 'wchar_t' : illegal use of this type as an expression

these 3 can be solved by using atlbase.h but what about the rest

error C2065: 'USES_CONVERSION' : undeclared identifier
error C2065: 'W2T' : undeclared identifier
error C2593: 'operator =' is ambiguous

ya one more thing
GetProcessImageFileName is it in psapi, then which is the correct version and can somepne post the 3 files, psapi.h psapi.lib n psapi.dll
because i m getting the error if i comment all the pervious errors
unresolved external symbol _GetProcessImageFileNameW@12

Thanks a lot
Swarup
Generalhow to make Static Executeable/portable executeable
murtazadhari
4:19 11 Nov '06  
i want to know how i can make static executable file.

Murtaza Tahir Ali Dhari
Generali want to refer code written by MFC(Visual C++6.0) about "Programmable Calculator"
amatuer_vn03
17:52 15 Sep '06  
please help me some code this "program stilmulator Calculator same Windows"

i like design Web

GeneralDid you ever find out why some icons dont appear?
plehxp
2:20 6 Sep '06  
Did you ever find out why some icons (MSN Messenger for example) do not draw properly?

I am having the same problem in a similar project and i dont know why some icons dont return a valid hIcon.
QuestionNon-MFC
spamna
7:21 19 Aug '06  
I am attempting to write a function to determine if my tray icon is still present. It irritates me greatly when explorer crashes and drops my icon and I feel it is a poor solution to simply delete and re-add the icon periodically as has been suggested to me. I am implementing this in a non-MFC application, so I am afraid I cannot use the CProcessData class you have used in your example. I was wondering if you could explain how to obtain the specific TRAYDATA object for each icon without using the CProcessData class. Here is my code:

bool IsTrayIconPresent(UINT uid) {
TBBUTTON tb = {0};
TRAYDATA td = {0};
HWND hWnd = ::FindWindow("Shell_TrayWnd", NULL);
if(hWnd) {
hWnd = ::FindWindowEx(hWnd, NULL, "TrayNotifyWnd", NULL);
if(hWnd) {
hWnd = ::FindWindowEx(hWnd, NULL, "SysPager", NULL);
if(hWnd) {
hWnd = ::FindWindowEx(hWnd, NULL, "ToolbarWindow32", NULL);
}
}
}

if(!hWnd) //error could not find Toolbar
return false;

int count = (int)::SendMessage(hWnd, TB_BUTTONCOUNT, 0, 0);
for(int i=0;i ::SendMessage(hWnd, TB_GETBUTTON, i, (LPARAM)(LPTBBUTTON)&tb);
memcpy(&td, (LPCVOID)tb.dwData, sizeof(td)); //does not work

if(td.uID == uid)
return true;
}

return false;
}

This code of course needs to be optimized, but this is just the prototype. Any help would be kindly appreciated.

Thanks,
Nate
AnswerRe: Non-MFC
Nishant Sivakumar
7:28 19 Aug '06  
spamna wrote:
I am implementing this in a non-MFC application, so I am afraid I cannot use the CProcessData class you have used in your example.

CProcessData is not MFC dependent. You can use it for non-MFC projects too.

Regards,
Nish
Nish’s thoughts on MFC, C++/CLI and .NET (my blog)
Currently working on C++/CLI in Action for Manning Publications.
Also visit the Ultimate Toolbox blog (New)


Last Updated 27 Jun 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010