Click here to Skip to main content
15,881,898 members
Articles / Desktop Programming / Win32
Tip/Trick

.NET WinForms Tray Icon Implemenation with Win7 and Vista Features

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
23 Oct 2014CPOL5 min read 21.4K   957   25   6
.NET WinForms Tray icon implemenation with Win7 and Vista features: GUID identification, large custom icons, custom UI instead of the hint, etc.

Introduction

Some time ago, I noticed strange behavior of the Network Connections tray icon hint in Windows 7. I know that WinAPI limits tray icon hint with 64 characters (including the null-terminator), but this hint was multiline, was much longer than 64 characters text and some text was italic! (in Win8 italic disappears, just long multiline hint) So, it seems that Win7 knows much more about the tray icon hint that I know and that WinForms knows. After some lurking in stackoverflow and MSDN, I found that since Windows Vista WinAPI of tray icons was extended. But there isn't any documentation and/or .NET wrappers for new features (just MSDN enum/struct member descriptions). Even the WinAPI Code Pack ignores them.

It was found that noticed strange hint was not extended tray icon hint. New API allows applications to use their fully defined UI. And that is not the one new opportunity.

So, I decided to create my own implementation. It may be useful for anyone who builds applications with tray icons with C#/WinForms.

Background

As mentioned in MSDN, new API provides the following new features:

  • GUID-based icons identification (instead of old style HWND and icon index).
  • Large (32x32 instead of 16x16 pixels) system icons in notification balloons.
  • Custom icons in notification balloons.
  • Using application-defined UI instead of standard 64-characters limited hint.

I've researched the decompiled sources of the built-in NotifyIcon component and found it fully non-improvable. Firstly, it uses much of WinForms internal methods. I can call them via reflection, but there is too much code to be written to do this and too many resources will be consumed in runtime. Especially, if 70% of that was just WinAPI P/Invoke wrappers.

By design of WinAPI, there cannot be a tray icon without the window to handle its messages. NotifyIcon creates its own invisible window for this purpose and contains many hacks to make context menu from another window (user code window) work with it. This was the second and the main difficulty.

So, if I cannot use a part of existing and working code (and if this code contains too many "workarounds"), my implementation will be almost completely new. Also I don't like the solution with own window (to have a new window dedicated to handle tray icon messages while I always have an own window - at least the app's main form?..). Handling window messages requires access to WndProc of the window and I didn't find a solution to do this automatically, so my component will not be so easy for integration as the standard control... But I think it's worth it.

In common case, using of the extended tray icon tooltip requires writing this tooltip by your own. If there is no need in something unusual, there will be just a large multiline (but custom, in terms of new tray icon API) tooltip. Built-in WinForms ToolTip control is mostly dedicated to show tooltips for controls. It has a timer to show and hide and is a much linked with other controls. So, the new implementation of hint-like window was born too. Someone may say that I'm inventing bicycles. And may be someone will be right. But I don't think that we could force built-in ToolTip to show wherever we want something like this:

Using the Code

To use TrayIcon in your code, you must do the following:

  1. Add TrayIcon.cs and its dependencies to your project
  2. Rebuild it, to component appear in Forms Designer toolbox
  3. Place it on the form
  4. Set component's property OwnerForm to this (containing form, you may do it from PropertyGrid of design mode), set other properties as you desire (Icon, HintText, GUID and others). Set Enabled property to true to enable tray icon.
  5. In form's code, override WndProc and call there the WndProc of a TrayIcon. Somehow like this:
C#
protected override void WndProc(ref Message m)
{
    if (myTrayIcon.WndProc(ref m))
        return;

    base.WndProc(ref m);
}

TrayIcon will catch only tray-related messages and pass all others.

After all of this is done, you can enjoy a new tray icon with new notifications :). Like this:

Almost all new features are accessible from the TrayIcon properties and methods.

Extended tooltip is not the part of tray icon API, but this demo contains common implementation. To use it, set the ShowDefaultTips to false and set LongHintText to required long (and multiline) text. Demo works in Windows XP in compatible mode, so it is recommended to set also HintText to some short version of your hint. It will also be shown if ShowDefaultTips is enabled.

You can fully override the size and look of the tooltip. To do that, you must set your own handlers to TooltipMeasure and TooltipPaint events and do all measuring and render there. This demo also does this to show an icon in tooltip. To show completely different UI instead of the hint, handle the TooltipShown and TooltipClosed events to show and close your UI.

As there is a custom tooltip for tray icon, I've also done the implementation for other purposes. This is not the replacement of the standard ToolTip component, but it is also useful. CustomHint component uses the same principles of custom measuring and render. As it is fully custom, it has no connection with the controls, so it should be shown manually. Like this:

C#
private void lblCustomHintTest_MouseLeave(object sender, EventArgs e)
{
  customHint.Hide();
}

private void lblCustomHintTest_MouseEnter(object sender, EventArgs e)
{
  customHint.Show(PointToScreen(new Point(lblCustomHintTest.Left,
    lblCustomHintTest.Top + lblCustomHintTest.Height)));
}

After overriding its render, you may use in forms such strange things as this:

History

  • 22 Oct, 2014 - Discovered problem and made mostly working solution
  • 23 Oct, 2014 - Integrated in one of my projects and tested; made a demo project and uploaded it here
  • 29 Oct, 2014 - Update with custom hint and custom tray hint implementations

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Broken Event
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionwindows xp Pin
A Jordison27-Oct-14 9:11
A Jordison27-Oct-14 9:11 
AnswerRe: windows xp Pin
BrokenEvent27-Oct-14 10:14
BrokenEvent27-Oct-14 10:14 
QuestionI have used thing in the past Pin
Sacha Barber24-Oct-14 3:16
Sacha Barber24-Oct-14 3:16 
AnswerRe: I have used thing in the past Pin
BrokenEvent24-Oct-14 3:51
BrokenEvent24-Oct-14 3:51 
Questionmiss download link Pin
Member 404996323-Oct-14 19:36
Member 404996323-Oct-14 19:36 
AnswerRe: miss download link Pin
BrokenEvent24-Oct-14 2:16
BrokenEvent24-Oct-14 2:16 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.