Geoff Chappell - Software Analyst
This method of the ITrayNotify interface asks to be called back with information about (and changes to) items in a tray’s notification area.
HRESULT ITrayNotify :: RegisterCallback (INotificationCB *pcb);
The pcb argument provides the address of an INotificationCB interface whose methods are to be called (back) by the ITrayNotify implementation to tell about items in the tray’s notification area. This argument can be NULL to turn callbacks off.
The method returns zero for success, else an error code.
If the REST_NOTRAYITEMSDISPLAY restriction was in force when the tray was created, then the tray does not accommodate notification-area icons except for the clock. The method succeeds trivially. This is not very satisfactory, since the caller may reasonably take success as approval to wait for callbacks, which will never come.
Except in the previous configuration, calling this method releases any callback interface that is already registered. The method then adopts the given callback interface. If pcb is NULL, callbacks are now cancelled and the function succeeds.
Otherwise, the method adds a reference to the newly registered callback interface and sets about telling the caller about icons that are already known. These are taken in two sets. First are the icons that are on the notification area but not counting the System Control Area (SCA). Second are icons that are known in the registry because of past use. Each icon, of whatever type, is reported by calling the Notify method of the registered callback interface. The first argument is zero. The second is the address of a structure that describes the icon. Icons that are known from the registry are distinguishable by having no window handle.
The function then succeeds. The Notify method of the registered callback interface may thereafter get called any number of times to report that an icon has been added, modified or deleted. Such notifications continue until RegisterCallback is next called (including by someone else).
The notification area provides for knowing no more than one callback interface at any one time. Though EXPLORER registers its TrayNotify class as being available for multiple use (specifically, it passes REGCLS_MULTIPLEUSE along with CLSCTX_INPROC_SERVER and CLSCTX_LOCAL_SERVER to CoRegisterClassObject), it implements the class as if its callback feature has only one possible user.
This intended user is the Customize Notification Icons dialog, as reached from the Taskbar and Start Menu Properties. If this dialog is open and some other ITrayNotify client registers a callback, then the intended dialog stops receiving callbacks. It will not be rendered completely useless but the information it displays about the notification-area icons will become out-of-date.
The RegisterCallback method can therefore be considered usable by well-behaved software only if some way can be found to detect whether the standard dialog is already open and to stop it from being opened and to detect whether yet another party has stopped the standard dialog from being opened (because you wouldn’t want to interfere with them any more than with the standard dialog). The exercise looks academic however. It seems unlikely to me that a third-party taskbar manager exists, and surely not commercially. Even if someone should think to write one, it couldn’t do anything very useful with the ITrayNotify and INotificationCB interfaces that isn’t already done by the Customize Notification Icons dialog.
That said, I must express surprise that any means exists at all to enumerate, let alone configure, other software’s notification icons from outside EXPLORER. The more sceptical may want proof, and I myself was sceptical enough to run up a demonstration program. It confirms that the work of the Customize Notification Icons dialog can be done in third-party software and it allows you to confirm the limitation that I raise above as a warning.
The TRAYNOT program presents a top-level window that consists solely of a List-View control for reporting the notification-area operations that are signalled through the ITrayNotify and INotificationCB interfaces. The program obtains an ITrayNotify interface from EXPLORER and calls the RegisterCallback method to arrange for callbacks through the Notify method of the program’s own INotificationCB interface.
For distribution, the built program (x86) is supplied with source code, compressed into one zip file: download the Tray Notification Reporter program. There are no command-line switches. Just run it (though of course I advise that you check for yourself that the program is what it says, and rebuild it if you want).
As an aside, note that the program fails if User Account Control (UAC) is enabled and the program is run with elevated privilege. EXPLORER is the COM server and TRAYNOT is a COM client. Yet EXPLORER has only medium integrity. Though Microsoft’s notes on UAC—they’re really not substantial enough to count as programming documentation—deal with the situation of a lower-integrity COM client trying to communicate with a higher-integrity COM server, curiously little is said about the reverse. A higher-integrity COM client is protected from a lower-integrity COM server, much as a higher-integrity program is protected from receiving window messages from a lower-integrity program. For the latter, Microsoft provides the higher-integrity program with explicit means to open itself to expected messages from a lower-integrity source. Finding the analogous provision for COM may be a worthwhile exercise for another time.