Archive for the ‘Tutorials’ Category

Project Resistance: Day 2

Tuesday, October 27th, 2009

Today I’ll attempt to flesh out the project by drawing the coloured bands onto the resistor image and allowing the user to change them with simple finger swipe gestures. This covers parts of day 2 and day 3 of the Windows Mobile variant of the project. We’ll get back to unit testing in a later day.

Drawing Coloured Bands

A UIScrollView control can be used to present a vertical list of colours which the user can swipe through with their finger. By sizing the control to be the height of the resistor and setting the “paging enabled” setting within Interface Builder, the UIScrollView will automatically snap to a “page” boundary, ensuring the user doesn’t leave the scroll view showing multiple colours.

By using the UIScrollView I get all the required gesture and finger swiping features for free without writing a single line of source code.

Modifying the graphic resources

The Windows Mobile version of the application has a set of graphic resources with each coloured band pre-rendered in each of its four possible positions. For example, here are the four resources used to render the colour green within each band.

Screenshot showing the 4 graphic resources used to draw green bands onto a resistor

Doing this provides less flexibility, as each time I want to introduce a new colour or change the size or shape of the resistor graphic I need to get all of the coloured bands redrawn by a graphic designer (I’m a developer, and don’t have an artistic bone in my body!). For this reason I’ve decided to take a different rendering approach within the iPhone application. I’ve updated the background resistor image to include areas with alpha transparency as demonstrated below:

Image showing resistor blank with transparent areas where each colour band should be located

The checker board pattern indicates areas which are transparent and will show what ever is placed underneath the graphic when it comes time to display it onscreen. Although hard to tell, the areas where the coloured bands go are only partially transparent, allowing them to shade things placed underneath to give a nice “rounded” effect.

By placing the rectangular UIScrollViews containing solid colours underneath this transparent image I automatically get the rounded and shaded effect. However now I only have one image for my graphic artist to create and tweak.

Diagram showing how images with alpha transparency can be composited together to form a single image

Another thing to note is that the UIImage control containing the resistor blank is positioned above the UIScrollView controls. However since the “user interaction enabled” checkbox is unchecked within Interface Builder this control won’t stop events such as finger presses from filtering down to the controls positioned underneath it. Not only is the graphic partially transparent, but it is also “invisible” with respect to user interaction.

Responding to selection changes

By handling the scrollViewDidEndDragging:willDecelerate: and scrollViewDidEndDecelerating: UIScrollViewDelegate messages I can detect the finger swipes and scrolling actions and determine when the user changes the selected colour of each band as follows:

- (void) band:(int)bandIndex didSelectColor:(int)colorIndex
{
  NSLog(@"Band %d selected colour at index %d", bandIndex, colorIndex);
}
 
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
  // called on finger up if user dragged. decelerate is true if it will continue moving afterwards
  if (!decelerate)
  {
    [self band:scrollView.tag didSelectColor:scrollView.contentOffset.y / scrollView.bounds.size.height];
  }
}
 
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
  // called when scroll view grinds to a halt
  [self band:scrollView.tag didSelectColor:scrollView.contentOffset.y / scrollView.bounds.size.height];
}

The UIScrollView control does all the gesture detection and scrolling animations behind the scenes, so the code is rather clean and logic free. At the moment this simply logs to the console a message similar to the following:

Band 3 selected colour at index 5

I’ll leave it for another day to hook this up to the model, which is yet to be added to the project etc…

Day 2 Summary

Screenshot showing Project Resistance running on the iPhone at the end of day 2By using the UIScrollView control to present a finger selectable list of colours, and being smart about the use of alpha transparency within my resistor graphic I have managed to get a fairly functional user interface with minimal (and easily maintainable) source code. All my layout and positioning can be done visually within Interface Builder without writing source code. As a comparison compare the current version of ResistorViewController.m against the equivalent ResistorView.cs.

It’s interesting to note that to date my source code only consists of application specific logic and very little rendering code, while Chris’s and Alex’s code base currently has a high percentage of source code dedicated to alpha transparency and the drawing of the resistor. In fact at this very moment they have discovered a graphic rendering quirk they currently need to investigate.

Project Resistance: Day 1

Tuesday, October 27th, 2009

Screenshot showing initial version of Project Resistance running on the iPhoneToday I did some of the preliminary work for Project Resistance. For the most part today was about setting up some infrastructure for the application, setting up source code repositories, file layouts and the like.

Creating a GitHub account

For this project I’ve decided to host the source code on GitHub. This seemed a more “iPhone” friendly location than Codeplex and gives me an excuse to try out Git. A distributed source code system I have not used before.

After signing up for a free account and following their instructions on creating an SSH key-pair to help verify my identity I was ready to create a new project repository by answering a few questions (such as name and homepage URL).

Since I don’t have Git installed on my machine I next downloaded and installed it via the Git OSX Installer. Once installed I needed to perform a small amount of configuration from the terminal.

git config --global user.name "Christopher Fairbairn"
git config --global user.email christopher@christec.co.nz

With this out of the way I was ready to create a local git repository.

Creating a git repository

To create a new repository you simply create a new directory in a convenient location and execute the “git init” command within it.

mkdir Project-Resistance
cd Project-Resistance
git init

One benefit of a distributed source control system is that I can work against this local reposistory, committing changes and even branching the project without needing to be connected to a centralised server. This could come in handy as I tend to work in a number of environments without decent connectivity.

To test out git I decided to create a short README file that describes the purpose of the project. Once I had created the file in a text editor I needed to make git aware of it, and then finally commit the change to the repository with a short explanation of what I had done.

git add README
git commit -m 'added README file'

With all the changes committed locally, it was time to perform the really big smoke test and push the changes I had made up to the repository stored on github. I could achieve this by performing the following two commands from a terminal window.

git remote add origin git@github.com:ChrisTec/Project-Resistance.git
git push origin master

Stubbing out a project

Within XCode I created a new iPhone application by selecting the Tab Bar Application project template. I then added some of the graphic files as resources.

Unlike the Windows Mobile application which required a small amount of plumbing code to be developed in order to draw images with alpha transparency I was simply able to drag and drop the images onto my view within Interface Builder. The Cocoa Touch framework supports controls with transparency out of the box.

Within a couple of minutes I was displaying the alpha blended images within the iPhone Simulator.

Day 1 Summary

Today was relatively straight forward. The process to create a git repository on github was rather quick, and now that I have the git utility installed I could even have started the project without internet connectivity.

Likewise by using the Tab Bar Application project template within XCode I was able to get the main screen of the application looking pretty good without writing a single line of source code.

Luckily I was able to reuse many of the graphical assets commissioned by Chris Tacke on his first day, although eventually I’ll need to replace these to cope with the iPhone’s different screen resolution (480×320). Currently I’m stretching them. It will be interesting to see how Chris handles this situation himself, as the screen resolution and orientation of Windows Mobile devices can vary significantly.

Project Resistance – Developing an iPhone Application

Tuesday, October 27th, 2009

Screenshot of Windows Mobile version of Project ResistanceChris Tacke and Alex Feinman have started blogging about a new project called Project Resistance. The idea is to document the end to end experience of developing and selling a small utility application for the Windows Mobile platform. Along the way they’ll comment about their experiences, struggles and productivity wins etc. All the source code and related material will be available online as the project progresses.

The application is rather simple. It allows you to select colour bands on a resistor and will tell you the resistor’s resistance. See the Wikipedia entry on resistors if you have no idea what any of that means.

In light of my previous blog post and after talking to Chris Tacke, I’ve offered to follow his blog posts and create an iPhone variant of the application. It’ll be interesting to contrast the relative strengths and weaknesses of each platform, and how the App Store experience compares.

The first blog post I’ll make on the iPhone application will be covering signing up to http://www.github.com to host the project’s source code.

30 Days of Windows Mobile – Day 08: Rotate Me

Sunday, December 14th, 2008

Rotate Me iconRotate Me is a simple application which demonstrates how to programmatically rotate the screen of a Windows Mobile device.

As discussed previously dynamic screen orientation changes was first introduced in Pocket PC 2003 Second Edition. There are four orientations understood by the operating system as shown below (I have also listed their typical orientations on a 240×320 QVGA device).

  • DMDO_0 – 0 degrees (portrait)
  • DMDO_90 – 90 degrees (landscape)
  • DMDO_180 – 180 degrees (upside down portrait)
  • DMDO_270 – 270 degrees (upside down landscape)

Determining the current screen orientation

The ChangeDisplaySettingsEx API acts a little like a catch all kitchen sink. It can be used to query and set the current state of various display related properties.

In order to query the current state of a property you pass in the CDS_TEST flag and specify the field(s) you want to query in the dmFields bitmask, as shown below.

static DWORD GetScreenOrientation()
{
  DEVMODE deviceMode;
 
  memset(&deviceMode, 0, sizeof(deviceMode));
  deviceMode.dmSize = sizeof(deviceMode);
  deviceMode.dmFields = DM_DISPLAYORIENTATION;
 
  // Query the DM_DISPLAYORIENTATION property
  if (ChangeDisplaySettingsEx(NULL, &deviceMode,
    NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL)
    return deviceMode.dmDisplayOrientation;
  else
    return DMDO_DEFAULT;
}

Notice in this example we default to returning DMDO_DEFAULT (which is defined as DMDO_0) if the query fails. This seemed like a sensible default value to assume in the case of an error.

Changing the current screen orientation

To change the value of a display property we use a very similar code snippet, except we use the CDS_RESET flag and pre-populate the field in the DEVMODE structure with the desired value.

static void SetScreenOrientation(DWORD dwOrientation)
{
  DEVMODE deviceMode;
 
  memset(&deviceMode, 0, sizeof(deviceMode));
  deviceMode.dmSize = sizeof(deviceMode);
  deviceMode.dmFields = DM_DISPLAYORIENTATION;
  deviceMode.dmDisplayOrientation = dwOrientation;
 
  // Set the DM_DISPLAYORIENTATION property to the
  // specified orientation
  ChangeDisplaySettingsEx(NULL, &deviceMode,
    NULL, CDS_RESET, NULL);
}

Sample Application

[Download rotateme.zip - 20.8 KB]

The small sample application available for download demonstrates using the above functions to change the screen orientation. Each time you run the application it will toggle the screen between 0 and 90 degrees rotation and then promptly quit. There is not even any user interface!

30 Days of Windows Mobile – Day 07: Mobile FX

Saturday, December 13th, 2008

Screenshot of Mobile FX ApplicationMobile FX is a fun sound effects engine for Windows Mobile. It displays a series of graphical buttons which clicked produce different sound effects. The user interface is driven by an XML based configuration file that enables the user to change which sound effects are available.

This is the 7th application in the 30 days of Windows Mobile series and marks my current re-commitment to progress in converting the number of applications currently sitting on my harddrive into blog posts. My hat is off to Chris Craft who managed 30 applications in 30 days. Although I took a similar amount of time to convert his C# applications into C++, it is taking me a lot longer to write the associated blog posts…

Mobile FX is an interesting application, in order to develop it in native code we will need to cover a number of new technologies and APIs which we have not covered before.

Creating controls at runtime

Up until now all of our applications have statically placed controls within the user interface via a dialog resource located in a *.rc resource file.

This application however specifies a variable number of sound effects within an XML based configuration file. Since the number of button controls required could change, it is easier to create the controls dynamically at runtime. The CreateWindow API enables us to create a control at runtime as shown below

// Create a static (label) control at runtime
HWND hWndPicture = CreateWindow(_T("static"),
  NULL,
  WS_CHILD | WS_VISIBLE | SS_BITMAP | SS_NOTIFY, 
  left, top, width, height,
  hDlg, NULL,
  GetModuleHandle(NULL),
  NULL);

The first string parameter to CreateWindow specifies the type of control to create. A future blog post will discuss how to register your own custom controls so that they can be created via CreateWindow. The other parameters specify various properties related to the new control, such as its style, location and size.

If we want to make use of the GetDlgItem function to reference the newly created control we need to associate an ID with it. One way to do this is to use the SetWindowLong function as demonstrated below:

// Associate the id '1234' with the control 'hWnd'
SetWindowLong(hWnd, GWL_ID, 1234);

Turning relative paths into full paths

Most file based APIs within Windows CE require absolute file paths which start at the root of the filesystem (i.e. we must specify “\path\to\some\file.txt” instead of “file.txt”).

If we want to use relative file paths within our application we must manually convert them into absolute paths before passing them to system APIs. The OS provides no concept of a current working directory.

To convert a path specified relative to the directory the application is installed in we can make use of the following helper routine.

void GetFullPathToFile(LPTSTR pszFullPath, LPCTSTR pszFilename)
{
  // Find the path to the current executable
  GetModuleFileName(GetModuleHandle(NULL),
    pszFullPath, MAX_PATH);
 
  // Strip off the exe filename and replace it with
  // the path provided by our second parameter.
  wcscpy(wcsrchr(pszFullPath, '\\') + 1, pszFilename);
}

The trick is to use the GetModuleHandle and GetModuleFileName APIs to determine the path of the current executable. Once this is found we can use string manipulation functions to remove the *.exe file name and replace it with the name of the file we expect to find in the same folder.

An example use of the function is shown below.

// Place the absolute path to "test.wav" into szPath
TCHAR szPath[MAX_MATH];
GetFullPathToFile(szPath, L"test.wav");

Playing sounds

Instead of using the SndPlaySync API I decided to use an older API called PlaySound. Unlike SndPlaySync the PlaySound API is available on devices prior to Windows Mobile 6, the disadvantage however is that it only supports *.wav files (refer to my blog post about “Making use of new APIs within older applications” for one technique to support the use of new APIs while still allowing limited functionality on older devices).

To play a sound effect we simply pass the full path to the required *.wav file to PlaySound along with a couple of flags.

// Start to asyncronously play a sound
LPCTSTR pszSoundEffect = _T("\\path\\to\\some.wav");
PlaySound(pszSoundEffect, NULL,
  SND_ASYNC | SND_FILENAME | SND_NODEFAULT);

This code snippet makes use of the SND_ASYNC flag. This means that the call to PlaySound does not block until the sound effect finishes playing. Instead the call returns immediately and the sound effect plays in the background.

Playing the sound effects asynchronously enables the user to interrupt the currently playing sound by selecting another sound effect. To stop any currently playing sound effects you can pass in NULL for the sound effect filename.

// Stop any currently playing sounds
PlaySound(NULL, NULL, SND_FILENAME);

Using Common Object Model (COM) objects

The early origins of the .NET runtime can be traced to the older COM and COM+ frameworks. As an example of this the commonly referenced mscorlib assembly at one stage stood for “Microsoft COM Object Runtime (COR) library“.

The Common Object Model (COM) framework can be considered to have many of the same design goals as the Common Language Runtime (CLR), such as the ability for objects written in various languages to interoperate with each other. The first step of using COM objects within an application is to initialise the framework by calling the CoInitializeEx API.

// Initilise the COM framework
CoInitializeEx(NULL, COINIT_MULTITHREADED);

Once we have initialised the COM runtime we can request objects to be created by calling the CoCreateInstance API, passing in the class id (CLSID) of the specific class we want to create an instance of. A CLSID is a unique GUID value which uniquely identifies a class. It enables the COM framework to lookup the registry to find details about how and where the class is implemented.

// Create an instance of the 'AAA" class and return a pointer
// to the newly created object in the pThingy variable
IAAA *pThingy = NULL;
CoCreateInstance(CLSID_AAA, NULL, CLSCTX_INPROC_SERVER,
  IID_IAAA, (void**)&pThingy);
 
  // ... use the object ...
 
// Release our reference to the object
pThingy->Release();

Unlike the CLR framework the COM framework does not implement garbage collection, instead it is a reference counted API. Each object has a counter associated with it. Whenever an object is passed to another section of code its reference counter should be increased via a call to the AddRef method. Likewise when a section of code finishes using an object it should decrement the reference counter by calling the Release method. If Release causes the reference counter to decrease to zero the object’s resources are automatically freed. AddRef and Release are both part of an interface called IUnknown.

Drawing PNGs

Previous applications in this series have utilised Windows Bitmap (*.bmp) formatted images. This application is different since the application includes PNG formatted images to display on the sound effect buttons.

Prior to Windows Mobile 5.0 there was no general purpose API to manipulate images compressed in common image formats such as JPEGs, PNGs or GIFs (although there were options such as SHLoadImageFile). Windows Mobile 5.0 introduced a COM based Imaging API that offers a large number of image codecs as well as image manipulation functionality.

One benefit of using this API with PNG files is the ability for it to keep alpha transparency information in order to draw non rectangular images over top of existing content. The following subroutine can be used to draw a PNG onto an existing GDI device context.

// Draw an alpha blended image on the device context 'hdc'
// within the rectangle defined by 'prcBounds'.
static BOOL DrawAlphaImage(HDC hDC, RECT * prcBounds,
                           WCHAR * pszImageFileName)
{
  // Create an instance of the ImagingFactory class
  IImagingFactory *pFactory = NULL;
  HRESULT hr = CoCreateInstance(CLSID_ImagingFactory, NULL,
      CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void**)&pFactory);
  if (hr == S_OK)
  {
    // Call the CreateImageFromFile method to load the image
    // into memory.
    IImage *pImage = NULL;
    hr = pFactory->CreateImageFromFile(pszImageFileName, &pImage);
    if (hr == S_OK)
    {
      // And finally draw the image onto the device context
      hr = pImage->Draw(hDC, prcBounds, NULL);
 
      // Free the COM objects
      pImage->Release();
      pImage = NULL;
    }
 
    pFactory->Release();
    pFactory = NULL;
  }
 
  return (hr == S_OK);
}

Parsing XML

This is the first application that has required the parsing of an XML document. For this we can use another COM based API, the Microsoft (MSXML) DOM Parser. The first step is to create an instance of the DOM Document class.

// Create an instance of the XML Document class
IXMLDOMDocument *pDoc = NULL;
HRESULT hr = CoCreateInstance(CLSID_DOMDocument, NULL,
  CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void**)&pDoc);
if (hr == S_OK)
{
  // ... use the DOM document ...
}

Once we have an instance of the DOM document we can load an XML document into it by specifying the path to the XML file.

// Load the XML file
VARIANT_BOOL bSuccess = VARIANT_FALSE;
VARIANT filename;
 
VariantInit(&filename);
V_BSTR(&filename) = SysAllocString(L"\\path\\to\\doc.xml");
V_VT(&filename) = VT_BSTR;
 
hr = pDoc->load(filename, &bSuccess);
if (hr == S_OK && bSuccess == VARIANT_TRUE)
{
  // ... make use of the document ...
}

There is a small amount of complexity here due to the load method making use of the VARIANT datatype (essentially a strongly typed container which can hold data of various datatypes).

Once we have loaded the XML document into memory we can query against it in a number of ways, including selecting a set of nodes via an XPATH expression.

IXMLDOMNodeList *pNodes = NULL;
LONG len = 0;
BSTR xpath = SysAllocString(L"/MobileFX/SoundPack/Buttons");
 
// Execute an XPATH query to obtain the set of nodes
// which match the predicate
if (pDoc->selectNodes(xpath, &pNodes) == S_OK
  && pNodes->get_length(&len) == S_OK)
{
  // Then iterate over each of the nodes
  // returned
  for (LONG i = 0; i < len; i++)
  {
    // Fetch the next node
    IXMLDOMNode *pNode = NULL;
    if (pNodes->get_item(i, &pNode) == S_OK)
    {
      // ... process the node ...
 
      pNode->Release();
    }
  }
}
 
pNodes->Release();

Reading the contents of the XML configuration file enables us to glue together a number of the code snippets shown previously. For each button found in the XML document we can dynamically create a button control, draw the PNG based icon onto it and load the sound effect specified by a relative path.

Sample Project

[Download mobilefx.zip - 2.34 MB]

The sample application available for download can be a lot of fun. However there are a couple of activities left as exercises for the interested developer. These would make great learning experiences, for example:

  • Add a menu item that allows the user to switch between multiple sound pack XML configuration files.
  • Add scrolling so a sound pack XML configuration file with more than 16 sound effects can be scrolled through to access additional sound effects.
  • Modify the CreateTile function so the sound effect images do not need to be “pre-buttonized”? The round edges and glossy finish should be able to be applied over top of a standard rectangular image by making multiple calls to the DrawAlphaImage function. Take a look at a tool such as Axialis IconWorkshop for some inspiration, and if you have a copy of Visual Studio 2008 you can download a special version for free! The iPhone does a similar thing for application and website shortcut icons.

30 Days of Windows Mobile – Day 06: Pocket PasswordGen

Thursday, September 11th, 2008

Screenshot of PasswordGen applicationIf you are like me you will have access to a number of password protected online services. Each time I am requested to change my password for one of these services, I struggle to come up with a unique yet strong password.

The following application is designed to make the process of creating new passwords much easier. It allows the user to specify the allowable types of characters in their password and optionally shows the password in a phonetic form to make it easier to remember, or quote over a phone.

Defining a datastructure

The first challenge with this application was to determine how to store the required lookup data. For each character that could be used in the generated password we must be able to determine its equivalent phonetic form. This can be represented by the following data structure:

typedef struct {
  TCHAR character;
  LPCTSTR phonetic;
} PhoneticLetter;

We can construct an array of PhoneticLetter entries for each character category that the user can select to include in the generated password.

// Define a lookup table for lower case letters
static PhoneticLetter gbl_lowerCase[] = {
  { 'a', _T("Alpha") },
  { 'b', _T("Bravo") },
  ...
  { 'z', _T("Zulu") }
};

Helper functions can then be written to randomly select letters from these arrays and to convert between character and phonetic forms.

Generating cryptographic strength numbers

In order to generate unique passwords we need a way to pick a character at random. Using a cryptographic strength random number generator is an ideal technique since any weakness in our random number generation algorithm could be used to exploit the passwords we generate.

By using the Windows Cryptographic APIs we can produce a stream of cryptographic strength random numbers. To do this we need to include the wincrypt.h header file and then call the CryptGenRandom function as shown below:

DWORD dwRandomSeed;
HCRYPTPROV hCrypt;
 
// Acquire the cryptographic context	
if (CryptAcquireContext(&hCrypt, NULL, NULL, PROV_RSA_FULL,
                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
{
  // Generate some random bytes.
  // Second parameter is number of bytes to generate
  // Third parameter is where to store generated bytes
  if (CryptGenRandom(hCrypt,
           sizeof(dwRandomSeed),
           (BYTE*)&dwRandomSeed))
  {
    // dwRandomSeed contains a random value
  }
 
  CryptReleaseContext(hCrypt, 0);
}

CryptGenRandom is designed to generate an arbitrary amount of random data. By passing in a DWORD for the third parameter we’ll get 32bits (4 bytes) worth of random data.

Changing Fonts

By default controls within a dialog will utilise the standard dialog font. From the screenshot above you will notice that the “Password” label is slightly larger and bolder than the other labels.

To change the font used by a specific control we can send it the desired font via a WM_SETFONT window message. The following example uses the CreateFontIndirect function to create a new font and then sends it to the password label control via a WM_SETFONT message.

// Create a new font by filling out a LOGFONT
// structure with the desired style details
// and calling CreateFontIndirect
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
HDC hdc = GetDC(NULL);
lf.lfHeight = -9 * GetDeviceCaps(hdc, LOGPIXELSY) / 72;
ReleaseDC(NULL, hdc);
lf.lfWeight = FW_BOLD;
HFONT hFont = CreateFontIndirect(&lf);
 
// Pass the font to the control via
// the WM_SETFONT message
SendDlgItemMessage(hDlg, IDC_LABEL_PASSWORD,
  WM_SETFONT, (WPARAM)hFont, 0);

Using Checkboxes

Just like radio buttons, a checkbox is another form of button control. You can send the BM_GETCHECK window message to a checkbox to determine it’s current state as shown below:

HWND hWndCtrl = GetDlgItem(hDlg, IDC_CHECKBOX1);
if (SendMessage(hWndCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED)
{
   // the checkbox is checked
}

Interacting with the Clipboard

You might be using your PDA’s webbrowser to create an account for an online service. Rather than manually retyping the newly generated password, it may be easier to copy and paste it between applications.

As discussed in a previous blog post adding a SIPPREF control to a dialog will automatically provide a cut/copy/paste popup menu.

To programatically copy something to the clipboard we need to open the clipboard via a call to the OpenClipboard function.

if (OpenClipboard(NULL))
 
{
  ... do something with the clipboard ...
 
  CloseClipboard();
}

Once the clipboard is opened you then can call functions such as EmptyClipboard or SetClipboardData to alter with the contents of the clipboard buffer.

Sample Application

[Download pocketpasswordgen.zip - 61KB]

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.

30 Days of Windows Mobile – Day 05: Mobile Capture

Monday, September 8th, 2008

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, 
  UDM_SETPOS, MAKELPARAM(10, 0));

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)
  == BST_CHECKED)
{
  // 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.

case WM_HOTKEY:
  if (wParam == 1234)
  {
    // hotkey button has been pressed
  }
  break;

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)
{
  HDC hdcSrc = GetDC(HWND_DESKTOP);
 
  // 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
  DeleteDC(hdcDest);
  DeleteObject(hbmp);
 
  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.

30 Days of Windows Mobile – Day 04: Mileage Tracker

Sunday, June 15th, 2008

Screenshot of Mileage Tracker applicationWith petrol prices reaching record highs across the globe people are starting to pay more attention to fuel efficiency.

Day 4 of Chris Craft’s 30 Days of .NET introduces a Mileage Tracker application to help you check the efficiency of your vehicle and perhaps driving habits!

This blog post covers a number of aspects of porting the original C# source code into C++.

Transparent Labels

Windows CE does not support windows with true transparency. Instead we have to fake it. A common technique is to revert to manually drawing the elements of the user interface which require transparency over top of the background of their parent control.

// Draw the string "Hello World" in the rectangle
// (x1=10, y1=20) - (x2=60, y2=40) using a transparent
// background.
RECT rcBounds = {10, 20, 60, 40};
WCHAR szBuffer[] = L"Hello World";
 
SetBkMode(hDC, TRANSPARENT);
DrawText(hDC, szBuffer, wcslen(szBuffer), &rcCtrl, DT_LEFT);

Getting a little bit more advanced (with better design time support) the .NET Compact Framework solution suggested by Alex Yakhnin is equally implementable in native code and is the technique used in the source code available for download.

Gradient Background

The original C# application used a bitmap for a background. For this conversion I decided to demonstrate an additional API by implementing the background programatically. The solid colour part at the top is easily implemented by calling FillRect within the WM_PAINT message handler. The shaded gradient underneath can be implemented with a call to GradientFill.

Filtering edit controls

For this application it is desirable to restrict input in the edit controls to only decimal numbers (a distance of “abc” miles does not make much sense). Although the edit control has an ES_NUMBER window style which restricts input to numeric digits we can not utilise this as we also want to accept a decimal point.

Another approach is to subclass the edit control. Subclassing a window allows us to override or alter the existing behaviour of the control. The article “Safe Subclassing in Win32” provides a great introduction to this technique.

Similar to a dialog procedure, each window (control) has an associated window procedure. The first step in subclassing is to replace the window procedure with our own custom one.

// Replace the window procedure associated with the
// 'hWndCtrl' window with one called 'MaskedEditProc'
SetWindowLong(hWndCtrl, GWL_WNDPROC, (LONG)MaskedEditProc);

The new window procedure has the opportunity to process or filter window messages before they are passed along to the original window procedure. For example by filtering the WM_CHAR window messages seen by the original window procedure we can make certain key presses disappear.

static LRESULT CALLBACK MaskedEditProc(HWND hWnd,
         UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  WNDPROC pfnOldWndProc =
      (WNDPROC)GetWindowLong(hWnd, GWL_USERDATA);
 
  // Process messages of interest
  switch (uMsg)
  {
    case WM_CHAR:
      if (iswdigit(wParam)	// digits
        || wParam == '-'	// negativeSign
        || wParam == '.'	// decimalSeparator
        || wParam == '\b')	// backspace
        break; // This character is allowed
      else
        return 0; // This character isn't allowed
  }
 
  // Allow the original window procedure to process
  // the message.
  return CallWindowProc(pfnOldWndProc, hWnd, uMsg,
                                 wParam, lParam);
}

A more advanced (and reusable) implementation of this technique is described in James Brown’s Masked Edit Control Input tutorial.

Sample Application

[Download mileagetracker.zip - 61KB]

Within the sample application available for download there are a number of possible tasks left as exercises for the reader.

  1. Modify the MaskedEditProc window procedure to make it reject input such as “1.23.4″. I.e. accept a maximum of one decimal point.
  2. Modify the decimal number parsing to be locale aware. Some locales for instance use a semi colon (;) as a decimal separator.
  3. Handle screen orientation and resolution changes.

30 Days of Windows Mobile – Day 03: GPS Compass

Monday, June 9th, 2008

Screenshot of GPS Compass applicationThe third application in Chris Craft’s 30 Days of .NET is a GPS based Compass.

Interacting with GPS Devices

Windows Mobile 5.0 and above provides a unified API called the GPS Intermediate Driver that enables multiple applications to concurrently share a single GPS device. This API is highlevel and abstracts away the need to manually parse NEMA sentences etc.

To create a connection to the GPS Device we can include gpsapi.h and make use of the GPSOpenDevice API.

// Open a connection to the GPS Intermediate Driver
HANDLE hGPS = GPSOpenDevice(NULL, NULL, NULL, 0);

This API is reference counted. Each call to GPSOpenDevice must eventually be matched with a call to GPSCloseDevice. The GPS Hardware is only powered down when the last client closes it’s handle.

// Close our connection to the GPS Intermdiate Driver
GPSCloseHandle(hGPS);

Once a connection has been established we can call GPSGetPosition or GPSGetDeviceState to retrieve location and GPS device status information respectively. For example we can query the current location using a code sample such as the following:

GPS_POSITION pos;
 
// Setup the data structure
memset(&pos, 0, sizeof(pos));
pos.dwVersion = GPS_VERSION_CURRENT;
pos.dwSize = sizeof(pos);
 
// Ask the GPS intermediate driver to
// fill out the structure.
GPSGetPosition(hGPS, &pos, 500000, 0);

One thing to note is that the GPS_POSITION data structure contains a field named dwValidFlags. This field is a bitmask that tells you which fields contain valid data. For example if the dwValidFlags field does not contain the GPS_VALID_LATITUDE flag it means you can not rely on the dblLatitude field (perhaps a location fix has not been made yet).

The GPS Compass application makes use of an optional feature. By passing in two event handles to GPSOpenDevice we do not need to periodically call GPSGetPosition to gather new position updates. Instead we can wait until the GPS Intermediate Driver signals our events and only then call GPSGetPosition, safe in the knowledge that it will definatly return different results than the last call. This helps us be slightly more efficient with respect to battery lifetime due to less CPU load.

String Concatenation

By default we do not have access to a nice string class such as System.String. A string within a C or C++ application is essentially a fixed size character array that uses a NULL character as a terminator.

To copy a string from one string buffer into another we can make use of a function called wcscpy.

// Allocate a string buffer capable of storing
// 31 characters (the 32nd element is used to store a NULL
// terminator) and then copy the string "Hello World" into
// the buffer
WCHAR szMyBuffer[32];
wcscpy(szMyBuffer, L"Hello World");

Likewise to append a string onto the end of another we can make use of the wcscat function as follows:

// Add the string "Goodbye World" onto the end
// of the string already in 'szMyBuffer'
wcscat(szMyBuffer, L" Goodbye World");

While using these functions memory management is much more explicit than it is in C#. For example when you allocate a string buffer you must specify its maximum length and there is no bounds checking to ensure you don’t attempt to store 200 characters in a 100 character buffer. This leads to so called buffer overrun errors if you are not careful.

You may be more familiar with string functions called strcpy (string copy) and strcat (string concatenate). wcscpy and wcscat are essentially identical except that they work on “wide characters” (UTF16 encoded data) instead of ANSI.

Moving a Window

To move or resize a control (or any window for that matter) you can make use of the MoveWindow function.

// Move and resize the window 'hWnd'
MoveWindow(hWnd, // the window to move
  10,  // new x location
  20,  // new y location
  30,  // new width
  40); // new height

One problem with using the MoveWindow function is that you always need to specify both the window’s new location and size. Sometimes it can be useful to use a different function called SetWindowPos. This function accepts a few additional parameters, the most important one being a flags argument that enables you to specify which parameters should be taken notice of. For example to move a window without resizing it you may use a code snippet like the following:

SetWindowPos(hWnd,
  NULL, // hWndInsertAfter
  10,   // new x
  20,   // new y
  0,    // new width
  0,    // new height
  SWP_NOSIZE); // flags

The SWP_NOSIZE flag tells the SetWindowPos function that it should ignore the width and height parameters and leave the window at its current size. If you wanted to resize a window yet keep it’s current location you could use a similar SWP_NOMOVE flag.

Creating a Menu

This is the first sample application that has required the use of a menu. A menu is designed in the resource editor and loaded by the SHCreateMenuBar API. The call to SHCreateMenuBar is typically placed in the handler for the WM_INITDIALOG window message. This is convenient since this window message is received just before the dialog is made visible.

case WM_INITDIALOG:
  // Configure the menu
  SHMENUBARINFO mbi;
  memset(&mbi, 0, sizeof(mbi));
  mbi.cbSize = sizeof(mbi);
  mbi.hWndParent = hWnd; // the dialog's handle
  mbi.nToolBarId = IDR_MENU; // the menu resource id
  mbi.hInstRes = GetModuleHandle(NULL);
  mbi.dwFlags = SHCMBF_HMENU;
 
  // Create the menu
  SHCreateMenuBar(&mbi);
  break;

Once a menu is visible there is a range of menu APIs that enable you to interact with the menu. For example to enable or disable a particular menu item you can make use of the EnableMenuItem API as shown below:

// Disable a menu item with id 'IDC_SOME_ITEM'
EnableMenuItem(hMenu, IDC_SOME_ITEM,
  MF_BYCOMMAND | MF_GRAYED);
 
// Enable a menu item with id 'IDC_SOME_ITEM'
EnableMenuItem(hMenu, IDC_SOME_ITEM,
  MF_BYCOMMAND | MF_ENABLED);

Notice that the EnableMenuItem function is used to both enable and disable menu items, The MF_GRAYED or MF_ENABLED flags passed as part of the last argument determines which action you want to perform.

A handy place to put code that configures the state of menu items is the message handler for the WM_INITMENUPOPUP window message. This message is sent to the menu’s owner just before a menu becomes visible.

Menu items behave very similiar to buttons and send a WM_COMMAND window message when they are selected by the user. This fact can be used to your advantage. If you want a button and menu item to both perform the same task you can assign them the same command ID.

Sample Application

[Download gpscompass.zip - 96KB]

30 Days of Windows Mobile – Day 02: Bluetooth Manager

Sunday, June 8th, 2008

Screenshot of Bluetooth Manager applicationThe second sample application produced by Chris Craft is a small utility to toggle the power of a Bluetooth radio. Leaving the power on to the bluetooth radio for extended periods of time can be a drain on the battery life of your device.

Accessing Bluetooth

This application only works on devices that utilise the Microsoft Bluetooth stack. Unlike other aspects of the operating system there is no standardised API for bluetooth development, leading OEMs to be free to pick the bluetooth stack they think best serves the requirements of their device.

The Microsoft Bluetooth APIs are designed for use with C and C++. To use them you need to include the header file “bthutil.h” and link to a library called “bthutil.lib”. You can determine these requirements by looking at the bottom of the MSDN documentation page for functions such as BthSetMode.

To change the state of the Bluetooth radio we can use the BthSetMode function as shown below:

// Turn the bluetooth radio off
BthSetMode(BTH_POWER_OFF);

BthSetMode accepts a single parameter which is the desired radio state. It can be one of the following three values:

Value Description
BTH_POWER_OFF The bluetooth radio is off
BTH_CONNECTABLE The bluetooth radio is on and other devices can connect to it
BTH_DISCOVERABLE The bluetooth radio is on and other devices can discover (find) it as well as connect to it

We can also query the current state of the bluetooth radio by calling a function called BthGetMode.

DWORD dwMode = BTH_POWER_OFF;
BthGetMode(&dwMode);
 
if (dwMode == BTH_CONNECTABLE)
{
  // Do something here if the radio
  // is currently connectable
}

Using the State and Notification Broker

Rather than periodically polling the BthGetMode function to determine when the radio changes state we can ask the operating system to proactively tell us when the bluetooth mode changes.

The State and Notification Broker (SNAPI) is built on top of an infrastructure that allows you to monitor the value of any registry key and obtain notifications whenever it changes. There are two header files involved.

  • regext.h – Provides functions that allow us to watch for registry value changes
  • snapi.h – Provides definitions of various registry values that store system state information

Our sample application makes use of a function defined in regext.h called RegistryNotifyWindow. This function monitors a registry value and posts a window message to a specified window whenever the value changes. We set this up using a code snippet that looks similar to the following:

HREGNOTIFY hregNotify;
 
// We are interested in any change to the registry value.
NOTIFICATIONCONDITION condition = {
  REG_CT_ANYCHANGE,
  SN_BLUETOOTHSTATEPOWERON_BITMASK, 0
};
 
// We want to listen to the BLUETOOTHSTATEPOWERON
// registry value and have a WM_BLUETOOTH_STATE_CHANGE
// window message posted to 'hdlg' whenever it changes.
RegistryNotifyWindow(SN_BLUETOOTHSTATEPOWERON_ROOT,
  SN_BLUETOOTHSTATEPOWERON_PATH,
  SN_BLUETOOTHSTATEPOWERON_VALUE,
  hDlg,
  WM_BLUETOOTH_STATE_CHANGED,
  0,
  &condition,
  &hregNotify);

By modifying the contents of the NOTIFICATIONCONDITION structure we can also produce more complex scenarios such as only being notified when the specified SNAPI property increases above a certain value.

Using a button control

This application uses two buttons. When the user presses a button the dialog is sent a WM_COMMAND window message to allow it to respond to the event. One of the parameters of the WM_COMMAND window message allows us to determine which button has been pressed. For example:

case WM_COMMAND:
   // Determine which button was pressed
   switch (LOWORD(wParam))
   {
     case IDC_BUTTON_POWERON:
       // turn the bluetooth radio on
       break;
 
     case IDC_BUTTON_POWEROFF:
       // turn the bluetooth radio off
       break;
   }
   break;

Using an edit control

To replace the entire contents of an edit (textbox) control you can use the SetWindowText function just like you would for a static control.

HWND hWndCtrl = GetDlgItem(hDlg, IDC_EDIT_LOG);
SetWindowText(hWndCtrl, L"This is the new content");

To append text to the end of the existing contents of an edit control is a two part process. First we can move the selection (cursor) to the end of the textbox via the EM_SETSEL window message and then we can replace that selection with the text we desire via the EM_REPLACESEL window message, as shown below:

// Move the cursor to the end of the edit control
SendMessage(hWndCtrl, EM_SETSEL, -1, -1);
 
// Replace that selection with the text we want
// to append to the end of the edit control
SendMessage(hWndCtrl, EM_REPLACESEL, FALSE,
  (LPARAM)L"Text to add");

Displaying an image

The static control is commonly used like a Label control would be within a .NET Compact Framework application however it can also be used like a Picturebox control.

To change the image displayed by the static control we can use the STM_SETIMAGE window message as demonstrated by the following code sample.

// Get the status bitmap control
HWND hWndCtrl = GetDlgItem(hDlg, IDC_STATUS_BITMAP);
 
// Load the desired image from a bitmap resource
HBITMAP hBitmap = LoadBitmap(GetModuleHandle(NULL),
  MAKEINTRESOURCE(IDB_POWER_OFF));
 
// Then send the STM_SETIMAGE window message
// to the static control
SendMessage(hWndCtrl, STM_SETIMAGE, IMAGE_BITMAP,
  (LPARAM)hBitmap);

The other thing we need to do for this code sample is to make the image click-able. By default a static control does not respond to stylus taps. Within the dialog resource editor you can set the Notify property for a static control to True. When this is done a WM_COMMAND message will be generated whenever the static control is clicked, just like a button would.

Sample Application

[Download bluetoothmanager.zip - 99KB]

The Bluetooth State and Notification broker properties are new to Windows Mobile 6.0 so ideally we should set the minimum OS version property in the CAB file to disallow installation on previous versions of the operating system. This is left as a learning experience for the reader (one hint is that the OS version you want to specify isn’t 6.0…).

Another reader exercise may be to download the Broadcom Bluetooth SDK and modify the sample application to work on devices that use this alternative Bluetooth stack.