While working recently on an embedded Windows CE project (no, it’s not dead, at least not yet), a colleague was tasked to read JPEG and PNG images from the file system, but he needed to convert these to pure Win32
HBITMAP images to match the signature of a 3rd party library function he needed to call. I suggested he use the COM
IImagingFactory to load pictures into an
IImage object, then simply draw them into a GDI device context and extract the resulting bitmaps from that. He was unsure how to do this, so over the course of 4 hours and a few bottles of Belgian ale, I wrote a little sample for him.
To make the project a bit more interesting and to show him the code in working form, I decided to write the sample for a Windows Mobile 6.5 phone I could bring into the office. Rather than simply read the images from the file system or as an embedded resource, I extended the sample a bit to solve a common problem, namely, reading Google maps over the wireless Internet.
Here are some screen shots from the completed application. The first simply shows the program’s instructions, which are to select a city to display from the Help->GetMap menu, and the second shows the retrieved Google map of Seattle displayed on the screen. Note that these screen shots were taken from the Windows Mobile 6.5 QVGA emulator, launched from Visual Studio, and that you must have network connectivity routed through the emulator in order to actually download and display a map.
This is easily accomplished by selecting the Configure choice from the emulator’s File menu, clicking on the Network tab, and checking the “Enable NE2000 PCMCIA network adapter and bind to:” checkbox, with a valid network adapter selected in the
comboBox. There are plenty of articles on the net that show how to configure your Windows Mobile emulator for Internet connectivity, so I won’t really delve into that here.
Figure 1 - Start Screen
Figure 2 - Seattle Map
Using the Code
The code is very well documented internally and illustrates a number of interesting and useful techniques such as using a
std::vector to hold pointers to chunks of dynamically allocated memory used to read a Google map image from the Internet, using the
IImagingFactory to convert this memory into an
IImage, then drawing the subsequent image in a device context and returning the
HBITMAP through a C++ reference.
Other useful bits are creating and destroying fonts, centering and drawing text and images on the screen, and registering/responding to a Windows CE
SH_UIMETRIC_CHANGE message used to signal the user’s desire to change the default system font size.
For convenience, we use the ATL
CString object, which is very much like MFC’s
CString, in the
DisplayInstructions function and I show how to use Win32’s
GetTextExtentPoint32 to compute the pixel size of the
string so we can display it in the center of the screen.
The most interesting function is
GetGoogleMap, which shows how to establish an Internet connection on the phone, connect to maps.google.com, and retrieve the map image.
Points of Interest
Even though Windows Mobile 6 has been eclipsed by Windows Phone 7, I find it amusing that at the time of writing (March, 2011), the older Windows Mobile models are still outselling Windows Phone 7 by a factor of 2 to 1. Microsoft’s decision to destroy their Windows Mobile developer ecosystem by banning native code development from their new platform hasn’t yet translated into anything resembling success, but has simply motivated most of the experienced C++ developers to move to Android, iPhone, or RIM. But, Microsoft has no choice but to continue their mobile efforts as the size of the smartphone market grows and the use of desktop and laptop platforms continues its slow decline.
- 20th March, 2011: Initial post
- 24th March, 2011: Updated the
GetGoogleMap function to release the screen device context once the compatible bitmap has been created
- 14th April, 2011: The
GetGoogleMap function was changed. Previously, we allocated a new
IOVEC structure for each chunk of a file read from the Internet and pushed it into the
readBufferArray vector. However, when you
struct or object on to a vector, you are actually making a copy so there is no need to dynamically allocate a new
IOVEC structure for each block as we were doing before. This caused us to leak
IOVEC structs that were never deleted. Now, we use a single
IOVEC struct created on the stack to hold a pointer to a chunk of dynamically allocated memory and this single
struct is pushed onto the
readBufferArray vector each time a chunk is read, eliminating the leak of dynamically allocated