Export (0) Print
Expand All
6 out of 13 rated this helpful - Rate this topic

Using the Microsoft .NET Compact Framework MessageWindow Class

.NET Compact Framework 1.0
 

Alex Yakhnin
IntelliProg, Inc.

March 2003

Applies to:
    Microsoft® .NET Compact Framework
    Microsoft Visual Studio® .NET 2003

Summary: Learn how to use the .NET Compact Framework MessageWindow class to create a NotifyIcon. (9 printed pages)

Download NotifyIcon.msi.


Contents

Introduction
Putting MessageWindow to work
Making the Client
Conclusion

Introduction

Although the Microsoft® .NET Compact Framework is a rich subset of the .NET Framework class library. Being a subset means that not all of the classes, methods and properties that are available on the full .NET Framework are available in the .NET Compact Framework. The interception of windows messages sent to managed controls is an example of this. The .NET Compact Framework does however implement a MessageWindow class that allows native and managed applications to communicate by way of Windows message constructs.

The MessageWindow is a part of the Microsoft.WindowsCE.Forms namespace, therefore adding the reference to Microsoft.WindowsCE.Forms.dll assembly to your .NET Compact Framework-based project is required. The MessageWindow class provides a WndProc method that is used to process the windows messages and exposes a valid window handle that is possible to pass to the native windows functions.

In order to use the MessageWindow in your program you need to create a new class by deriving it from the MessageWindow and override the default WndProc behavior to watch for the specific window messages:

[C#
using Microsoft.WindowCE.Forms;
public class MyMessageWindow : MessageWindow
{
  protected override void WndProc(ref Message msg)
  {
        switch(msg.Msg)
        {
            case WM_LBUTTONDOWN:
            //Do something here
break;
        }

        // call the base class WndProc for default message handling
        base.WndProc(ref msg);
 }
}

Putting MessageWindow to work

The best way to understand how to use the MessageWindow is by example.

We are going to create a NotifyIcon object that will allow us to place an icon on the Today screen's taskbar. It will also notify us when the user clicks on the icon so we can carry out the appropriate action.

The Window CE Platform API's include the Shell_NotifyIcon function that sends a message to the system to add, modify, or delete an icon from the taskbar status area. The Platform invoke prototype of this function would look the following way:

[DllImport("coredll.dll")]
internal static extern int Shell_NotifyIcon(int dwMessage, ref
  NOTIFYICONDATA pnid);

Where the NOTIFYICONDATA structure declared as:

struct NOTIFYICONDATA
{
    int cbSize;
    IntPtr hWnd;
    uint uID;
    uint uFlags;
    uint uCallbackMessage;
    IntPtr hIcon;
}

Please note that the NOTIFYICONDATA pnid parameter is declared to be passed by reference since Shell_NotifyIcon expects a pointer to the NOTIFYICONDATA structure.

The hWnd member in the NOTIFYICONDATA structure is the handle to the window that will receive notification messages associated with an icon in the taskbar status area. This is where MessageWindow will come handy.

Let's start from creation of the new Microsoft Visual C#™ Smart Device Application with the name NotifyClient and select the Pocket PC platform and Windows Application as s project type. Add the new NotifyIcon.cs class to the project and insert the following helper function that wraps a call to the Shell_NotifyIcon finction:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace NotifyClient
{

   public class NotifyIcon
   {

private void TrayMessage(IntPtr hwnd, int dwMessage, uint uID, IntPtr
  hIcon)
{
   NOTIFYICONDATA notdata = new NOTIFYICONDATA();

   notdata.cbSize = 152;
   notdata.hIcon =  hIcon;
   notdata.hWnd = hwnd;
   notdata.uCallbackMessage = WM_NOTIFY_TRAY;
   notdata.uFlags = NIF_MESSAGE | NIF_ICON;
   notdata.uID = uID;

   Shell_NotifyIcon(dwMessage, ref notdata);
}
}

}

In the code above we create the new instance of the NOTIFYICONDATA structure, assign all required members and pass it to the Shell_NotifyIcon function.

Now, it's time to create a subclass of the MessageWindow that is going to process the messages that are being sent from the Taskbar. Our new class WindowSink will be internal to the NotifyIcon since we don't want the client that is using the NotifyIcon class to be able to access the messaging loop that MessageWindow provides:

internal class WindowSink : Microsoft.WindowsCE.Forms.MessageWindow
{
   //Private members
   private int m_uID = 0;
   private NotifyIcon notifyIcon;
   //Constructor
   public WindowSink(NotifyIcon notIcon)
   {
      notifyIcon = notIcon;
   }

   public int uID
   {
      set
      {
m_uID = value;
      }
}


   protected override void WndProc(ref Message msg)
   {
         if (msg.Msg == WM_NOTIFY_TRAY)
      {
         if((int)msg.LParam == WM_LBUTTONDOWN)
         {
            if ((int)msg.WParam == m_uID)
            {
               //If somebody hooked, raise the event
               if (notifyIcon.Click != null)
                  notifyIcon.Click(notifyIcon, null);

            }
            }
      }

   }
}

In the WndProc override we are trying to catch our custom message WM_NOTIFY_TRAY to determine if the icon on the Taskbar was tapped. If that was the case we raise the Click event of the NotifyIcon class. The Click event needs to be declared in the NotifyIcon class as follows:

public event System.EventHandler Click;

Next we will add these public methods:

public void Add(IntPtr hIcon)
{
   TrayMessage(windowSink.Hwnd, NIM_ADD, (uint)uID, hIcon);
}

public void Remove()
{

TrayMessage(windowSink.Hwnd, NIM_DELETE, (uint)uID, IntPtr.Zero);
}

public void Modify(IntPtr hIcon)
{

   TrayMessage(windowSink.Hwnd, NIM_MODIFY, (uint)uID, hIcon);
}

Important:   It is very important to delete the icon from the Taskbar when the application exits. This is why we should add the clean up code in the NotifyIcon class's destructor:
//Destructor
~NotifyIcon()
{
   Remove();
}

This is essentially all the code that is needed to provide the required functionality.

Please keep in mind that this article presents only portions of the code. The entire sample is available as download, see top of article for link.

Making the Client

Now, is the time to put the created NotifyIcon class to work. As a first step we will add the application icon to the NotifyClient project we created. In order to do that you need to bring up the Project Properties Dialog by selecting Project—Properties from Visual Studio main menu. Choose the Application Icon item and assign the icon file of your choice.

Figure 1. Project properties dialog

When our program will be compiled the icon that we have chosen will become a native resource which is possible to retrieve by using the LoadIcon Platform API call:

[DllImport("coredll.dll")]
internal static extern IntPtr LoadIcon(IntPtr hInst, string IconName);

The second parameter in this function is the resource identifier of the application icon in the compiled program. By picking in the compiled executable with the resource explorer I have discovered that the application icon in .NET Compact Framework-based applications have the same resource identifier as native applications "#32512". So now we have all the necessary information in order to make a call to the NotifyIcon class. Let's snap two buttons onto the form and insert the following code on their click events:

private void cmdAddIcon_Click(object sender, System.EventArgs e)
{
   IntPtr hIcon = LoadIcon(GetModuleHandle(null), "#32512");
   notifyIcon.Add(hIcon);
}

private void cmdRemoveIcon_Click(object sender, System.EventArgs e)
{
   notifyIcon.Remove();
}

Let's not forget to hook up into NotifyIcon's Click event to get notified when the user taps the icon:

public Form1()
{
   //
   // Required for Windows Form Designer support
   //
   InitializeComponent();
   // Create instance
   notifyIcon = new NotifyIcon();
   // Hook up into event
   notifyIcon.Click+=new EventHandler(notifyIcon_Click);
}

private void notifyIcon_Click(object sender, EventArgs e)
{
   MessageBox.Show("Icon Clicked!");
}

So, after running our program, tapping the "Add Icon" button and switching to the Today view on the Pocket PC we should see our icon:

Figure 2. Today Screen

Tapping on the icon should now fire the notifyIcon_Click event and display a message box:

Figure 3. The trapped event

Conclusion

We have just finished creating the NotifyIcon class by utilizing the Windows CE API's through P/Invoke and using the MessageWindow class as a window that receives notification messages associated with the icon on the Taskbar.

Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft. All rights reserved.