ButtonEx - Owner Drawn Button Control

Wow 2 posts in 1 day. I must have a lot of spare time today! Actually I'm down with a cold and I just feel sorry for myself when I stay in bed.

In this article I'd like to share another piece of code that I use quite often. Its a simple owner drawn button control that can have a nice 3D shadow. Drawing the 3D shadow effect was by complete accident though. I was trying to just draw a simple control that acts like a button. When I was drawing the borders the first time I drawn the rectangle a pixel bigger hence the control had a 1 pixel line of just black on the right and bottom side. Anyway, my graphic artist loved it and decided that we keep it.

The control has the following properties added:
  1) PushedColor (Color) - The color the control will be filled with once the MouseDown is fired
  2) DrawShadow (Boolean) - A flag whether to draw the 3D border

The default settings of the control is best on a form with a blue-ish background.

And here's the code:

public class ButtonEx : Control
  private Bitmap off_screen;
  private SolidBrush back_brush;
  private SolidBrush selected_brush;
  private SolidBrush text_brush;
  private Pen border_pen;
  private bool pushed;
  private bool shadow;

  public ButtonEx()
    BackColor = Color.FromArgb(2, 32, 154);
    ForeColor = Color.White;

    back_brush = new SolidBrush(Color.FromArgb(48, 88, 198));
    selected_brush = new SolidBrush(Color.FromArgb(15, 51, 190));
    border_pen = new Pen(Color.White);
    text_brush = new SolidBrush(Color.White);

  public override Color BackColor
    get { return base.BackColor; }
      base.BackColor = value;
      back_brush = new SolidBrush(value);

  public override Color ForeColor
    get { return base.ForeColor; }
      base.ForeColor = value;
      border_pen = new Pen(value);
      text_brush = new SolidBrush(value);

  public Color PushedColor
    get { return selected_brush.Color; }
    set { selected_brush = new SolidBrush(value); }

  public bool DrawShadow
    get { return shadow; }
    set { shadow = value; }

  protected override void OnPaint(PaintEventArgs e)
    if (off_screen == null) {
      off_screen = new Bitmap(ClientSize.Width, ClientSize.Height);

    using (Graphics gxOff = Graphics.FromImage(off_screen)) {
        ClientSize.Width - (shadow ? 0 : 1),
        ClientSize.Height - (shadow ? 0 : 1));

      Rectangle rect = new Rectangle(1, 1,
        ClientRectangle.Width - 2, ClientRectangle.Height - 2);

        pushed ? back_brush : selected_brush, rect);

      if (!string.IsNullOrEmpty(Text)) {
        SizeF size = gxOff.MeasureString(Text, Font);
          (ClientSize.Width - size.Width) / 2,
          (ClientSize.Height - size.Height) / 2);

    e.Graphics.DrawImage(off_screen, 0, 0);

  protected override void OnPaintBackground(PaintEventArgs e) { }

  protected override void OnMouseDown(MouseEventArgs e)

    pushed = true;

  protected override void OnMouseUp(MouseEventArgs e)

    pushed = false;

  protected override void OnTextChanged(EventArgs e)


Attaching Photos to a .NETCF Application

Sorry for not posting any articles lately. I've been quite busy and didn't have time to follow up on blogs.

Anyway, lately I've been working on a Mobile Inspection Log application for a customer. The application is rather simple and works like a small check list. The back-end server provides the mobile client with a list of Observation types where the User can set each observation to "OK", "Questionable", "Fail", and "N/A". If an Observation is questionable or failed then the user can attach a comment and a photo. The photo is then saved to a local database which can be synchronized with an access database on the users desktop computer or be sent to a web service.

The user has 2 options for attaching photos to their observation: 1) Opening an existing photo on the file system; 2) taking a photo themselves using the built-in camera. Since the one of the requirements for the application is Windows Mobile 6.0 Professional, my job got a lot easier with the Microsoft.WindowsMobile.Forms.CameraCaptureDialog and the Microsoft.WindowsMobile.Forms.SelectPictreDialog forms

Here's a small sample of how to use the CameraCaptureDialog:

string image_filename = null;
using (CameraCaptureDialog camera = new CameraCaptureDialog()) {
  camera.Owner = this;
  camera.Title = base.Text;
  camera.Mode = CameraCaptureMode.Still;
  camera.StillQuality = CameraCaptureStillQuality.High;

  if (camera.ShowDialog() == DialogResult.OK) {
    image_filename = camera.FileName;

And for the SelectPictureDialog:

string image_filename = null;
using (SelectPictureDialog open = new SelectPictureDialog()) {
  open.Filter = "Pictures (*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF";

  if (open.ShowDialog() == DialogResult.OK) {
    image_filename = open.FileName;

For saving to the local database I simply convert an Image to byte[]. I do this by:

public static byte[] ImageToByteArray(Image image, ImageFormat format) {
  MemoryStream stream = new MemoryStream();
  image.Save(stream, format);

  byte[] buffer = stream.GetBuffer();

  stream = null;

  return buffer;


public static byte[] ImageToByteArray(string image_file) {
  FileStream stream = new FileStream(image_file, FileMode.Open);
  int size = (int)stream.Length;
  byte[] buffer = new byte[size];
  stream.Read(buffer, 0, size);

  return buffer;

For loading image from the database to the application I simply convert the byte[] to an Image. I do that by:

public static Image ByteArrayToImage(byte[] raw_data) {
  MemoryStream stream = new MemoryStream(raw_data.Length);
  stream.Write(raw_data, 0, raw_data.Length - 1);

  Bitmap image = new Bitmap(stream);

  stream = null;

  return image;

Since each inspection report will contain around 40-50 observation, it can also take around 40-50 images. For synchronizing the application via web services, I had to split up the inspection report in parts, 1 part will contain all the textual information, and all the other parts will be for the photos. The Mobile Client Software Factory made life easier for having this architecture run on an occasionally connected environment.

Other things that are keeping me busy is integrating mobile applications with popular out-of-the-box ERP systems, such as Navision, Axapta, and Visma. I'll post more info and how-to's once I get more familiar with these systems.

Displaying the Calendar view on a DateTimePicker Control in .NETCF

I've recently made a solution where the customer requested to be able to bring up the calendar view in a DateTimePicker control by pressing on a specific button on the screen. The solution to that was really simple: Create a control that inherits from System.Windows.Forms.DateTimePicker and add a method called ShowCalendar() which I call to bring up the Calendar view.

public class DateTimePickerEx : DateTimePicker
  static extern int SendMessage(
    IntPtr hWnd, uint uMsg, int wParam, int lParam);

  const int WM_LBUTTONDOWN = 0x0201;

  public void ShowCalendar() {
    int x = Width - 10;
    int y = Height / 2;
    int lParam = x + y * 0x00010000;

    SendMessage(Handle, WM_LBUTTONDOWN, 1, lParam);

Generic Multiple CAB File Installer for the Desktop

In this article I would like to share a nice and simple multiple CAB file installer application for the desktop that I have been using for a few years now. The tool can install up to 10 CAB files and is written in C and has less than a 100 lines of code.

Before we get started with installing multiple CAB files with a generic installer, let's try to go through the process of installing a CAB file from the desktop.

Installing a CAB file from the desktop to the mobile device is pretty simple. All you need to do is create a .INI file that defines the CAB files you wish to install and launch the Application Manager (CeAppMgr.exe) passing the .INI file (full path) as the arguments. Application Manager is included when installing ActiveSync or the Windows Mobile Device Center (Vista)

An Application Manager .INI file contains information that registers an application with the Application Manager. The .INI file uses the following format:

Version = 1.0
Component = component_name

Description = descriptive_name
CabFiles = cab_filename [,cab_filename]

Here's an MSDN link for more details on Creating an .ini File for the Application Manager

Before launching the Application Manager, we should first make sure that it's installed. Once we know that then we get the location of the file. The easiest way to do this programmatically is to look into the registry key SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\CEAppMgr.exe. If this key doesn't exist, then the Application Manager is not installed.

The next step is quite interesting yet very simple. In this installer application, I use a configuration file called Setup.ini which defines which CAB files I want to install. Setup.ini will look like this:

CABFILE1 = MyApp1.ini

You can easily modifiy the code to install more than 10 CAB files if you think it's appropriate. I used GetPrivateProfileString() to read the values from my configuration file.

Setup.ini, the .INI files, and the actual CAB files are required to be in the same directory as the generic installer.

Ok, now we have Application Manager command-line arguments ready, we now just have to launch it. I used CreateProcess() to launch the application manager and used WaitForSingleObject() to wait for the process to end.

Here's the full source code:


#include "windows.h"
#include "tchar.h"

#define CE_APP_MGR TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\CEAppMgr.exe")

LPTSTR GetParameters()
  TCHAR szParams[2048];
  szParams[0] = TCHAR(0);

  TCHAR szCurrDir[MAX_PATH];
  GetCurrentDirectory(MAX_PATH, szCurrDir);

  for (int i = 1; i < 11; i++) {
    TCHAR buffer[16];
    TCHAR szKey[16];

    strcpy(szKey, TEXT("CABFILE"));
    itoa(i, buffer, 16);
    strcat(szKey, buffer);

    TCHAR szSetupIni[MAX_PATH];
    strcpy(szSetupIni, szCurrDir);
    strcat(szSetupIni, TEXT("\\"));
    strcat(szSetupIni, TEXT("Setup.ini"));

    TCHAR szCabFile[MAX_PATH];
    ::GetPrivateProfileString(TEXT("CabFiles"), szKey,
      (TCHAR*)"", szCabFile, sizeof(szCabFile), szSetupIni);

    if (0 != strcmp(szCabFile, (TCHAR*)"")) {
      strcat(szParams, TEXT(" \""));
      strcat(szParams, szCurrDir);
      strcat(szParams, TEXT("\\"));
      strcat(szParams, szCabFile);
      strcat(szParams, TEXT(" \""));

  return szParams;

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  HKEY hkey;
  DWORD dwDataSize = MAX_PATH;
  DWORD dwType = REG_SZ;

    if(ERROR_SUCCESS != RegQueryValueEx(hkey, NULL, NULL,
      &dwType, (PBYTE)szCEAppMgrPath, &dwDataSize))
      MessageBox(NULL, TEXT("Unable to find Application Manager for Pocket PC Applications"),
      return 1;
  } else {
    MessageBox(NULL, TEXT("Unable to find Application Manager for Pocket PC Applications"),
    return 1;


  STARTUPINFO startup_info = {0};
  startup_info.cb = sizeof(startup_info);

  if (CreateProcess(szCEAppMgrPath, GetParameters(), NULL,
    NULL, FALSE, 0, NULL, NULL, &startup_info, &pi))
    WaitForSingleObject(pi.hProcess, INFINITE);
  } else {
    MessageBox(NULL, TEXT("Unable to Launch Application Manager for Pocket PC Applications"),
    return 2;

  return 0;

When deplying my applications in this manner, I like packaging them in a self-extracting zip file that is configured for software installation. I'm still holding to an old version of Winzip Self-Extractor to accomplish this task.

Another reason I use WaitForSingleObject is because a self-extracting zip installer file deletes the all the temporary files it has extracted once the installer process ends. This means that your .INI and CAB files will be deleted even before they get copied to the device.

Accessing Windows Mobile 6.0 Sound API's through .NETCF

A new set of APIs were introduced in Windows Mobile 6 to make it easier to manage and play sound. The new API's support playing sounds in a variety of formats that Windows Media Player supports

These API's are really easy to use. You can play a sound file with a single function call. Let's try to do that through .NETCF by P/Invoking SndPlaySync(LPCTSTR pszSoundFile, DWORD dwFlags).

static extern uint SndPlaySync(string pszSoundFile, uint dwFlags);

void PlaySound() {
  SndPlaySync("\\Storage Card\\Intro.mp3", 0);

In the previous sample, we are playing a sound file synchronously. Now, this is interesting in a way that its very very easy to play an audio file. But what really gets interesting is that the new Sound API provides methods for playing sound files asynchronously.

To play audio files asynchronously, we will need to call 4 methods from the Sound API.

  SndOpen(LPCTSTR pszSoundFile, HSOUND* phSound)
  SndPlayAsync(HSOUND hSound, DWORD dwFlags)
  SndClose(HSOUND hSound)
  SndStop(SND_SCOPE SoundScope, HSOUND hSound)

Let's start by declare our P/Invokes

static extern uint SndOpen(string pszSoundFile, ref IntPtr phSound);

static extern uint SndPlayAsync(IntPtr hSound, uint dwFlags);

static extern uint SndClose(IntPtr hSound);

static extern uint SndStop(int SoundScope, IntPtr hSound);

Now that we have our P/Invokes ready. Let's start playing with the Sound API in .NETCF. In the sample below, the application will play the audio file Intro.mp3 located in the Storage Card. To play an Audio file asynchronously, we will first need a handle to the audio file. We use SndOpen(string, IntPtr) to accomplish that. Once we have the handle to the audio file, we can call SndPlayAsync(IntPtr, int) to start playing the audio file. To stop playing the audio we just have to close the handle and call SndStop(SND_SCOPE_PROCESS, IntPtr.Zero) to stop the playback of the sound.

IntPtr hSound = IntPtr.Zero;
const string AUDIO_FILE = "\\Storage Card\\Intro.mp3";
const int SND_SCOPE_PROCESS = 0x1;

void Play() {
  SndOpen(AUDIO_FILE, ref hSound);
  SndPlayAsync(hSound, 0);

void Stop() {
  SndStop(SND_SCOPE_PROCESS, IntPtr.Zero);

How cool is that? You can now easily add some cool sound effects to your application. Maybe even use the Sound API for one of those annoying startup sounds!