Introduction
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.
Background
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.
History
- 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 push_back
a 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 struct
s 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 IOVEC struct
s.