Log in

View Full Version : Refreshing the Taskbar Notification Area


REBlog
February 15th, 2008, 14:21
I am working on an automation system that involves forcefully terminating a process that creates an icon in the Taskbar Notification Area (no, not the "system tray" ("http://blogs.msdn.com/oldnewthing/archive/2003/09/10/54831.aspx"). It is the responsibility of the process that creates an icon in the Taskbar Notification Area to remove the icon when the process exits, however, since I am using TerminateProcess(...) ("http://msdn2.microsoft.com/en-us/library/ms686714.aspx") to remotely kill the process, the code to remove the icon never gets executed. As such, the icon remains in the Taskbar Notification Area until one moves the mouse cursor over the icon, at which point it disappears.

Since this is an automation system that's being developed, this icon-creating process will get executed many times, and if left unchecked would end up leaving hundreds of icons in the Taskbar Notification Area (one icon per execution). That's bad.

Despite my best Googling efforts ("refresh notification area", "redraw system tray", etc.), I wasn't able to find elegant code to solve this problem. I found some novel solutions, though. The most common suggestion was to use SetCursor(...) ("http://msdn2.microsoft.com/en-us/library/ms648393(VS.85).aspx") to drag the mouse cursor around the Taskbar Notification Area; while this works, it's an ugly hack and is actually quite slow. One of my "favorite" suggestions was to try to associate each icon in the Taskbar Notification Area with a process, then monitoring each process for termination, then deleting the icon once the given process terminates (talk about overkill... geeze).

When a user moves the mouse over a "dead icon" in the Taskbar Notification Area, some window message must get sent to the window to cause it to say to itself, "hey, the mouse is over me, so let me see if the process that created this icon is still alive.... Oh, it's not? Let me remove the icon, then." I wanted to find what window message was causing that code to fire so that I could send that message to the window myself.

I started up Microsoft Spy++ ("http://msdn2.microsoft.com/en-us/library/aa315486(VS.60).aspx") and saw the following information for the Taskbar Notification Area and its parent windows:

http://malwareanalysis.com/CommunityServer/blogs/geffner/2008_02_15_1.jpg

A useful feature of Microsoft Spy++ is that it allows you to monitor window messages sent to a given window. I started monitoring the window messages getting sent to the "Notification Area" window without moving my mouse over the window and saw the following messages getting sent:


TB_BUTTONCOUNT ("http://msdn2.microsoft.com/en-us/library/ms940419.aspx")
TB_GETBUTTONINFOW ("http://msdn2.microsoft.com/en-us/library/ms864705.aspx")
TB_SETBUTTONINFOW ("http://msdn2.microsoft.com/en-us/library/bb787413(VS.85).aspx")
WM_PAINT ("http://msdn2.microsoft.com/en-us/library/ms534901(VS.85).aspx")
WM_ERASEBKGND ("http://msdn2.microsoft.com/en-us/library/ms648055(VS.85).aspx")
The messages above clearly had nothing to do with me moving my mouse (since I wasn't moving my mouse over the window), so I configured Microsoft Spy++ to filter out those messages. Then I moved my mouse over the "dead icon" in question and saw the following messages:

<00001> 00010056 S WM_NCHITTEST xPos:1491 yPos:1024
<00002> 00010056 R WM_NCHITTEST nHittest:HTCLIENT
<00003> 00010056 S WM_SETCURSOR hwnd:00010056 nHittest:HTCLIENT wMouseMsg:WM_MOUSEMOVE
<00004> 00010056 R WM_SETCURSOR fHaltProcessing:False
<00005> 00010056 P WM_MOUSEMOVE fwKeys:0000 xPos:5 yPos:0
<00006> 00010056 S TB_HITTEST pptHitTest:022BFC18
<00007> 00010056 R TB_HITTEST iIndex:0
<00008> 00010056 S TB_DELETEBUTTON iButton:0
<00009> 00010056 R TB_DELETEBUTTON fSucceeded:True

Aha! So either WM_NCHITTEST ("http://msdn2.microsoft.com/en-us/library/ms645618(VS.85).aspx"), WM_SETCURSOR ("http://msdn2.microsoft.com/en-us/library/ms648382(VS.85).aspx"), WM_MOUSEMOVE ("http://msdn2.microsoft.com/en-us/library/ms645616(VS.85).aspx"), or TB_HITTEST ("http://msdn2.microsoft.com/en-us/library/bb787360(VS.85).aspx") leads to the TB_DELETEBUTTON ("http://www.piclist.com/techref/os/win/api/win32/mess/src/msg16_21.htm") getting sent. After trying to send each window message manually with SendMessage(...) ("http://msdn2.microsoft.com/en-us/library/ms644950(VS.85).aspx"), I found which window message was the catalyst: WM_MOUSEMOVE.

With this new-found knowledge, I was able to whip up the following code to refresh the Taskbar Notification Area:

Code:
#define FW(x,y) FindWindowEx(x, NULL, y, L""

void RefreshTaskbarNotificationArea()
{
HWND hNotificationArea;
RECT r;

GetClientRect(
hNotificationArea = FindWindowEx(
FW(FW(FW(NULL, L"Shell_TrayWnd", L"TrayNotifyWnd", L"SysPager",
NULL,
L"ToolbarWindow32",
L"Notification Area",
&r);

for (LONG x = 0; x < r.right; x += 5)
for (LONG y = 0; y < r.bottom; y += 5)
SendMessage(
hNotificationArea,
WM_MOUSEMOVE,
0,
(y << 16) + x);
}


http://malwareanalysis.com/CommunityServer/aggbug.aspx?PostID=985

http://malwareanalysis.com/CommunityServer/blogs/geffner/archive/2008/02/15/985.aspx

dELTA
February 15th, 2008, 16:59
Haven't we all been annoyed by this little Windows quirk, nice and useful hack.

And for more tools like Spy++ (ok, currently just one, but it's better anyway ), see the Window Monitoring Tools category of the CRCETL:

http://www.woodmann.com/collaborative/tools/Category:Window_Monitoring_Tools

disavowed
March 2nd, 2008, 16:06
admins, looks like you may want to fix your blog importing code to fix server addresses for IMGs.

Kayaker
March 2nd, 2008, 16:57
Aargh, that always happens with a relative HREF. In this case the img src was a relative link, so the anchor became www.woodmann.com instead of malwareanalysis.com

<IMG height=128 src="/CommunityServer/blogs/geffner/2008_02_15_1.jpg" width=373>

It would be nice if all authors used absolute links throughout, which would avoid this problem

I understand the usage of the relative links mind you, since that's commonly what you'd use when designing a web page. Fortunately this has only happened a few times.

I might be able to check if a blog link (href or img src or attachment) is relative and if so change it to include the source anchor link. I was hoping not to have to make any more changes to the already heavily modified import script, but I'll see how straightforward it is.

Thanks for the heads up.