6

MSDN's documentation about Notifications and the Notification Area is pretty clear in the requirement for having an icon in the notification area in order to display a notification:

To display a notification, you must have an icon in the notification area. In certain cases, such as Microsoft Communicator or battery level, that icon will already be present. In many other cases, however, you will add an icon to the notification area only as long as is needed to show the notification.

Since I do not wish to add any icon to the notification area, I was thinking of perhaps "reusing" an existing one that is most likely to be there on a typical desktop. A good candidate may be the system clock.

My questions are:

  1. How do I find/enumerate the NOTIFYICONDATA structure for the system clock (AKA "Date and Time Properties" when restored)?
  2. Is there a better way of accomplishing this (without adding an icon)?
7
  • Your quote specifically says you can't do this - I don't understand what your actual question might be: "The docs say I can't, but I want to anyway. How?" If you could hijack an existing notification icon, that would be a pretty wide security hole for malware, don't you think? Voting to close as "not a real question".
    – Ken White
    Commented Jun 7, 2011 at 19:33
  • 1
    @Ken White Thanks for your answer. My first question specifically asks about re-using an existing icon. No hijacking, just sending a displayable TEXT message. There shouldn't be any security risk associated, as sending text-to-be-displayed to my own icon or to another icon should result in exactly the same. Unless you can explain otherwise, of course.
    – WinWin
    Commented Jun 7, 2011 at 20:14
  • 1
    Sorry. Misunderstood your question somewhat; it's still not going to work, though, as the docs specifically state. There are only a couple of ways to pass text between apps safely (since the text is actually a character pointer), and notifications are not included in those ways. I don't understand the desire to avoid adding an icon, however, since that is exactly how they're designed to be used even for short purposes (as noted in the last sentence of your docs quote above).
    – Ken White
    Commented Jun 7, 2011 at 23:27
  • @Ken White No problem. I will try to better explain my situation: I am looking to use the notification area in a manner similar to MessageBox(), in which once could get away with having no owner window. The reason is that my tiny application is designed to run in multiple instances without each knowing about the other. So, I don't have the "luxury" of a central managing app with a single icon. Since the number of those instances can reach hundreds (or thousands) I don't want to each add an icon... I wish popping up a balloon were as simple as a MessageBox().
    – WinWin
    Commented Jun 8, 2011 at 0:55
  • 2
    I'm still unclear. You're now saying you might have "hundreds (or thousands)" of instances of your app that you want to use notification balloons for? What would be the point of that - how would a user see or have time to read them? I think I'm now more confused than ever... :) However, you could still have a notification app that acts as a single icon, and receives updates from other instances via an inter-process communication of some sort and handles the notification displays.
    – Ken White
    Commented Jun 8, 2011 at 20:30

1 Answer 1

10

Shell_NotifyIcon uses IUserNotification under the hood. I played around with it and made a utility out of it. I heard of a visually impaired sysadmin who uses it to make his scripts screen reader compatible. It is command line, it does not have a message loop.

It is self aware, meaning that notifications sent to it will be queued (you have control over it). For that to work, I provided a IQueryContinue implementation. The project is in C++ and is open source, help yourself.

Here is the guts of it :

 HRESULT NotifyUser(const NOTIFU_PARAM& params, IQueryContinue *querycontinue, IUserNotificationCallback *notifcallback)
 {
    HRESULT result = E_FAIL;

    IUserNotification *un = 0;
    IUserNotification2 *deux = 0; //French pun : "un" above stands for UserNotification but it also means 1 in French. deux means 2.

    //First try with the Vista/Windows 7 interface
    //(unless /xp flag is specified
    if (!params.mForceXP)
       result = CoCreateInstance(CLSID_UserNotification, 0, CLSCTX_ALL, IID_IUserNotification2, (void**)&deux);

    //Fall back to Windows XP
    if (!SUCCEEDED(result))
    {
       TRACE(eWARN, L"Using Windows XP interface IUserNotification\n");
       result = CoCreateInstance(CLSID_UserNotification, 0, CLSCTX_ALL, IID_IUserNotification, (void**)&un);
    }
    else
    {
       TRACE(eINFO, L"Using Vista interface IUserNotification2\n");
       un = (IUserNotification*)deux; //Rather ugly cast saves some code...
    }

    if (SUCCEEDED(result))
    {
       const std::basic_string<TCHAR> crlf_text(L"\\n");
       const std::basic_string<TCHAR> crlf(L"\n");
       std::basic_string<TCHAR> text(params.mText);
       size_t look = 0;
       size_t found;

       //Replace \n with actual CRLF pair
       while ((found = text.find(crlf_text, look)) != std::string::npos)
       {
          text.replace(found, crlf_text.size(), crlf);
          look = found+1;
       }

       result = un->SetIconInfo(params.mIcon, params.mTitle.c_str());
       result = un->SetBalloonInfo(params.mTitle.c_str(), text.c_str(), params.mType);

       //Looks like it controls what happends when the X button is
       //clicked on
       result = un->SetBalloonRetry(0, 250, 0);

       if (deux)
          result = deux->Show(querycontinue, 250, notifcallback);
       else
          result = un->Show(querycontinue, 250);

       un->Release();
    }

    return result;
 }
2
  • 1
    This is an incredible answer. Already +1 for that. And thank you. If I have multiple instances of the same application (unaware of each other), each sending a notification message, does this mean that each will create its own icon in the systray?
    – WinWin
    Commented Jul 6, 2011 at 20:30
  • 2
    Yes, unfortunately. Notifications are queued by process, so multiple process will each get their icon. I got around this by implementing IQueryContinue with a semaphore. A running instance checks if another (notifu) process wants to display something. If so, it will dismiss itself. The user will see the icon going away and come back again very fast. It was either that or make a notification hub that would queue and display messages coming from multiple processes.
    – ixe013
    Commented Jul 6, 2011 at 20:48

Not the answer you're looking for? Browse other questions tagged or ask your own question.