WPF “Hello World” for the .NET Micro Framework

November 27th, 2007

Screenshot of WPF Hello World application running within an emulator

The first time I heard that the .NET Micro Framework’s GUI framework was Windows Presentation Foundation (WPF) I was excited but wanted to know more. How could such a “big” framework be compressed for use on such a small device, with little to no OS for support?

This blog entry discusses the structure of simple WPF applications written for the .NET Micro Framework and outlines some of the differences when compared against the WPF framework found on the desktop.

The WPF implementation found within the .NET Micro Framework shares many of the same underlying structures and concepts as the desktop version of WPF, but the implementation and capabilities are completely different. For example there is no declarative markup language (XAML), no data binding, no visual form designer and the namespaces are slightly different.

Getting Started
To get started create a new .NET Micro Framework Console application from within Visual Studio 2005 and delete the contents of Program.cs. We would typically use the “Windows Application” template, but since we want to learn the purpose of the code generated by that template we will code it all from scratch.

We also need to add a couple of additional references to our Project in order for the compiler to find the WPF related classes:

  • Microsoft.SPOT.TinyCore
  • Microsoft.SPOT.Graphics

Creating a window
A window is represented by the Microsoft.SPOT.Presentation.Window class. Typically a subclass of this class will be produced to encapsulate as much window specific logic as possible for each type of window within our application. Since we don’t have a Visual Form designer or XAML we must hand code this in C# directly.

Our main window could be represented as follows:

using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Media;
 
public class MainWindow : Window
{
  public MainWindow() 
  { 
    // Make the window the same size as the LCD screen
    this.Width = SystemMetrics.ScreenWidth;
    this.Height = SystemMetrics.ScreenHeight;
 
    // Make the window have a red background
    this.Background = new SolidColorBrush((Color)0x0000FF);
  }
}

The constructor provides an ideal place to configure the look and feel of our window. In this example we configure the initial width and height of our window to be the same size as the LCD screen found on our device. We also give it a solid red background fill.

Creating an Application
A WPF application is represented by the Microsoft.SPOT.Application class. This class manages the display of windows and routes events from the hardware to the active window’s controls etc.

To display our main window on the screen we must create an instance of our application and call it’s Run method, passing in the main window. Like standard desktop .NET applications, the main entry point of an application is its static Main method and this provides an ideal place to perform this initialisation step as shown below:

using System; 
using Microsoft.SPOT; 
 
public class Program : Application 
{
  // This is the method the .NET Micro Framework
  // will call when our application starts running 
  public static void Main() 
  { 
    // Create an instance of the Application
    // and our main Window class
    Application myApplication = new Program(); 
    Window myWindow = new MainWindow(); 
 
    // Ask the application to display the
    // initial window, and don't return until
    // it is closed.
    myApplication.Run(myWindow);
  }
}

When you run this application you should see a solid red window covering the entire screen. It’s pretty boring! Since there is no way (presently) to close this window the call to myApplication.Run will never return.

Adding content
A window can hold a single control, this is because it derives from ContentControl. This class provides a Child property to specify the control which should be displayed within the client area of the window.

Most of the standard controls can be found within the Microsoft.SPOT.Presentation.Controls namespace. The two we will cover in this blog posting are the Text and Image controls.

Displaying Text
To place a string of text on a window we can use the following code snippet at the end of our Window’s constructor:

Font font = Resources.GetFont(Resources.FontResources.small);
this.Child = new Text(font, "Hello World!");

This code refers to a font called “small”. The .NET Micro Framework by default has no fonts, so we must include this font resource as an embedded resource within our application. We do this by following these steps:

  1. Open Resources.resx within the designer
  2. Open the Files section and select to add an existing file
  3. Navigate to the C:\Program Files\Microsoft .Net Micro Framework\v2.0.2036\Fonts\ directory and select “small.tinyfnt”.

By default there are only a couple of fonts to choose from. With Service Pack 1 of the .NET Micro Framework there is also a conversion utility which allows you to convert any TrueType font you may have into the required format.

Displaying an Image
To place an image on a window we make use of the Image control. The easiest way is to simply pass the bitmap we want to display in as a constructor parameter as shown in the below code snippet:

Bitmap bmp = Resources.GetBitmap(Resources.BitmapResources.sample);
Image img = new Image(bmp);
this.Child = img;

We could use the bitmap drawing techniques discussed last time to dynamically create a bitmap to display, or we could embedded an image into our executable. To embedded an image such as the “sample” image in the above example, we follow a similar process to adding a font to our resources.resx file, only this time we select the “Image” section instead of the “Files” section.

By default the image or text will be rendered in the top left corner of the area provided by the window. By changing the HorizontalAlignment and VerticalAlignment properties we can modify this to move the image into the center of the area given to the control. For example to center the image in the previous example we could add the following two lines of code to the Window’s constructor:

img.VerticalAlignment = VerticalAlignment.Center; 
img.HorizontalAlignment = HorizontalAlignment.Center;

Sample Application

[Download wpf-hello-world.zip - 6.7 KB]

A small sample application is available for download. This application demonstrates the techniques outlined within this blog entry and displays the classic “Hello World” message to the user.

The next post on the .NET Micro Framework will discuss how to add more than one control to a window and how to control the size and location of these controls. After that posting we will finally be at the stage where we are ready to discuss how to generate and respond to keyboard or button press events. This will also enable us to discuss how to create multiple windows and close them etc.

Drawing shapes with the .NET Micro Framework

November 19th, 2007

This blog entry is a lead in to a new series of articles about developing GUIs with the .NET Micro Framework.

A good place to start when learning a new GUI framework is to learn how to draw simple graphics. This blog entry discusses how to draw simple graphics with the .NET Micro Framework.

Creating a Bitmap
The Microsoft.SPOT namespace contains a Bitmap class which represents a bitmap image. To create a bitmap the same size as your physical screen you could use a code snippet such as the following:

using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
 
Bitmap bmp = new Bitmap(SystemMetrics.ScreenWidth,
     SystemMetrics.ScreenHeight);

Once you have a bitmap you can draw on it by using the various instance methods of the Bitmap class. When your drawing is completed, you need to copy the bitmap to the LCD screen in order for it to become visible. The framework provides a Flush() method to perform this task. Calling Flush() on your bitmap will copy the bitmap data to the LCD screen.

Bitmap bmp = new Bitmap(SystemMetrics.ScreenWidth,
     SystemMetrics.ScreenHeight);
// ... do drawing stuff here ...
bmp.Flush(); // copy bitmap to LCD

It is important to note that to use the Flush() method your bitmap must be exactly the same size as the LCD display. Otherwise the flush will simply not work, even though no exception or debug diagnostic will indicate a problem while debugging. This is a common trend with many of the .NET Micro Framework Base Class Library methods.

Representing Colours
A colour is represented by the Color enumeration found within the Microsoft.SPOT.Presentation.Media namespace.

This enumeration only has the values Black and White pre-defined. For example to specify the colour White you could use a code snippet such as the following:

using Microsoft.SPOT.Presentation.Media;
Color white = Color.White;

It is possible to specify other colours by specifying the red, green and blue intensity values that make up the desired colour. To do this you use a static method within the ColorUtility class called ColorFromRGB as shown below:

using Microsoft.SPOT.Presentation.Media;
// Specify full intensity red
Color red = ColorUtility.ColorFromRGB(255, 0, 0);

The parameters passed to ColorFromRGB are the Red, Green and Blue components of the desired colour. These values are all bytes which range from 0 to 255 (full brightness).

ColorFromRGB basically encapsulates some simple bit shifts and a typecast. Internally the .NET Micro Framework represents colours as 3 8bit fields packed into a single 32bit unsigned integer. Instead of using the ColorFromRGB method we can perform a manual typecast between a suitable number and the Color enumeration as follows:

using Microsoft.SPOT.Presentation.Media;
//                 0xBBGGRR
Color red = (Color)0x0000FF;

The format when the value is expressed in hexadecimal is 0xBBGGRR, i.e. 8 bits red (R), 8 bits green (G), followed by 8 bits blue (B). So the above example creates a red colour with full intensity.

Drawing Shapes
The bitmap class has numerous methods available for drawing the outlines of basic shapes such as lines, rectangles and ellipses.

Drawing lines:
draw_line.png

// Draw a red line 10 pixels thick
// between (x=20, y=30) and (x=40, y=50).
bmp.DrawLine(red, // colour
     10,  // thickness
     20,  // x0
     30,  // y0
     40,  // x1
     50) // y1;

A line is specified by providing the colour, thickness and start and end co-ordinates of the line. The current implementation of the .NET Micro Framework base class library appears to ignore the thickness parameter, all lines are drawn 1 pixel wide.

Drawing rectangles:
draw_rectangle.png

// Draw a rectangle which is 40 pixels
// wide and 50 pixels high. The top left
// corner is at (x=20, y=30). The outline is
// 10 pixels wide in red. 
bmp.DrawRectangle(red, // outline colour
     10, // outline thickness
     20, // x
     30, // y
     40, // width
     50, // height
     0,  // xCornerRadius,
     0,  // yCornerRadius,
     0, 0, 0, 0, 0, 0, 0);

Drawing a rectangle involves using the DrawRectangle method which potentially requires setting a number of parameters. We will initially ignore the last 7 parameters and set them to zero (we will discuss them later when we cover gradient fills.).

If the outline thickness is greater than 1 then the co-ordinates specified indicate the center of the outline, i.e. half the outline is drawn on each side.

Rectangles with rounded corners can be specified by setting the xCornerRadius and yCornerRadius parameters to the desired radius. If the radius is larger than zero the outline thickness is ignored by the current version of the BCL and the framework reverts to drawing a 1 pixel thick outline.

Drawing Ellipses:
draw_ellipse.png

// Draw an ellipse centred at (x=30, y=60)
// with a radius of 10 on the x axis and
// 20 on the y axis.
bmp.DrawEllipse(red, // colour
     30,  // x
     60,  // y
     10,  // x radius
     20); // y radius

The simplest way to draw an ellipse is to specify the colour, center co-ordinates, and then the radiuses for the x and y axis respectively. This allows drawing not only ellipses, but also circles (which simply have the x and y radiuses the same).

There is a more complex overload of the DrawEllipse method which enables you to specify the thickness of the outline and/or fill the inside of the shape. However both features are not implemented by the current version of the base class library.

Filling Shapes
linear-gradient-fill.png

DrawEllipse and DrawRectangle both have overloads that support specifying a gradient fill to colour in the internal area of the shape (the 7 parameters set to 0 in the above examples).

The specification of a gradient fill consists of a start and end co-ordinate and associated colours at those two points. The framework will then apply a linear gradient between those two points. Any point “before” the start co-ordinate will be the starting colour, while any point “after” the end point will be the end colour. If both the start and end colours are the same a solid fill will be obtained.

The co-ordinates for the gradient start and end points are measured in screen co-ordinates. I.e. they are relative to the top left corner of the LCD and could refer to locations outside the area of the shape being drawn. This fact can be used to produce some interesting rendering and animation effects.

The opacity parameter allows the fill to be semitransparent and show previous content drawn to the same region of the bitmap. The opacity is a byte value with 0 indicating fully transparent, and 255 indicating full opaque (solid fill).

The fill effect shown in the image above was achieved via the following code sample. Notice the direction of the linear fill (as dictated by it’s start and end co-ordinates), and the fact that the bottom right half of the rectangle is a solid white fill due to this region being “after” the gradient’s end point.

bmp.DrawRectangle(Color.White, // outline colour
     0,    // outline thickness (no outline)
     50,    // x
     50,    // y
     100,   // width
     100,   // height
     0,     // x corner radius
     0,     // y corner radius
     red,   // start gradient colour
     50,    // start gradient x
     50,    // start gradient y
     Color.White, // end gradient colour
     100,   // end gradient x
     100,   // end gradient y
     0xFF); // opacity of fill

Sample Applications

[Download drawingexample.zip - 8.6 KB]

alpha-blended-rectangles.pngThe sample application available for download demonstrates a number of basic drawing operations as discussed above. The application cycles through a number of demonstrations. The sample application also demonstrates the use of System.Reflection functionality within the .NET Micro Framework to find the examples. If you would like to experiment with the drawing APIs, this sample application would be an ideal test harness, just add another “Example_XYZ” method that contains your drawing code and your example will be automatically picked up.

[Download randomshapes.zip - 35 KB]

random-shapes-demo.pngAnother sample application is available for download (without explanation as to how it is implemented). This example helps demonstrates the rendering capabilities of the .NET Micro Framework by creating and animating up to 50 random rectangles of different size, colour and alpha transparency over top of the .NET Micro Framework snowflake logo. It also demonstrates the fact that the .NET Micro Framework emulator is really a simulator. You will notice that running this example under the emulator produces very impressive rendering speeds which are not matched when running on actual hardware.

My next blog entry about the .NET Micro Framework will discuss how to create a basic WPF style application. Eventually I will outline an alternative approach for drawing basic shapes that enables the WPF framework to take care of compositing the individual shapes onto the screen, enabling basic shapes to be animated and moved around in a more object orientated manor.

ARANZ Medical presentation

November 17th, 2007

On Thursday I did an internal presentation for the company I work for and it’s related siblings under the ARANZ umbrella.

The presentation introduced the Windows Mobile platform used by ARANZ Medical Limited to some of the other groups within ARANZ which do not have a mobile (or even Microsoft orientated) development focus. It also highlighted some of the themes I picked up upon while attending MEDC 2007 earlier this year, with an emphasis on those that had relevance to our medical products.

I thought some of you might be interested in the slides, so have made these available via slideshare.net.

How to run an application immediately after installation

November 15th, 2007

It is quite common for commercial software to have a registration or configuration process which must be completed immediately after installation in order for the software to become operational. This blog entry outlines one technique for getting such a process to automatically occur after installation of a Windows Mobile software package.

My solution is largely based upon a sample application provided with the Windows Mobile 5.0 and Windows Mobile 6 SDKs. If you haven’t found these samples yet (installed by default) I encourage you to investigate them further.

Solution Overview
Most Windows Mobile Software is installed via CAB files. A CAB file is an archive which installs a number of files and registry settings onto a PDA. A less commonly used feature of a CAB file is that of a setup dll. A setup dll (traditionally named setup.dll) is a DLL which can hook into various steps of the installation/uninstallation process in order to extend or modify the process. The process of using a setup dll is described within MSDN in an article titled “Optional Setup.dll Files for installation“.

When the device processes a CAB file that includes a setup dll, it extracts the DLL and calls specifically named functions within it at the following stages of the installation process:

Since the DLL must export a set of functions it typically must be implemented in a native language such as C or C++. The functions exported by the setup.dll can perform any task they want and can optionally decide to abort the installation process.

So in order to run an application after installation of a CAB file, one approach is to write a setup dll that implements an Install_Exit() function that launches the newly installed executable.

Launching an application on installation
Since we want to perform a custom action in response to the installation process completing the correct place to place our custom code is the Install_Exit entry point.

One of the parameters to this entry point (as described in MSDN) is pszInstallDir which contains the path to the location the user has decided to install the application in (i.e. typically \Storage Card\Program Files\xyz or \Program Files\xyz). This will help us locate the executable that has been installed.

We can start the desired application by using the CreateProcess API. If we fail to launch the application we can return codeINSTALL_EXIT_UNINSTALL which will cause the CAB installation process to rollback any changes made during installation and display an error message to the user.

My sample application launches an application after installation by placing the following code within the Install_Exit function:

// We are provided with the installation folder the 
// user has installed the application into. So append
// the name of the application we want to launch. 
PROCESS_INFORMATION pi;
TCHAR szPath[MAX_PATH]; 
_tcscpy(szPath, pszInstallDir); 
_tcscat(szPath, _T("\\")); 
_tcscat(szPath, _T("TestApplication.exe")); 
 
// Start the application, and don't wait for it to exit 
if (!CreateProcess(szPath, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, &pi)) 
{ 
  // Failed to launch executable so indicate an error
  // and cause wceload to rollback the installation
  cie = codeINSTALL_EXIT_UNINSTALL; 
}

You will notice that this code sample hardcodes the name of the executable to launch (TestApplication.exe). It does however cope with users deciding to install the application on to an SD Card etc.

Using Visual Studio Smart Device CAB projects
ce-setup-dll-selected.pngce-setup-dll.pngHaving developed your custom setup.dll implementation you must package it into the CAB file in a particular way to indicate to the installation process that the file should be treated specially.

If you are using the Smart Device CAB project type within Visual Studio this is a two step process.

The first step is to add the “Primary Output” of your setup.dll project into the application folder of your setup project (use the file system viewer). This ensures that your dll is archived as part of the CAB file.

The second step is to indicate to the CAB building process which dll within your CAB file should be treated as the special “setup.dll”. To indicate which dll you want to use as the setup.dll within Solution Explorer you should select your Smart Device CAB project, and then switch to the Property viewer. You will notice one of the CAB file properties is called “CE Setup DLL”. Using a popup dialog that appears when this property is selected you should be able to navigate to the DLL you included in the first step of the process.

If you are creating your CAB file via a manually written INF file you specify the DLL that should be used by specifying a CESetupDLL parameter in your [DefaultInstall] section (documented within MSDN) as shown below:

[DefaultInstall]
CopyFiles = CopyToInstallDir,CopyToWindows
CESetupDLL = MySetup.dll

Sample Application

[Download sample application - 19.3Kb]

I have produced a small sample application which demonstrates this technique. It consists of a solution (SetupDLL.sln) that contains the following projects.

  • TestApplication – An application (written in C#) to run after the installation process.
  • SetupDLL – The DLL the CAB installation process invokes during installation in order to execute TestApplication.
  • SetupDLLCab – The CAB file project that packages everything up into a single CAB file for the end user to install.

If you build the example CAB file and then install it on a device you should notice that at the end of the installation process (just before the “installation has completed” message box appears) the included .NET Compact Framework application will automatically run.

I will end this blog posting with a question. Is anyone interested in being able to write such setup dlls within a managed language such as VB.NET or C#, and if so what kind of custom behaviour/logic would you be interested in implementing?

Windows Mobile Tip: Show all files within File Explorer

November 15th, 2007

show-all-files.PNGThis is a Windows Mobile Pocket PC specific tip which takes some people a little while to discover (especially if using a Windows Mobile device isn’t part of their day to day job).

By default the File Explorer application does not show all files. As well as files specifically marked as hidden, it will hide files with a series of “special” file extensions such as *.dll.

In order to show these files you must enable the “Show All Files” option, which can be achieved by following these steps:

  1. Open the File Explorer application.
  2. Scroll down to the blank area at the bottom of a directory listing.
  3. Tap and hold the stylus on the blank space underneath the last file in the directory listing.
  4. Select “show all files” from the popup menu which appears.

The directory listing should now display all files within the folder. Unfourtantly since file extensions are not visible you may end up with multiple enteries with the same name. For example, foo.exe, foo.dll, foo.txt and foo.pdf will all be listed as “foo”.

If the icon associated with a particular file extension doesn’t help you determine the type of file, you can tap on the file. If the file is assoicated with an application it should be launched automatically. If there is no association a message box will be displayed stating “foo.xyz is not a valid executable”. This message box will display the full filename (including extension) of the file.

A future blog entry will outline how developers can extend the functionality of built in applications such as File Explorer. We will develop an extension that allows us to rename the file extension of a file (i.e. change foo.log into foo.txt).

Code Camp Boot Camp summary

November 7th, 2007

Sponsors of Code Camp Boot CampIt’s now a couple of days since Code Camp Boot Camp finished, and I finally have some time to summarise the event, having completed my last university exam (ever?) earlier today.

This was the first .NET code camp event I have been directly involved in organising. Peter Jones and Simeon Pilgrim have already posted some good summary posts on the event.

Overall the general consensus was that the event was a great success.

It was good to see encouraging comments on the catering for the event, since this was my primary responsibility and my first time performing such a task. Subway sandwiches seemed to go down a treat.

Unfortunately helping to organise the event I didn’t get to see all the presentations I would have liked to. The ones that I did see were just as good as those at “professional” events such as MEDC which cost significantly more to attend. We are lucky to have a number of excellent speakers in New Zealand, who don’t mind travelling at their own expense to events around the country, and this generosity is a large part of why we can make such events free for attendees.

Over all I came away with a better appreciation of LINQ, and in particular technologies around LINQ and SQL (such as SQL to LINQ and ADO.NET Entities). I liked the ASP.NET Dynamic Data Controls presentation by Andrew Tokeley and can see some personal projects where this could be a useful framework.

The Morse Code puzzle challenge only had a couple of entries but as Simeon mentioned the 4 solutions we obtained had taken quite different approaches to solving the problem. I was quite impressed by the solution of Simon Green (who was the eventual winner of the Zune MP3 player). Simon had solved the problem not once, but twice, and his LINQ based solution was just a tad slower than Simeon’s hand coded radix tree based model solution.

Personally I found the event a great way to develop some personal contacts and future opportunities. Hopefully I’ll be presenting at the Southland .NET User Group and a yet to be formed Mobile and Embedded Developers User Group as a result of conversations I had at the event.

I would like to take the oppertunity to thank the sponsors who really made this the event that it was…

We out these sponsors the event wouldn’t have been possible.

Vodafone v1210 Windows Mobile 6 ROM upgrade

November 6th, 2007

I went hunting for the Windows Mobile 6 ROM upgrade a couple of times since I purchased a Vodafone v1210 smartphone earlier this year and saw an upgrade was planned for later in the year by Vodafone New Zealand.

It’s probably been out for quite a while and I’m the last one to find it… but today I found the official Vodafone New Zealand ROM upgrade so thought I would share the link.

http://www.vodafone.co.nz/personal/help/device-support/vodafone/vodafone_1210/

Code Camp Boot Camp later today!

November 2nd, 2007

Code Camp Boot Camp shirt and dog tagsI have just got back from a speakers dinner held for the speakers who are speaking at the Code Camp Boot Camp event happening in Christchurch later today (I must be there in under 7 hours time in fact…)

The event promises to be a great series of exciting presentations by some really skilled developers. Even if you haven’t registered or can’t spare the entire weekend, it would be worth your while comming along to atleast a session or two and you’re more than welcome to do this.

This has been the first .NET User Group event I have helped organise, and hopefully it isn’t the last as it’s been loads of fun. If you’re at this event please do say hi, it would be great to put a face to some of the people I’ve only met online.

Portable Puzzle Collection beta 2 (plus source code)

October 31st, 2007

OpenNETCF logoToday I produced a build of my port of Simon Tatham’s Portable Puzzle Collection as my submission to OpenNETCF’s latest monthly coding competition. While producing this submission I realised that since the last mention of this porting effort I hadn’t provided an update on my progress, or even outlined how you could obtain the source code. Opps…

Since the last blog entry I have created a project on google code to host my porting efforts. You can find this project at http://code.google.com/p/portablepuzzlecollection-wm.

If you are interested in helping out with this porting effort, here are some details you will probably need to know:

Tools required:
In order to build the puzzle collection you will need to have the following tools installed on your desktop machine.

Build instructions:
Unlike many projects which use Visual Studio 2005, this port does not have a project or solution file. Instead the Visual Studio 2005 compilers are used from the command line as part of a custom build framework developed by Simon Tatham. This is mainly due to the build framework also supporting building the puzzles for Mac OS X, desktop Windows and Linux all from a Unix based build server.

I have modified the build script with some temporary hacks to allow building the puzzle collection with Visual Studio 2005 on a Windows based host. To build the puzzle collection in this environment you should perform the following steps:

  • Obtain the source code from the SVN Repository.
  • Open up a command prompt.
  • Change to the directory you placed the source code in.
  • run build-ppc.bat.

Assuming no errors this should produce a CAB file and a setup.exe. If an error occurs you may be able to determine what happened by viewing the contents of the wce-build-log.txt file.

To install the software manually install the CAB file on your device, or run the setup.exe executable on your desktop PC (which will automatically download and install the CAB file for you).

Depending upon your circumstances you may need to alter some of the paths specified within build-ppc.bat. Eventually I may produce a VS2005 project file as an alternative (and more friendly) way to build the puzzle collection.

Found an issue with this port?
There are still a number of issues outstanding with this port. If you find any I would appreciate it if you could report them via the issue tracker available at http://code.google.com/p/portablepuzzlecollection-wm/issues/list. Or even better submit a patch!

Apart from a few cosmetic style issues, the major issues I am aware of at present is the lack of keypad support for some games. This is stopping some of the games from being playable on a Smartphone (Windows Mobile Standard) device.

MCTS welcome kits arrive

October 31st, 2007

MCTS: Windows Mobile 5.0 Application Development logo

Last week I received a package from Microsoft Singapore. It was my charter member certificate for the MCTS: Windows Mobile 5.0 Application Development certification. I sat the beta exam for this about 12 months ago, so it was good to finally receive the certificate, even if it was only a token piece of paper (the real value in certification lies elsewhere).

The interesting thing is that yesterday I also received a mass email sent out by Lutz Ziob, General Manager for Microsoft Learning. Due to the delays in shipping (some) welcome kits over the last few months Microsoft decided to provide each affected MCP with a free exam voucher.

I’ll probably use my free voucher to sit the 70-500: Windows Mobile Designing, Implementing, and Managing exam later this year, or should I hold out for the Windows Mobile 6 and/or Windows Embedded CE exams? I wonder how long it will be before these become available?

I was surprised when I looked on the MCP website that there are only 107 MCTS: Windows Mobile 5.0 Application Development certification holders as of October 2nd 2007.