New Windows Tray / Notification Manager is here!

Hi Guys,

As mentioned in the previous post I worked for the past days on a new way for changing the notification area. Luckily I found the blog from Geoff Chappell which led me to an interface which is implemented by EXPLORER to support the notification area of the taskbar. (http://www.geoffchappell.com/studies/windows/shell/explorer/interfaces/itraynotify/index.htm?tx=28) On his blog he describes how to use the interface and register the COM class TrayNotify.

To my surprise that didn’t work with windows 8. So i figured out that Microsoft must have changed the ITrayNotify interface for the new Explorer Version (Win7: 6.2; Win8: 6.3). After reverse engineering explorer.exe using OllyDbg I found out that the virtual function table after the IUnknown methods have slightly changed:

HRESULT RegisterCallback (INotificationCB *,unsigned long *)
HRESULT UnregisterCallback (unsigned long *)
HRESULT SetPreference (NOTIFYITEM const *)
HRESULT EnableAutoTray (BOOL)
//Look at virtual function table for correct signature
HRESULT DoAction (Dummy)
etc…

Cause of these changes i use two different dlls. One for WinXp,Win7 and one for Win8, Win10.


In my application i use managed WPF(.Net Framework 4.0) for the GUI and a dll with unmanaged c++ Code for defining the interface and registering the callback. I also implemented my own Callback to call a managed method(C# application) in an unmanaged function(my c++ dll). See: http://limbioliong.wordpress.com/2011/06/19/delegates-as-callbacks-part-2/.

You could do it without an unmanaged dll using Pinvoke with C# but i did it for educational purposes and cause i wanted to know if it would be possible.

I will attach the application with 2 different dlls. If you want to use the Program in windows 8 you have to rename TrayNotificationManagementWin8.dll to TrayNotificationManagement.dll and put the dll into the same folder as TrayManager.exe. Otherwise it will fail. The Datagrid list will automatically update itself if there is a notification change ongoing in the Notification area of Windows, like update, deleting or modifying something there.

If you want to use the programm silent via command line please use the following syntax:

TrayManager.exe -t “Programm ToolTip” 2

TrayManager.exe -p “Programm name” 2

So for example:
TrayManager.exe -t “Microsoft Outlook” 2

Here are the possible numbers:

0=hide when inactive
1=always hide
2=always show

This will set the Outlook tray to Always Visible.

-t = To use the programs tool-tip to identify the specific icon in the Notification area.
-p = To use the programs executable to identify the icon. (e.g. for Outlook it would be Outlook.exe)

It only has to contain a word but it has to be in within “”;

I will attach the whole project source in the upcoming days after i did some commenting.

Cheers!

PS: Heres a Screenshot of the NotificationManager:

Download file:
TrayManager.zip

Download source:
Source.zip

Advertisements

56 thoughts on “New Windows Tray / Notification Manager is here!

  1. Can you provide the source code, as i want to integrate it within my app rather than executing taskmanager. Or tell me if i can use those dlls for that purpose. Could you please explain the procedure?

    • I would also love to see the source code. I’ve got an app in progress and have been struggling with an elegant and effective solution – which yours is.

      Thanks for posting the executable and laying out how you did it. Code please ? Pretty please ?

      Ms. G

      • Thanks.

        Some questions – How does the initial loading of the NOTIFYITEMICON’s work ? I don’t see that part in the code you uploaded.

        More specifically I am looking change the attribute programmatically so I’m curious how to go about it without wiring in all the property change additions that are wpf related.

        Thanks!

  2. Hi, thanks a lot for that .dlls. It works great at both Win7 and Win 8 but I have problem to Windows Server OS.. Do you have any proposal or it is not supported yet?

    • Probably due to the fact that the virtual function table for the ITrayNotify interface is different from the version of Win7/8. I have no Windows Server OS at hand so i wont be able to dig into it. If you can send me your explorer.exe of your Server OS i can modify and reupload the dll so that it will also work for Windows Server OS.

      • Sorry , my bad , it was the command after the TrayManagement that crushed!! My excuses , it works fine on Windows Server 2008 R2 SP1!!

  3. Does this work with the Windows 7 Clock? It is not showing up for All Users and this would be perfect to get it to show up on user login script.

  4. Hi! Your DLL works great, but I have been trying to use your source code in my own app for Windows 8.1 and I was getting the E_NOINTERFACE error code in CoCreateInstance. I have solved it changing the GUID of ITrayNotify to “D133CE13-3537-48BA-93A7-AFCD5D2053B4”. I hope this help others with the same problem.

    It would be great to know how do you reverse the virtual function table. It seems amazing! 🙂
    Thanks for sharing your knowledge.

  5. Would love some help creating some pure C# pinvoke code to do the RegisterCallback and SetPreference to keep an item visible in the dock, or just some basic framework of signatures/mashaling. For those of us who don’t do interop very often, getting this nailed down all in C# is rather time consuming and confusing. I could call out to your utility, but would much rather keep it in my own code. Thanks so much for doing all this work. Wouldn’t mind making a donation if it encourages you. Feel free to email me.

      • Hi, first of all thanks for sharing this awesome piece of code. I would also like to ask same thing as @hemancuso.
        Maybe You wrote same thing in pure C# (pinvoke)? I also would like to have everything inside my code without need to use unmanaged dll, especially I don’t know C++ that much.
        Best regards and once more thats for sharing.

  6. As hemancuso I would also like to set the Icon of my own C# application to “always visible” in the Task bar, and with our Windows Server Environment this would be much easier from within my own code and without unmanaged DLLs.
    Thanks also for your effort.

  7. Amazing post, really!
    Will probably do the C# rewrite soon or later, but for now, your exe gives us the way to do it neat and fast.
    Thanks a lot for sharing your knowledge as well as your time to investigate all this!

  8. I developed a Powershell script v3 which hides the icons to launch the user session using TrayManager command line.
    It works perfectly on a 2008 SP2, however on a 2008 R2, I have to execute it in compatibility mode 2003 SP1 and I get the following error that occurs randomly when multiple users open their sessions simultaneously. the error is random and concerns mscorlib 4.0.

    I have. Net Framework 4.5 installed.
    Thank you for your reply

      • I tried to reinstall 4. Net Framework and 4.5, but this has not corrected the problem. I also tried to use it with a clean OS (only Windows update) but the problem persists.

    • Ok i tried it with a 2008 R2 server with Service Pack 1. Works without problems here..Even in 2003Sp1 compatibility mode So it must be your Server configuration i think?

      Try some other .net 4.5 application. I guess the same problem will appear..

  9. Hello,
    Is it possible to use only the DLL? What are the methods and functions it contains?
    Thank you for your reply.

    • Hi,
      Of course its possible. You just need to call EnableNotification(true) to register the callback function with thenotification area. After that you can call the functions that you need like EnableAutoTrayFunction(true).
      Please look at the source code of TrayNotify.cpp.
      You can download it below my Blog entry post.

      • I got to use the dll functions with Begin, End, and EnableAutoTrayFunction in a VB.NET console project. I would eventually be able to change the display of a single icon (hide, unhide) tell him his exe name, but I block. Could you give me a track.
        Thanks for your reply

  10. Love this program but am experiencing an issue with it. If I right click and run as administrator, the window opens but the list is empty. If I try to run cmd prompt as admin and run a command with traymanager, it doesn’t give an error but also nothing happens.

    Doing either of these without elevated privileges and the program works perfectly.

    My problem is that I’m trying to run this program remotely with PDQ Deploy. PDQ seems to run everything as admin which breaks the functionality of this program.

    Is it possible to run the program with administrator privileges in Windows 7?

    • Found that when “Run as Administrator” is used with UAC off, the program works normally. With UAC on, opening traymanager with run as administrator will not show the list of running programs.

  11. Hi,

    short questions. Tool is working nicely. Only problem I have is with the program you use for your example, Outlook. I use the command line but instead of setting the Outlook symbol itself to always show it only activates the “you have new unread e-mail” notification. Both share the same EXE so I guess the logic of you tool gets confused. I didnt really find where the command line arguments are handled in your source. Is it possible to use the Identifier in the command line? Because Outlook seems to be 12345 always. So could make sure that works. Or handle arrays of Programs?

  12. I was just about to role this out to solve a problem. The problem is that its causing errors on our machines. The error says Wpf4TrayManager has stopped working. We can see in the event log that traymanager.exe is causing this error. Any way you could help us with this? I am trying to run it from a scheduled task when the user logs in so we don’t need the GUI really. I have tried playing with calling the DLL directly using Rundll32 but I couldn’t figure it out. I have looked at the source code but I am not a C++ programmer so its beyond my ken.

    • Hi,
      On which OS are these machines running? Do you call the traymanager with administrator rights or without? Please provide a bit more information.
      Thanks!

      • The error is occurring on a Windows 7 computer run without admin rights. I am not getting an error on Win 8.1

      • So a little more information on this. We can not reliably recreate the problem. We are still working on figuring out exactly what causes the issue. I can tell you that when we see the error we also get the following in the Application event log.

        Error 1026

        Application: TrayManager.exe
        Framework Version: v4.0.30319
        Description: The process was terminated due to an unhandled exception.
        Exception Info: System.InvalidOperationException

        Stack:
        at System.ThrowHelper.ThrowInvalidOperationException(System.ExceptionResource)
        at System.Collections.Generic.List`1+Enumerator[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].MoveNextRare()
        at System.Collections.Generic.List`1+Enumerator[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].MoveNext()
        at Wpf4TrayManager.App.OnStartup(System.Windows.StartupEventArgs)
        at System.Windows.Application.b__1(System.Object)
        at System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)
        at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate)
        at System.Windows.Threading.DispatcherOperation.InvokeImpl()
        at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(System.Object)
        at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
        at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
        at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
        at System.Windows.Threading.DispatcherOperation.Invoke()
        at System.Windows.Threading.Dispatcher.ProcessQueue()
        at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)
        at MS.Win32.HwndWrapper.WndProc(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)
        at MS.Win32.HwndSubclass.DispatcherCallbackOperation(System.Object)
        at System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)
        at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate)
        at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Int32)
        at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr)
        at MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef)
        at System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame)
        at System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame)
        at System.Windows.Threading.Dispatcher.Run()
        at System.Windows.Application.RunDispatcher(System.Object)
        at System.Windows.Application.RunInternal(System.Windows.Window)
        at System.Windows.Application.Run(System.Windows.Window)
        at Wpf4TrayManager.App.Main()

        Error 1000
        Faulting application name: TrayManager.exe, version: 1.0.0.0, time stamp: 0x5225df75
        Faulting module name: KERNELBASE.dll, version: 6.1.7601.18229, time stamp: 0x51fb1116
        Exception code: 0xe0434352
        Fault offset: 0x0000c41f
        Faulting process id: 0x1234
        Faulting application start time: 0x01cf688fe921b0c5
        Faulting application path: C:\Windows\EUC\BIN\Traymanager\TrayManager.exe
        Faulting module path: C:\WINDOWS\syswow64\KERNELBASE.dll
        Report Id: 36852185-d483-11e3-879b-80c16eebd0af

      • I am seeing the same problem on Windows 7×64 as reported by MattMcLane. I call traymanager without administrator rights. While I have not captured the detailed exception below I can recognize the error described by Matt McLane.

        This error happens infrequently but is never the less a big problem for production code
        I have never seen it on Win8 or Win10.

        The computers showing these errors are running corporate win7 images (I am not at liberty to reveal the company name, but its a Fortune 100). Sometimes their windows images behaves very slowly for reasons I am unable to explain. When that happens any operation done by any application on that computer takes several seconds to complete but it will eventually complete.

        My guess is that there is a timeout somewhere that kicks in and this causes the exception.

  13. Hello,
    Do you think it could be possible to write a similar solution entirely in C#?
    If necessary I will include C++ program with my C# problem but I would prefer to include this functionality inside my C# program.

  14. Hi, the download link for the compiled version Isn’t working anymore,
    can you update the link, because it’s exact what i’, m looking for

    Thanks!!!

  15. Thanks for working this all out!

    You mention that the signature for the Win 8 function is:

    HRESULT RegisterCallback (INotificationCB *,unsigned long *)

    do you know what the extra unsigned long parameter is for and what value it should be?

    Thanks 🙂

    • Hi,

      I dont know for sure, but my guess is that it specifies an identifier for the function.
      If you want to unregister the callback you also need the unsigned long parameter that refers to the function.

      • Hey, did somebody check detailed what UnregisterCallback on Win8 & Win8.1 is doing??
        It doesn’t work for me. UnregisterCallback doesn’t fire Release(AddRef opposite) callbacs for INotificationCB instance, as it is for RegisterCallback(NULL) -> unregistration on Win7 system. After all this leads to app crash. Coz there are still living com instance of callback inside com library and during com uninitialization time this callbacks are fired (but it can be too late) . You can prevent this situation to make instance of INotificationCB live, but it’s not good design, contrary to Win7 version you don’t want to do that (only 1 registered callback)…

  16. Thanks for sharing the great work. I’d like to look at the source code but the link seems to be down.
    Could you re-upload it?

    Thanks!

  17. I am trying to use this in a login script for a domain.

    Any reason why this should not work in the login script?

    When I run the command TrayManager.exe -p “Symantec Endpoint Protection” 2 from the command line, the SEP icon shows up in the Tray just fine, but when I run the same command from the login script, the SEP icon never gets promoted.

    Any idea why?

    Thanks

    • Hi Rick,

      I am trying to do the same for my users.
      Did you make any progress?

      When i excecute it manually, I have managed to clear all warnings (via GPO) and it runs perfectly.
      But for some reason a login script, batch script isn’t excuting. as well as with a delay.

      Regards, Rick B

  18. This is great work. Thanks for sharing. I’ve one question though, I’d like to see how the initial call is made for changing icon state when the program is run in silent mode. Could you please post the rest of the source files?
    Thanks again.

  19. Hi Guys. With the Windows 10 Build 1511 it the Tool stop working ;-(.

    If is a newer Version avalible?

    Thanks for your great works.

  20. Hi!
    I just tested it with Windows 10 Pro.
    It works at my machine.
    You have to use the winDows8 Dll for that.
    Please Dont forget to rename TrayNotificationManagementWin8.dll as described in the article.

      • Hi Mike

        We do that with Windos 8.1 and it works like a sharm. On Windows 10 the Settings are in the Appstore. The Tool works for One Time. When you have restartet the Maschine you lost the Settings. ;-(

      • It works on my win 10 machines, tried on all of them several reboots now and the settings are still ok.

      • HI Mike

        Thanks for your Feedback. Now it works without any Change on the Settigs. Very Strange. But It works ;-).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s