Geoff Chappell - Software Analyst
This function sends a request to the taskbar window concerning an icon in the notification area.
BOOL Shell_NotifyIcon ( DWORD dwMessage, PNOTIFYICONDATA lpdata);
The function has an ANSI form, both with and without the A suffix, and a Unicode form, with the W suffix.
The dwMessage argument loosely describes the operation to perform with the information that is addressed by the lpdata argument. The following are the values that are recognised for dwMessage by either SHELL32 or EXPLORER:
NIM_ADD | 0 | add the given icon to the taskbar notification area |
NIM_MODIFY | 1 | modify the given icon on the taskbar notification area |
NIM_DELETE | 2 | delete the given icon from the taskbar notification area |
NIM_SETFOCUS | 3 | set the focus to the taskbar notification area, preferably to the given icon |
NIM_SETVERSION | 4 | set new or old behaviour for the given icon on the taskbar notification area |
Note however that NIM_SETFOCUS and NIM_SETVERSION are supported only in version 5.00 and higher.
The NOTIFYICONDATA structure addressed by the lpdata argument is described separately (in preparation), for although it is used only for this function, it is quite large and is complicated by having gone through several expansions which all remain valid.
The function returns a non-zero value for success, else FALSE to indicate failure. Call GetLastError to retrieve an error code.
Though SHELL32 implements the function, its role is almost entirely that of a switchboard, to direct the call to the taskbar window. The function therefore has some behaviour originating in SHELL32.DLL and some in EXPLORER.EXE (which is the ordinary provider of the taskbar window). These notes are concerned only with the former.
Starting with the version 6.00 from Windows Vista, it is an error (ERROR_INVALID_PARAMETER) to pass NULL as lpdata.
If there is no top-level window with the class name expected for the taskbar, namely “Shell_TrayWnd”, then the function has nowhere to send the request, and fails. (The error code is from FindWindow.)
As a switchboard, SHELL32 is mostly unconcerned with interpreting the function’s arguments. However, the NOTIFYICONDATA structure that is expected at lpdata has changed through successive SHELL32 versions. In version 5.00 and higher, the function has the problem that its caller may be using an old layout. It detects this from cbSize. In repackaging the input so that the taskbar window sees only the latest layout, there is some parameter validation (but not so that invalid input causes the function to fail). Most notably, uFlags bits that are not valid for the layout are ignored. In version 6.00 and higher, the function also places null terminators at the last element of:
The version 6.00 from Windows Vista introduces yet another extension to the input structure and more validation. If the NOTIFYICONDATA is large enough to provide for hBalloonIcon and dwMessage is either NIM_ADD or NIM_MODIFY and NIF_INFO is set in uFlags and NIIF_USER is set in dwInfoFlags, then the function checks that whatever is intended as the balloon icon has a plausible size. The icon to check is given by hBalloonIcon if not NULL, else hIcon. If NIIF_LARGE_ICON is set in dwInfoFlags, then the icon is invalid if either its width or height is smaller than SM_CXICON. Otherwise, if the icon is from hBalloonIcon, it is invalid if its width and height are not exactly SM_CXSMICON and SM_CYSMICON respectively. Whichever member provides the icon, if the icon is invalid, the function fails (though without setting an error code).
In version 5.00 and higher, processes are not necessarily able to set the foreground window, yet the whole point to NIM_SETFOCUS is to bring the taskbar window to the foreground, with the focus on the indicated icon. If dwMessage is NIM_SETFOCUS, the function asks that the taskbar window’s process be allowed to set the foreground window.
A security feature introduced for Windows Vista is that a process cannot send a window message to a process that has higher integrity. This is a problem if the caller of this function has higher integrity than the taskbar window’s process but wants to receive callback messages about the indicated icon. Old callers won’t know but may misbehave without the expected callback, and so this function must pave the way for them. If NIF_MESSAGE is set in uFlags, then the function adds the message number given by uCallbackMessage to the current process’s message filter if dwMessage is NIM_ADD or NIM_MODIFY and removes it if dwMessage is NIM_DELETE.
Since the taskbar may be, and typically is, implemented in another process, the function’s input is passed to the taskbar window as a
message. In version 5.00 and higher, sending the message is aborted if the target process seems hung. The NT implementations of these versions have a variation and an extra condition. First, the message is sent such that the calling thread is blocked even from nonqueued messages until a reply is obtained. Second, a timeout applies, of 4 seconds in most versions, but increased to 7 in the version 6.00 from Windows Vista. If delivery is frustrated, the function fails. Otherwise, the function returns whatever the taskbar window returns for the message. Thus, if the taskbar window can fail the function by returning zero from its window procedure.What the taskbar window does with the message is not of concern here. Details are in preparation for the separate articles on each of the values that are supported for dwMessage. Unsupported values for dwMessage are typically failed by the taskbar window, but there does exist an exception, presumably as a coding error. If the REST_NOTRAYITEMSDISPLAY restriction was in force when the taskbar was created, then although the taskbar window does not accommodate notification-area icons, it lets the message succeed no matter what the value of dwMessage.
For reasons not presently understood, the version 6.00 from Windows Vista provides that if NIF_INFO is set in uFlags and dwMessage is either NIM_ADD or NIM_MODIFY, then the string at szInfo is registered with Windows Error Reporting. This is done even if the message cannot be delivered or is failed by the taskbar window.
This function is natively Unicode in NT versions of Windows. The Shell_NotifyIconA function repackages ANSI input as Unicode and calls Shell_NotifyIconW internally.
Except as noted below, the Shell_NotifyIcon function is exported by name from SHELL32.DLL in an ANSI form (with and without an A suffix) and a Unicode form (with a W suffix). The function is ancient. It is exported from versions 1.30 and 3.51, though admittedly with implementations that fail trivially (returning FALSE having done nothing but set ERROR_CALL_NOT_IMPLEMENTED as the error code). The function has been “live” since version 4.00. The version 4.00 from Windows 95 does not export a Unicode form of the function. The Windows, as opposed to NT, builds of later versions export a Unicode form, but only in a trivial coding (which just returns FALSE, without setting an error code).
This ancient SHELL32 function has long been documented. It seems fair to deride the documentation as sparse, relative to the function’s very many cases and subtleties of behaviour. (As I say this, I must of course admit to the difficulty of writing good documentation for this function. I have twice attempted to cover in detail the supported values of dwMessage and the members of the NOTIFYICONDATA structure, and I have twice abandoned it. However, I am not the manufacturer.)
Especially notable is that as recently as January 2007, Microsoft’s documentation of Shell_NotifyIcon, on CD and online, did not even hint that the function might fail for reasons more serious than being improperly called. An unsurprising consequence is that very many callers of this function do not check it for success or failure. A practical effect has been to exaggerate the mystery of missing icons in the notification area.