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)?
WinWin
  • 7,493
  • 10
  • 44
  • 53
  • 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 Jun 07 '11 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 Jun 07 '11 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 Jun 07 '11 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 Jun 08 '11 at 00: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 Jun 08 '11 at 20:30
  • @Ken White I found something very similar to what I want to accomplish: http://stackoverflow.com/questions/5730340/tooltip-anywhere-in-the-screen-vc-express-edition Yes, it's not pretty as a notification balloon but for the purpose of **briefly** notifying the user (~1 sec) about an item being processed that should be OK. A notification app that acts as a single icon, and receives updates from other instances via an inter-process communication is way beyond the scope of the tiny app I am trying to write. I was really aiming for a one-statement solution but I guess it's not possible. – WinWin Jun 08 '11 at 23:01
  • You could register a message ([link](http://msdn.microsoft.com/en-us/library/ms644947(v=vs.85).aspx)), and have your satellite applications send it to your notification app. Please be aware that the timeout is deprecated as of Windows Vista. – ggponti Jun 09 '11 at 14:26

1 Answers1

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;
 }
ixe013
  • 9,559
  • 3
  • 46
  • 77
  • 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 Jul 06 '11 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 Jul 06 '11 at 20:48