Archive for the ‘Native Interop’ Category

Creating Managed Today Screen Items

Sunday, February 17th, 2008

Screenshot showing sample today screen item written in C#Today I thought I would demonstrate a proof of concept that may enable you to create today screen items in managed languages such as C# or VB.NET. In part this early preview was brought about by a recent request for advice on how to create managed Input Methods for the SIP keyboard, something that I think could be achieved using a similar approach. This is still a work in progress to see what is possible…. at the moment I have not fully evaluated the technique to be valid and/or tidied the code to my usual standard for release. I would love your feedback on this project.

Problem Definition

The Windows Mobile OS has a Today Screen API that enables custom items to be displayed on the main screen of the device. This API is highly geared towards native (C or C++) developers, and it is not possible for managed (VB.NET or C#) developers to implement the API directly.

Jim Wilson previously demonstrated in an MSDN article titled “Creating a Pocket PC Today Screen Plug-in with the .NET Compact Framework” a technique were a C++ based today screen item was developed to display HTML based content that was generated by a C# application. Although this is suitable for some applications it doesn’t lend itself to highly interactive or graphic intensive animated displays.

What we ideally want to do is to implement a minimal amount of native code that satisifies the requirements of the Today Screen API and have this native stub delegate all the GUI functionality off to a managed application.

It would also be extremely handy if the native part of this solution could be written once and reutilised among multiple managed today screen items. In part because this would open up today screen item development to those developers who currently don’t have experience in developing native code.

Solution Architecture

Architecture of a managed today screen item solutionMy solution utilises a native today screen item written in C++. This today screen item is implemented in a DLL called ManagedTodayScreenItem.dll. The OS is configured to load this item into the today screen process. However unlike other today screen items this one looks up additional configuration data stored in the registry to determine the name of a managed (i.e. VB.NET or C#) executable that should be launched when it is first displayed.

The managed executable starts up as normal and displays it’s main form. However once displayed the managed process then proceeds to establish an inter-process communication (IPC) channel back to the native today screen item. Once this channel is established the managed application informs the native today screen item of it’s window handle. The native today screen item then reparents the managed form to be a child of the today screen item and resizes it to fit the space allocated to the today screen item.

From this point on the illusion of a managed today screen item has been made. Whenever the managed form needs to act like a today screen item (such as painting the today screen watermark on it’s background) it can communicate with the native today screen item stub, and conversely whenever the native stub detects a change in it’s size or location it can communicate this change back to the managed part of the item.

Creating a new today screen item

Creating a new today screen item with this framework is relatively easy. Perhaps the easiest way is to modify the SampleTodayScreenItem example within the sample application mentioned below.

If you are creating a today screen item from scratch you need to follow these steps:

  1. Create a new Smart Device Application (win forms project).
  2. Change the FormBorderStyle property of the main form to None. As discussed previously this enables us to make the form non fullscreen.
  3. Add a reference to the Christec.WindowsMobile.TodayScreen.dll assembly found in the sample project below.
  4. Change the main form to derive from the TodayScreenPluginForm base class.

The last step is very important. The TodayScreenPluginForm class itself derives from Form but overrides a couple of methods (such as OnPaint) to ensure the form has the look and feel of a today screen item. This base class also behind the scenes sets up the inter-process communication channel which allows the managed part of the solution to communicate with the native part.

Your form source code should look something like the following after these changes:

using Christec.WindowsMobile.TodayScreen;
 
public Form1 : TodayScreenPluginForm
{
  public Form1()
    : base(4567)
  {
    InitializeComponent();
  }
}

A key thing to point out here is the call to the TodayScreenPluginForm constructor that accepts an integer parameter. This integer is an id that is a unique value that identifies this particular today screen plugin. This is the part of the framework that enables the one native today screen item to be reutilised multiple times by different managed plugins (since each managed plugin should be given a different id value to differentiate itself).

Once the managed executable has been created as described above and compiled all that is required is a couple of registry settings to be added to make the operating system aware of the new today screen item. These registry settings are as follows:

Underneath HKLM\Software\Microsoft\Today\Items\<Name>

  • DLL = “\Windows\ManagedTodayScreenItem.dll”
  • Flags = 4567
  • Name = “A name for the item”
  • Options = 0
  • Type = 4

<Name> within the registry key above should be replaced with the name you want to be visible to the user within the Today Screen control panel applet. All these registry values should be identical for each managed today screen plugin you develop. The only difference should be the value you use for the Flags setting. This should match up with the value you passed into the TodayScreenPluginForm constructor within the source code of the managed part of your today screen item.

The native ManagedTodayScreenItem.dll today screen item utilises this “flags” value to lookup another set of item specific registry keys to determine which managed executable needs to be executed as outlined below:

Underneath HKLM\Software\ChrisTec\ManagedTodayScreenPlugins\<id>

  • (default) = “\path\to\managed\executable.exe”
  • Height = height of today screen item in pixels.

<id> within the registry key above should be replaced with the unique id value (4567 in the example) for your managed today screen item. At present it is not possible to dynamically change the height of the today screen item at runtime. This would be something that is reasonably easy to implement but is one of the features I have not implemented yet as it wasn’t required in order to prove the validity of the concept.

Sample Applicaton

[Download managedtodayscreenitem.zip - 37.1KB]

The sample project that is available for download contains two CAB files within a subdirectory called “bin”. These are as follows:

  • ChrisTec.WindowsMobile.TodayScreen-Framework.cab – installs the native part of the today screen item framework. This part can be shared among multiple managed today screen items and only needs to be installed once per device. It can be thought of as being similar to the .NET CF or SQL Server CE CAB files that install a framework for other applications to utilise. This cab file can also be utilised by managed developers who are not comfortable rebuilding the C++ source code.
  • SampleTodayScreenItem.cab – An example today screen item written in C#. It simply consists of three buttons with each button displaying a simple message box once clicked.

If both of these CAB files are installed on a Pocket PC device and the device is then soft reset you should see the new today screen item appear.

If you would like to have a go at creating your own managed today screen item you should also find a pre-compiled copy of the Christec.WindowsMobile.TodayScreen assembly that you will need to reference within this directory.

Within the other subdirectory (called “src”) you should be able to find solution files that will enable you to rebuild the two CAB files mentioned above.

Outstanding Tasks

As I stated in the introduction, this project is an early proof of concept that I have decided to share early on in the hope that it helps a few people and perhaps gets a couple interested in contributing. Since the code is not fully released there are a number of known issues and outstanding tasks.

Some of these are as follows:

  1. Slight compatibility issues on Pocket PC 2003 devices after a soft reset.
  2. Does not handle the managed application crashing in the most robust manor.
  3. The Visual Studio IDE experience could be improved with project item templates etc.
  4. Having multiple managed today screen items share the single native dll probably doesn’t work (needs a little more work).
  5. The Christec.WindowsMobile.TodayScreeen assembly should be placed into the Global Assembly Cache (GAC).
  6. It would be great if less registry configuration is required.

Summary

Hopefully this blog entry will cause some interest, as I know developing custom today screen items in managed code is a frequent question on online developer help forums. Although this solution isn’t fully complete and isn’t the most straight forward to configure (at present at-least) the results I have managed to get so far are encouraging.

If this proof of concept can validate the technique I am using to host .NET Compact Framework based forms within native processes I can see no reason why it would not work in other situations such as custom SIP based keyboards. The only difference would be the native component that would need to wrap up the native API provided by the operating system.

I would be really keen to hear your feedback and thoughts on this prototype. Especially if you are able to give me a hand to further validate and develop the concept.

Sharing Platform Invoke code between the Desktop and Compact Framework

Saturday, December 15th, 2007

Previously we discussed techniques for backwards compatibility when accessing new APIs within native applications. This blog posting discusses how similar techniques can be used by .NET Compact Framework developers utilising Platform Invoke functionality.

.NET Compact Framework developers inherently have a head start, as utilising Platform Invoke functionality means they are always implicitly dynamically linking to native APIs.

Building Assemblies that work on Desktop and PDA
Screenshot of sample .NET Compact Framework application running on a Desktop PC running Microsoft VistaIf you build your application as a Smart Device project you will find that you can get your executable to also run on the full .NET Framework without modification.

The magic that allows this to happen is a new feature Microsoft introduced with .NET Framework v2.0 called retargetable assemblies. An assembly which is marked as retargetable can be substituted with a compatible assembly from a different publisher.

The .NET Compact Framework base class libraries (such as System.Data.dll) are retargetable. This allows the desktop assembly loader (fusion) to substitute them for the desktop versions of these assemblies when the executable is ran on a Desktop PC.

The reverse is not possible. I.e. an assembly built against the desktop assemblies will fail to run when placed on a device running the .NET Compact Framework.

You have to be careful while using this feature. If you manage to use a feature only present in the .NET Compact Framework version of an assembly, a TypeLoadException will occur when your application attempts to run on a desktop PC,.

Dealing with non existant APIs
Sometimes you may need to access an API which is only available on a particular platform or device and it is important to handle the error cases which may occur when the application runs on a platform that does not support the API.

Internally the Platform Invoke functionality calls the LoadLibrary and GetProcAddress system APIs discussed when we talked about native platform compatibility. If either of these APIs return failure codes the .NET Compact Framework Platform Invoke functionality will cause an exception to be thrown. We will again use the SndPlaySync API to demonstrate this.

// Declare the SndPlaySync API as being a native function present
// within the aygshell.dll file
[DllImport("aygshell.dll")]
private static extern int SndPlaySync(string pszSoundFile, UInt32 dwFlags);
 
...
 
try
{
  // Attempt to call the SndPlaySync function
  SndPlaySync(@"\Windows\Alarm2.wav", 0);
}
catch (DllNotFoundException ex)
{
  // deal with the DLL not being present
  // at all
}
catch (MissingMethodException ex)
{
  // deal with the method not being found
  // within the dll
}

If we ran this application on a desktop PC we would expect to receive a DllNotFoundException, this is because the aygshell.dll file does not exist on a desktop PC.

If we ran this application on a PDA running Windows Mobile 5.0 or lower we would expect a MissingMethodException, since these platforms have an aygshell.dll, but it does not provide the SndPlaySync API.

In a real application we may like to handle these exceptions by attempting to use an alternative, or less capable technique to implement the same functionality. For example we may fall back to using an older API with less features, or disable some element of our user interface.

Dealing with APIs that exist in different locations
Windows CE (the operating system Windows Mobile is based upon) aims to have a Win32 API implementation which is fairly compatible with the implementation found in desktop versions of the Microsoft Windows operating system. However for a number of technical and historical reasons the APIs are commonly exposed by different DLLs. This leads to a potential issue since the DLLImport attribute utilised to Platform Invoke a function requires hard coding the DLL’s name into your application as shown below.

// MessageBox is found within coredll.dll
[DllImport("coredll.dll")]
private static extern int MessageBox(IntPtr hWnd, String lpText,
  String lpCaption, uint uType);

We can work around this problem by having more than one Platform Invoke declaration for our desired function. We can have one declaration for each platform we target, with the only difference being the DLL specified. For example:

// MessageBox is found in coredll.dll on Windows Mobile
[DllImport("coredll.dll")]
private static extern int MessageBox(IntPtr hWnd, String lpText,
  String lpCaption, uint uType);
 
// MessageBox is found in user32.dll on Desktop PCs 
[DllImport("user32.dll")]
private static extern int MessageBox(IntPtr hWnd, String lpText,
  String lpCaption, uint uType);

However if we attempt to compile this the compiler would tell us that we have duplicate definitions for the MessageBox function. We can get around this by giving them different names and using the optional EntryPoint field of the DllImport attribute to define the actual name of the function within the DLL.

[DllImport("coredll.dll", EntryPoint="MessageBox")]
private static extern int MessageBox_WCE(IntPtr hWnd, String lpText,
  String lpCaption, uint uType);
 
[DllImport("user32.dll", EntryPoint="MessageBox")]
private static extern int MessageBox_WIN(IntPtr hWnd, String lpText,
  String lpCaption, uint uType);

Having these two definitions gives two uniquely named functions as far as the C# compiler is concerned, but both attempt to access a function called MessageBox in their respective DLLs.

We can then produce a small wrapper function which hides this difference and automatically calls the correct method based upon the current platform the application is running on.

int MessageBox(IntPtr hWnd, String lpText,
  String lpCaption, uint uType)
{
  if (Environment.OSVersion.Platform == PlatformID.WinCE)
    // call the Windows CE version of this function
    MessageBox_WCE(hWnd, lpText, lpCaption, uType);
  else
    // call the desktop version of this function
    MessageBox_WIN(hWnd, lpText, lpCaption, uType);
}

Sample Application

[Download CrossPlatformTest.zip - 9.9KB]

A small sample application is available to demonstrate these two techniques. Once the application is built you should be able to run it on both the Windows Mobile 5.0, and 6 Device Emulators, as well as your Desktop PC (for this navigate to the executable on your hard-drive and double click it).

The first button should display a message box (similar in functionality to the built in System.Windows.Forms.MessageBox class). If you step through the code you should see that different DllImport statements are used to take care of the different DLLs this API lives in on Windows Mobile devices and Desktop PCs.

The second button attempts to play a sound via the SndPlaySync API which is present on Windows Mobile 6 and above. If you run this example on any other platform you should get a message box indicating an error. The message displayed demonstrates the different type of exceptions which may be thrown when the API is not present on a given platform.

Making use of new APIs within older applications

Tuesday, December 4th, 2007

Each new release of the Windows Mobile platform tends to introduce a couple of new APIs. This blog post discusses a technique that Native developers can use to allow conditional access to these APIs while still allowing the application to run on older devices.

Introduction
Typically a developer creating a C or C++ application within Visual Studio would choose a device SDK that matches their target device. For example when creating a project for a Windows Mobile 6 Professional device the developer would typically select the “Windows Mobile 6 Professional” SDK within the New Project wizard. Compiling with a particular Device SDK “marks” the executable in such a way that it requires as a minimum that particular version of Windows Mobile in order to run.

Since the Windows Mobile platform strives for backwards compatibility this should also mean that the application would work on any newer version of the OS (but it would be constrained to accessing the subset of functionality exposed by the selected SDK).

Visual Studio includes a tool called Dependency Walker. Opening an exe or dll file within this application allows you to determine which version of the Windows Mobile OS an executable is designed for. This tool can typically be found within the C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\Bin directory. The “Subsystem Ver” field as indicated in the above screen-shot shows the minimum version of the Windows CE kernel required for the selected program to run (see “What device is my application running on?” for a table of Windows CE kernel versions and their associated Windows Mobile releases). Trying to run an executable compiled for a newer version of the OS on an older version will result in an error message similar to the following:

Dependency Walker (as it’s name suggests) also allows us to determine which DLLs an executable depends upon and hence must be present on the device in order for the application to run. For example in the following screenshot the application has dependencies on aygshell.dll, phone.dll, and coredll.dll. If any of these DLLs are not present on a device, the OS will fail to start the application with the same error message shown above.

Accessing APIs from newer versions of the OS
Some times it is necessary to compile against an older device SDK while still allowing access to new APIs whenever the application is running on a newer device.

As an example, a previous project I worked on was compiled against the Pocket PC 2002 SDK, and there were a couple of hundred Pocket PC 2002 devices out in the field. When Windows Mobile 2003 Second Edition devices started showing up (which support dynamic screen orientation changes), it was desirable to access a new API to ensure the application always ran in Portrait mode, without switching the project over to the Pocket PC 2003 SDK (since that would mean needing to compile two versions of the app, or loosing support for the existing Pocket PC 2002 devices).

As an easy to follow example we will use the SndPlaySync API introduced in Windows Mobile 6, and discuss how to access this while building our application against the Pocket PC 2003 SDK.

When targeting the Windows Mobile 6 Professional SDK we could make use of this API as follows:

// Play the Alarm2.wav sound effect
#include <soundfile.h>
SndPlaySync(_T("\\Windows\\Alarm2.wav"), 0);

However attempting to run this executable on a Pocket PC 2003 device will fail because:

  1. The executable is marked as requiring Windows CE OS version 5.02 or higher.
  2. The executable indicates it depends upon a function called SndPlaySync being present within a dll called aygshell.dll. Although aygshell.dll exists on a Pocket PC 2003 device, it does not export a function called SndPlaySync.

Both of these facts can be confirmed via the use of the Dependency Walker utility as discussed above.

If we change our project to target the Pocket PC 2003 Device SDK we will notice that the project fails to compile. This makes sense, since changing the SDK changes the version of the Windows header files our project compiles against. The Pocket PC 2003 version of the Windows header files are clearly highlighting the fact that the SndPlaySync function does not exist on this version of the platform.

One solution to this problem is to dynamically link to this API. In other words when our application runs we manually load aygshell.dll and attempt to find the SndPlaySync function within it. If we find it we can make use of it, otherwise we can fail gracefully and provide some kind of fallback.

Within the Win32 programming environment we do this by making use of a function pointer typedef and the LoadLibrary and GetProcAddress APIs.

By looking at the MSDN documentation for SndPlaySync we can typically determine which DLL the API lives within, and determine a function prototype that is suitable for converting into a function pointer typedef. Depending upon the API in question, we may also need to copy any structs or #define’s utilised by the function that are not present in the older Windows Mobile header files.

An example of this technique is shown below:

// A typedef that defines a function pointer called SND_PLAY_SYNC that
// is capable of pointing to any function that has the same
// prototype as SndPlaySync
typedef HRESULT (* SND_PLAY_SYNC)(LPCTSTR pszSoundFile, DWORD dwFlags);
 
// Attemp to load aygshell.dll
HMODULE hLib = LoadLibrary(_T("aygshell.dll"));
if (hLib)
{
  // If we manage to load it attempt to get the address
  // of the SndPlaySync API located within it.
  SND_PLAY_SYNC pfnSndPlaySync =
    (SND_PLAY_SYNC)GetProcAddress(hLib, _T("SndPlaySync"));
 
  // If SndPlaySync is found then invoke it. Otherwise
  // provide a simple fallback, in this case a simple
  // message box. A more complete example may
  // have used an alternative sound playing API.
  if (pfnSndPlaySync)
    pfnSndPlaySync(_T("\\Windows\\Alarm2.wav"), 0);
  else
    MessageBox(GetForegroundWindow(),
      _T("Sorry we can not play a sound"),
      _T("Status"), MB_OK);
 
  CloseHandle(hLib);
}

This solution doesn’t magically make the API available on older devices. The key thing is it delays the check for the SndPlaySync API being present from launch time (by the OS) until runtime (by our code). If you use the Dependency Walker utility you will notice that there is no hard-coded dependency on the SndPlaySync API within this version of the application.

Sample Application

[Download BinaryCompatabilityExample.zip - 16KB]

A small sample application is available for download. It contains two projects. The first called “BadApp” targets the Windows Mobile 6 SDK and will fail to run on devices using an older version of the OS. The second called “GoodApp” targets the Pocket PC 2003 SDK and shows how to modify the source code of “BadApp” in order to make the application also run on older devices. As an added bonus the sample demonstrates how this solution can also resolve issues with devices using the same OS version but having different hardware capabilities. This issue has been discussed by Mel Sampat in regards to accessing phone functionality (some PDAs still come without any cellular capabilities).

A future blog posting will discuss how similar techniques can be implemented for .NET Compact Framework applications which use Platform Invoke (DllImport) functionality. This can be particularly handy for getting an application that makes use of PInvokes to work on both the desktop and PDA devices without the need of conditional compilation and multiple versions of the executable.

Send and receive Win32 messages in managed code by using the MessageWindow class

Tuesday, July 31st, 2007

The System.Windows.Forms namespace is a wrapper around the native Win32 GUI functionality provided by the operating system. The .NET Framework does a pretty good job at hiding the specifics of the Win32 APIs from managed developers, providing them with a more object orientated programming model. However the managed wrappers do not provide access to all features present in the underlying OS. This is especially true of the .NET Compact Framework. One technique to access native functionality which is not supported by the .NET Compact Framework is to send window messages. This is the subject of this blog entry.

Requirements
This blog entry is specific to .NET Compact Framework v2.0 or higher. Although most of the concepts are usable in .NET Compact Framework v1.0, you will need to do some additional work, since some of the properties utilised in the samples are not directly available in the older version of the .NET Compact Framework.

To get the code samples within this blog entry to compile within your projects, you must:

  • Include a reference to the Microsoft.WindowsCE.Forms assembly
  • Include a “using Microsoft.WindowsCE.Forms” statement at the top of your source code file

What is a Window and what is a Message?
The Win32 GUI platform is built around the concept of “windows”. A window is a rectangular section of the screen. Any window can also have additional child windows, which are windows contained within the rectangular space allocated to their parent.

The concept of a window is an overloaded term. The Win32 Operating System APIs not only consider Forms to be windows, but also controls you commonly place on a form such as TextBoxes or Labels. What differentiates the behavior and look and feel of these different windows is their “window class”.

Within the Win32 GUI API windows communicate with each other via the concept of messages. Messages are sent to a specific window to inform them whenever events such as typing, or tapping on the screen occur. Other window messages are of a more house keeping nature and indicate that a window should repaint itself etc.

For the purposes of the Win32 GUI APIs a windows message has the following properties:

  • Message Type – used to differentiate between different types of messages
  • WParam – a value, the meaning of which depends upon the type of message
  • LParam – essentially the same as WParam, another message type dependent field

Within the .NET Compact Framework, a window message is represented by the Microsoft.WindowsCE.Forms.Message class.

Finding a Window Handle
In order to send a message to a window you must obtain it’s handle. A handle is simply a special value which uniquely identifies a particular window to the native Win32 GUI APIs.

In many cases you can easily obtain a window handle for a control within your application by querying the Handle property of the desired control. This property is available on all the GUI controls (including forms), because they all eventually derive from the Control base class.

The following example demonstrates how you may obtain the window handle of a textbox placed onto your form:

private void button1_Click(object sender, EventArgs e)
{
  // Obtain the window handle for a textbox control
  // called 'textBox1' which we have placed onto the form
  IntPtr hwnd = textBox1.Handle;
}

By convention window handles are typically referred to as HWNDs, this is Hungarian notation for “Handle to a Window” and can be traced back to the days when C developers prefixed their variables with a description of the variable’s data type.

Sometimes you need to send a message to a window created by another application. In this scenario you do not have a Control instance to query the Handle property. In this case you need to ask the operating system to search for the window given it’s name.

The .NET Compact Framework does not support this, so you will need to Platform Invoke a native Win32 API called FindWindow, as the following example demonstrates:

using System.Runtime.InteropServices;
 
[DllImport("coredll.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
 
private void button1_Click(object sender, EventArgs e)
{
  // Find a window with the name "Test Application"
  IntPtr hwnd = FindWindow(null, "Test Application");
}

Fabien Decret mentions in his blog posting titled “Find a Window Handle” how you can use the Remote Spy utility to determine the name and window class of a particular window.

Sending a Message
To send a message to a window we simply create an instance of the Message class and configure it’s properties to the desired values. We then pass the message along to the MessageWindow.SendMessage static method to have it sent.

The following example demonstrates how to send a WM_CLOSE message to the File Explorer application, which will have the effect of closing it.

// Define the window message we want to send
const int WM_CLOSE = 0x10;
 
// Find the window we want to send the message to
IntPtr hWnd = FindWindow(null, "File Explorer");
 
// If the window was found, ask the application to close
if (hWnd != IntPtr.Zero)
{
  // Create a WM_CLOSE message (it doesn't use the lParam
  // and wParam fields so we set them to zero) and send the
  // message to the window
  Message msg = Message.Create(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
  MessageWindow.SendMessage(ref msg);
}

The documentation for the WM_CLOSE window message can be found on MSDN. This documentation explains the interpretation of the lParam and wParam parameters, as well as outlining at the bottom of the page, which header file we need to look in to obtain the value of WM_CLOSE (i.e. 0×10).

There is also a MessageWindow.PostMessage method, which is utilised the same way as SendMessage except that unlike SendMessage it does not wait for the message to be processed by the window it is sent to before returning.

Receiving a Message
On the desktop, the Control class provides a WndProc method which can be overridden to process any window message sent to the control. The Compact Framework however does not provide the WndProc method for us to override, so there is no (easy) way to see window messages sent to a control.

The .NET Compact Framework instead has a special class called MessageWindow which enables the creation of a hidden window that provides a virtual WndProc method which can be overridden to process any window messages sent to it.

To make use of this class applications must derive a class from MessageWindow and then override the WndProc method so that messages sent to the window can be processed.

The following code sample shows how to derive a class from the MessageWindow base class:

public class MyMessageWindow : MessageWindow
{
  // The window message type we want to process
  public static readonly int WM_USER = 0x400;
 
  // This method gets called for every window message this
  // window receives.
  protected override void WndProc (ref Message m)
  {
    // Check if it is a message we want to handle
    // based upon it's message type
    if (m.Msg == WM_USER)
    {
      // This is a message we recognise, so lets
      // process it. In this case we'll display a message
      // box
      MessageBox.Show("Hello - i received a window message");
    }
 
    base.WndProc (ref m);
    }
}

Because this is a managed application, there is no definitions available for the standard window messages such as WM_USER. A glance at the MSDN Documentation for WM_USER will confirm that the definition can be found within the C header file winuser.h, managed developers need to duplicate this definition in their own applications, as the code sample demonstrates. WM_USER is a good message number to utilise, since Microsoft defines this message number as the starting point for user defined messages.

Once we have defined our MessageWindow subclass we simply need to create an instance of the class to create the hidden window. The class has an Hwnd property which provides the window handle we need to send messages to in order for them to be processed by this window.

The following code sample demonstrates how to create an instance of the MyMessageWindow class, and then send a window message to it.

// Create the hidden window
MessageWindow msgWindow = new MyMessageWindow();
 
// Send a message to it
Message msg = Message.Create(msgWindow.Hwnd,
    MyMessageWindow.WM_USER, IntPtr.Zero, IntPtr.Zero);
MessageWindow.SendMessage(ref msg);

The previous code sample is not a typical use case of a message window. Typically the window will be created by one part of an application, and a message will be sent to the window from an unrelated part of the application (or even another application entirely). This leads to a problem, since the code which sends the window message will typically not have access to the window handle (Hwnd property value) to know where to send the message.

In this case you may like to set your MessageWindow’s Text property to something uniquely identifiable as your application. You can then use the FindWindow approach mentioned previously to find the window handle by passing in the same string.

Practical Uses
Sending window messages can be utilised for a number of purposes, but they are mainly utilised to interface to external applications. The following references are to real life situations where sending window messages is useful:

Sample Application
I have put together a small sample application to demonstrate some of these techniques. the easiest way to play with the demo is to open up the “SenderApplication” and “SecondApplication” projects into two instances of Visual Studio 2005. You will then be able to follow the “demo script” below:

  1. Start the “SecondApplication” in the debugger (press F5)
  2. Start the “SenderApplication” in the debugger (press F5 – also ensure you select the same emulator/device)
  3. Click the “Click another button” button and notice how the application behaves as if the “Show a Message Box” button was pressed. This is because a button click window message is being sent to the message box button whenever the first button is clicked.
  4. Click the “Display message in another app” button. Notice how the second application pops up and displays a message box stating the current state of the checkbox in the first application. This is because the “SenderApplication” has sent a window message to the MessageWindow created by the “SecondApplication”.
  5. Dismiss the message box and minimise the “SecondApplication” to return to the “SenderApplication”.
  6. Change the state of the checkbox and click the “Display message in another app” button a couple of times to see how the two applications are communicating the state of the checkbox.
  7. Press the “Close other app” button, and notice that the “SecondApplication” application shuts down (which will cause Visual Studio to stop debugging that project).

This blog entry neatly covers some of the background theory on something I have been working on quietly in the past few days, hopefully early next week I’ll have an interesting application to blog about….