30 Days of Windows Mobile – Day 05: Mobile Capture

Screenshot of Mobile Capture applicationAfter a long hiatus I am back into blogging while I convert Chris Craft’s 30 Days of Windows Mobile demo applications into native C.

The next application in the series is a screen capture utility that runs directly on a Windows Mobile based PDA.

It has a ton of features and is ideal for capturing screenshots for user manuals etc. Once the settings have been configured the application will minimise itself and stay out of sight. A sound effect plays when a screenshot is captured and the file can then be found in the root directory of the device.

Creating numeric up-down controls

An up-down control is a pair of arrow buttons that can be associated with an edit control to allow the user to adjust the value without needing to use the keyboard.

To set the allowable range and current value of an up-down control you can send it the UDM_SETRANGE32 and UDM_SETPOS window messages as demonstrated in the following example.

// Set the range of the spinbox to 1 to 60
// and the current value to 10
SendDlgItemMessage(hDlg, IDC_SPIN_DELAYTIMER,  
  UDM_SETRANGE32, 1, 60);
SendDlgItemMessage(hDlg, IDC_SPIN_DELAYTIMER, 

The easiest way to associate an up-down control with an edit control is to place it immediately after the edit control in the dialog tab order and then specify the UDS_AUTOBUDDY and UDS_ALIGNRIGHT window styles. The UDS_ALIGNRIGHT window style means the up-down control will automatically resize and move to sit on the right edge of the edit control. While UDS_AUTOBUDDYINT means changing the up-down control’s value will automatically update the text within the edit control.

Using Radio Buttons

When clicked radio buttons send a standard WM_COMMAND window message just like a regular button. You can also determine a radio button’s current state be sending it the BM_GETCHECK window message as shown below:

if (SendDlgItemMessage(hDlg, IDC_CHECKBOX, BM_GETCHECK, 0, 0)
  // do something if the radio button is checked

To group a number of radio buttons together and make them mutually exclusive, they should be placed consecutively in the dialog’s tab order and then the first one should have the WS_GROUP window style set.

Capturing Hardware Buttons

One mode of this application starts the screen capture process when a specified hardware button is pressed.

To override the default behaviour of a hardware button and use it for an application specific purpose we can make use of the RegisterHotKey function:

// Register the VK_APP1 (typically Contacts)
// button as a hotkey for our dialog.
RegisterHotKey(hDlg, 1234, MOD_WIN, VK_APP1);

You can refer to the Windows Mobile documentation for a list of standard hardware button key codes suitable for registration.

When we are finished with a hardware button and want to return it to its default behaviour we can call the matching UnregisterHotKey function:

UnregisterHotKey(hDlg, 1234);

While the hotkey is registered the dialog will be sent WM_HOTKEY window messages whenever the hardware button is pressed. The unique id value we passed to the RegisterHotKey function is provided to us to help determine which hotkey was pressed in case we register more than one.

  if (wParam == 1234)
    // hotkey button has been pressed

Finding Hardware Buttons

Although we could hardcode the combobox list of available hardware buttons, it is better to query the device for this list, as the number of available buttons can vary between devices.

We can query the HKLM\Software\Microsoft\Shell\Keys registry key to find a list of available hardware buttons.

It is of interest to note that many buttons will be listed twice. Many buttons can have a different behaviour associated with them depending upon if they are held down for a short or long period of time.

Taking a screenshot

Calling the GetDC function and passing in the special HWND_DESKTOP value obtains a device context for the entire screen. A device context is roughly analogous to a managed System.Drawing.Graphics instance.

By using the BitBlt function we can copy the bitmap data associated with a rectangular region of one device context into another.

The CreateCompatibleDC and CreateCompatibleBtmap functions can be utilised to create an offscreen bitmap and associated device context suitable for storing the screenshot.

// Save a rectangular area of the screen
// specified by "pRect" to a file specified by "pszFilename".
void Snapshot(WCHAR *pszFilename, RECT *pRect)
  // Create a new bitmap of the required size and a device
  // context to allow us to draw onto it.
  int width = pRect->right - pRect->left;
  int height = pRect->bottom - pRect->top;
  HDC hdcDest = CreateCompatibleDC(hdcSrc);
  HBITMAP hbmp = CreateCompatibleBitmap(hdcSrc, width, height);
  SelectObject(hdcDest, hbmp);
  // Blit (copy) from the source device context (the screen)
  // to the device context that is associated with our
  // offscreen bitmap buffer.
  BitBlt(hdcDest, 0, 0, width, height,
    hdcSrc, pRect->left, pRect->top, SRCCOPY);
  // Finally save our bitmap to disk
  SaveBitmap(pszFilename, hdcDest, hbmp);
  // Free the resources
  ReleaseDC(HWND_DESKTOP, hdcSrc);

Saving a bitmap to file

As discussed by Chris Tacke there are two types of bitmap objects. Device Dependant Bitmaps (DDBs) and Device Independent Bitmaps (DIBs). A bitmap file is basically the raw pixel data of a DIB written to disk with BITMAPFILEHEADER and BITMAPINFOHEADER headers attached to describe the format of the data.

Within the source code available for download there is a small function called SaveBitmap which accepts an HBITMAP and saves the contents to a file.

Sample Application

[Download mobilecapture.zip - 68KB]

The C++ source code and a CAB file for this sample application can be downloaded. If you have any questions about the source code or would like to discuss native Windows Mobile development further please leave a comment on this blog entry.

Leave a Reply