Windows CE (Compact Edition) is small, but you don't have to start over in writing applications. Learn the tasks involved in moving a Win 32 application's user interface to Windows CE.
One winter day in 1986, while working in a federal research program in Alaska, drinking a cup of coffee and reading the latest issue of Dr. Dobbs, I learned of a technology that seemed to hold out the promise of solving a lot of problems for my colleagues. According to Dr Dobbs Editor Jon Erickson, Microsoft's Windows 1.0 was going to do great things for IBM PC users. "Hock the Volvo" he admonished, "and buy the Windows SDK right now!"
I took him at his word, and plunged ahead, though I was fortunate enough to hang on to the family station wagon. Inside six months I was totally immersed in Windows programming, and have been ever since. In the intervening years, I have written code for every version of Windows, written about writing Windows code for most of the serious programming journals (including Dr. Dobbs ), and published three books on Windows Programming. I can honestly say I never met a Windows I didn't like, and Windows CE is far and away my favorite so far. Here's why:
The Windows CE Opportunity
The Windows revolution of the early eighties did two things. First, it created a consistent, predictable, intuitive user interface. Over time this attracted a broad community of users, and by extension, created a public body of knowledge about how to use personal computers and software. Second, Windows interposed a layer of hardware abstraction that made peripheral devices independent of specific operating systems and thus dramatically stimulated the PC aftermarket. If you weren't active in personal computer programming before the advent of Windows, this may not mean much, but it was very important. It meant that a non-technical person could buy a computer, printer, and mouse, take them home, connect them -- and -- they worked. At the time, this was remarkable. The wealth and variety of cheap, interoperable peripherals we have today is a direct result of the maturation of the Windows "Plug and Play" concept.
Windows CE brings us to the brink of a similar revolution for handheld and palmtop computers. We are, so to speak, on the threshold of changes that are going to have as much or more impact on the way we live as did the personal computer revolution. Win CE has inherent technical momentum that none of the other handheld or palmtop competitors enjoy, because it leverages the huge base of Win 32 knowledge, skill and code. With a little savvy effort, Win 32 code moves quickly to Win CE. By porting existing code rather than starting from scratch, you'll incur less risk, deliver applications more quickly, and enjoy the reassuring prospect of a stable API in the future.
Finally, the best thing about Windows CE is that it's the perfect medium for individual creativity and innovation. Because Win CE applications must be small and lightweight, they lend themselves to the kind of projects a single person or a very small team can undertake. The devices themselves are fairly inexpensive, the SDK is an add-on to tools you probably already have and know well, and most likely at least some of your code will move across without any changes at all. In short, this time around, you can give it a try without hocking the Volvo.
Part I: Adapting Application Appearance to Windows CE
Every single thing we do in moving a Win 32 application's user interface to Windows CE is motivated by the fact that CE ( an acronym that stands for "Compact Edition") is small. It has an abbreviated API, is designed with low power devices in mind, has fierce memory and storage limitations, mandates tiny screens, assumes few to no peripheral devices, and offers relatively little in the way of second chances to errant code. In short, the job of porting Win 32 code to Windows CE could be summed up in the bumper sticker one sees so frequently:
"REDUCE, REUSE, RECYCLE"
In this first installment, I am focusing exclusively on the tasks that will get a user interface up and running for your application in the least time. In many cases this involves trimming back the lush, repetitive feature set we have come to expect on the desktop. This may go against the grain of your prior experience. What you have to remember is that the physical limitations of Windows CE are real. You can run out of memory, and you can run out of power. This one rule is the key to making a transition from the desktop user interface to a CE style interface: In any trade-off situation, we always choose the design solution that makes the application smaller.
Analyzing the User interface of Your Win32 Application
Our object in this lesson is to start with a Win32 application and get a visible Windows CE facsimile of it up and running as quickly as possible. Notice that I said visible facsimile. Here's what I mean by this. As a first step, we are going to isolate the parts of the Win 32 application that have to do with its user interface and include only those in our new Windows CE project. Right now we don't want to even consider the parts of the application that encode its specific behaviors and functionality.
We do this for several reasons. First, we divide the porting problem into the smallest, simplest elements possible, because this is the fastest path to stable code. If you fully port one aspect of an application at a time, test it, stabilize it and document it, then you'll consistently move forward, building on this incremental success. Second, a typical Win32 app, even a fairly lightweight one, will contain tens if not hundreds of unsupported function calls, library references, and other baggage that would take too long to successfully prune away if we started with all of it. Third, and most important of all, as you move the user interface of your porting subject to the highly constrained Win CE environment, you will undoubtedly shed a great deal of the desktop application's feature set. Shedding features isn't bad. It's good, and its necessary. When you have the user interface finalized on the CE side, you will be in a much better position to decide what functionality it makes sense to port. Our objective here is a ported app that reflects the spirit of the Win CE environment and its Win32 origins: it should be a small, lightweight, intelligently distilled essence of the Win 32 app from which it evolved.
The Resource File Is A Road Map
If a Windows application has a user interface at all, most of it's significant details are recorded in the resource file. Figure 1 is a screenshot of a simple Win32 application that includes icon, accelerator, dialog, menu, and string table resources.
Let's dissect the resource file for this application and assess the relative portability of its user interface.
Figure 1 - A simple Win32 application.
//Microsoft Developer Studio generated resource script.//#include "resource.h"#define APSTUDIO_READONLY_SYMBOLS/////////////////////////////////////////////////////////////////////// Generated from the TEXTINCLUDE 2 resource.//#define APSTUDIO_HIDDEN_SYMBOLS#include "windows.h"#undef APSTUDIO_HIDDEN_SYMBOLS#include "resource.h"///////////////////////////////////////////////////////////////////#undef APSTUDIO_READONLY_SYMBOLS///////////////////////////////////////////////////////////////////// English (U.S.) resources#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)#ifdef _WIN32LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US#pragma code_page(1252)#endif //_WIN32//////////////////////////////////////////////////////////////////////// Icon//// Icon with lowest ID value placed first to ensure application// icon remains consistent on all systems.IDI_RESOURCE_FILE ICON DISCARDABLE "resource_file.ICO"IDI_SMALL ICON DISCARDABLE "SMALL.ICO"/////////////////////////////////////////////////////////////////////// Menu//IDC_RESOURCE_FILE MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "Open", ID_FILE_OPEN MENUITEM "Close", ID_FILE_CLOSE MENUITEM "Save", ID_FILE_SAVE MENUITEM "SaveAs", ID_FILE_SAVEAS MENUITEM "Print", ID_FILE_PRINT MENUITEM "Print Setup", ID_FILE_PRINTSETUP MENUITEM SEPARATOR MENUITEM "E&xit", IDM_EXIT MENUITEM SEPARATOR MENUITEM "Recent Files", ID_FILE_RECENTFILES END POPUP "More Menus" BEGIN POPUP "Submenu 1" BEGIN MENUITEM "Item1", ID_SUBMENU1_ITEM1 MENUITEM "Item2", ID_SUBMENU1_ITEM2 END END POPUP "&Help" BEGIN MENUITEM "&About ...", IDM_ABOUT ENDEND/////////////////////////////////////////////////////////////////////// Accelerator//IDC_RESOURCE_FILE ACCELERATORS MOVEABLE PURE BEGIN "?", IDM_ABOUT, ASCII, ALTEND/////////////////////////////////////////////////////////////////////// Dialog//IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 230, 75STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENUCAPTION "About"FONT 8, "System"BEGIN ICON IDI_RESOURCE_FILE,IDC_MYICON,14,9,16,16 LTEXT "resource_file Version 1.0",IDC_STATIC,49,10, 119,8,SS_NOPREFIX LTEXT "Copyright (C) 2001",IDC_STATIC,49,20,119,8 DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUPENDIDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 242, 201STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENUCAPTION "ResourceFile Example"FONT 8, "MS Sans Serif"BEGIN DEFPUSHBUTTON "OK",IDOK,185,5,50,14 PUSHBUTTON "Cancel",IDCANCEL,185,25,50,14 EDITTEXT IDC_EDIT1,25,25,135,45,ES_AUTOHSCROLL LISTBOX IDC_LIST1,25,95,95,50,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Radio Button Group",IDC_STATIC,150,90,75,55 LTEXT "Scrolling Listbox",IDC_STATIC,25,80,100,10 LTEXT "Edit Control",IDC_STATIC,25,10,125,10END#ifdef APSTUDIO_INVOKED/////////////////////////////////////////////////////////////////////// TEXTINCLUDE//2 TEXTINCLUDE DISCARDABLE BEGIN "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" "#include ""windows.h""\r\n" "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" "#include ""resource.h""\r\n" "\0"END3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0"END1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0"END#endif // APSTUDIO_INVOKED/////////////////////////////////////////////////////////////////////// DESIGNINFO//#ifdef APSTUDIO_INVOKEDGUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_DIALOG1, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 235 TOPMARGIN, 7 BOTTOMMARGIN, 194 ENDEND#endif // APSTUDIO_INVOKED/////////////////////////////////////////////////////////////////////// String Table//STRINGTABLE DISCARDABLE BEGIN IDS_APP_TITLE "resource_file" IDS_HELLO "Hello World!" IDC_RESOURCE_FILE "RESOURCE_FILE"END#endif // English (U.S.) resources///////////////////////////////////////////////////////////////////#ifndef APSTUDIO_INVOKED/////////////////////////////////////////////////////////////////////// Generated from the TEXTINCLUDE 3 resource./////////////////////////////////////////////////////////////////////#endif // not APSTUDIO_INVOKED
Porting Icons and Cursors
Here's the fragment of the resource file that describes the application's icons:
// Icon with lowest ID value placed first to ensure application// icon remains consistent on all systems.IDI_RESOURCE_FILE ICON DISCARDABLE "resource_file.ICO"IDI_SMALL ICON DISCARDABLE "SMALL.ICO"
The first icon shown, IDI_RESOURCE_FILE, is the application's main icon. That is, it is the one that is displayed when the user creates a shortcut to the application. Win 32 applications' main icons are 32 by 32 pixels and may use the full range of system colors. By contrast, Windows CE icons must be no larger than 16 by 16 pixels, and must be explicitly loaded by the application. If the icon is too large, it won't load. The second icon in the resource file, IDI_SMALL, is used to represent the application in list views ( Windows Explorer, for example). This icon is superfluous on the CE side and should be eliminated.
Modify the application's main icon so that its dimensions are exactly 16x16 pixels. Since many CE devices are limited in their color depth, check to make sure your icon still "reads" correctly in black and white. ( Most paint programs have a function that let you change a color image to grey scale or black and white. ) Delete the small icon's file and references from the project.
The resource_file application includes no special cursor resources. However, this simply means that the app doesn't store any images specifically intended to be displayed as cursors in it's resource file. Win 32 applications would typically use the APIs LoadCursor, LoadCursorFromFile, or CreateCursor to get or create a special cursor.
In most cases, using special purpose cursors is a bad practice under Win CE, both because it is unnecessarily wasteful of memory and because the concept of a cursor is permeated by the assumption that the user has a keyboard and a mouse as well. By contrast, Windows CE devices are heavily biased toward stylus input. Since the user taps the screen to choose the "current position" (which is really just the location of the input focus) a cursor is superfluous. Most Windows CE devices provide implicit support for the wait cursor, however. Standard practice is to display the wait cursor whenever you undertake an operation that will make the system unresponsive for a noticeable period of time. Here's how to load the native wait cursor:
//LoadCursor loads the cursor image and returns the handle//SetCursor sets the new cursor and returns the handle to //the old cursorhOldCursor = SetCursor(LoadCursor( NULL, IDC_WAIT));
Here's one more thing of note about custom cursor resources. The file that encodes a cursor resource includes information for a variety of display devices. On the desktop, this means the cursor is drawn correctly for all resolution and aspect ratios, so the actual cursor file may be several times as large as the bitmap used for the cursor. Also, Windows CE doesn't support color cursors, and attempting to load one may produce catastrophic results.Task 2:
Identify code that manipulates the cursor. Except for code that displays the wait cursor during lengthy operations, eliminate calls to cursor handling functions. Where the cursor changes signal change of mode or application state, devise ways to inform users. For example, use message boxes or modify the application's caption on the taskbar icon
Here are the lines from the resource file that encode the default accelerator for the resource_file application:
IDC_RESOURCE_FILE ACCELERATORS MOVEABLE PURE BEGIN "?", IDM_ABOUT, ASCII, ALTEND
This entry means a user can type Alt+? To open the application's About box . Much of what was said about cursors applies to accelerators. They are not as wasteful of memory or as risky if misused, but they lose their meaning in an environment where the user has options such as the stylus, voice input and rich ink.Task 3:
Eliminate code that defines or manipulates accelerators.
Here's the application's string table resource code:
STRINGTABLE DISCARDABLE BEGIN IDS_APP_TITLE "resource_file" IDS_HELLO "Hello World!" IDC_RESOURCE_FILE "RESOURCE_FILE"END
So far, we've mostly been tossing unnecessary things out. Not so with the string table, which is a key tool for several reasons. First, Windows CE has aggressively embraced the world market for handheld and palmtop computers. This is the motivation behind CE's standardization on Unicode. Putting all the application's static text in the string table means that an application can be fully translated by manipulating only the resource file and the help files. It doesn't even have to be recompiled, only linked with a new language version of the resource file. More important, however, is the string table's potential to conserve the runtime memory. In a nutshell, here's the memory advantage of using the stringtable.
Every Windows CE application occupies a region of read only memory in which the program image and read only static data are stored. This region is separate and distinct from the read/write memory used by an executing application. String resources are stored in read only memory, never used en masse, but instead loaded on demand at runtime by an application. This dramatically reduces the application's footprint in the memory region used for the application heap and stack.
Locate the literal text in your application and move it to the string table. Replace the literals with calls to LoadString.
Here is the menu section for the resource_file application:
// Menu//IDC_RESOURCE_FILE MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "Open", ID_FILE_OPEN MENUITEM "Close", ID_FILE_CLOSE MENUITEM "Save", ID_FILE_SAVE MENUITEM "SaveAs", ID_FILE_SAVEAS MENUITEM "Print", ID_FILE_PRINT MENUITEM "Print Setup", ID_FILE_PRINTSETUP MENUITEM SEPARATOR MENUITEM "E&xit", IDM_EXIT MENUITEM SEPARATOR MENUITEM "Recent Files", ID_FILE_RECENTFILES END POPUP "More Menus" BEGIN POPUP "Submenu 1" BEGIN MENUITEM "Item1", ID_SUBMENU1_ITEM1 MENUITEM "Item2", ID_SUBMENU1_ITEM2 END END POPUP "&Help" BEGIN MENUITEM "&About ...", IDM_ABOUT ENDEND
With menus, we come to a serious porting effort. First, we'll look at what we can get rid of and then we'll examine the changed nature of menu handling under Windows CE.
In the File menu, you can eliminate Exit because it duplicates a standard element on the Windows CE menu bar. You can also eliminate File.Print Setup. Printing is supported on CE devices only thru the serial or infrared ports, which essentially amounts to transferring a file to a desktop computer and delegating to its printer, so you can't effect changes in printer setup from the handheld. For this reason you may want to eliminate File.Print, since it's basically a subterfuge for moving a file to the desktop and doing the file handling there.
Skipping over the "More Menus" popup for now, look at the "Help" menu. It's only purpose in this case is to display an item that shows the application's about box. "Help" should go because it is a waste of valuable screen real estate. The About box. Should go because it's a waste of valuable memory resources. If you feel strongly about displaying copyright and version info, use MessageBox when the program opens to do this. The dialog template and code that implants the MessageBox function is already present, so using it to display a splash screen with copyright, owner and version number information incurs very little overhead.
Now let's look more closely at the "More Menus" item. This is our first trela instance of making a choice to keep or eliminate a feature based on its congruence with the spirit of the Windows CE environment. "More Menus" resource description is shown below:
POPUP "More Menus" BEGIN POPUP "Submenu 1" BEGIN MENUITEM "Item1", ID_SUBMENU1_ITEM1 MENUITEM "Item2", ID_SUBMENU1_ITEM2 END END
Floating menus and popup submenus are a key thing for which to be on the lookout when deciding whether to move existing menu code or to undertake redesign. If you have nested POPUP statements in the menu portion of the resource file, you need to consider changing the menu design. More that one level of nesting ( e.g. a POPUP submenu that include another POPUP) mandates. POPUPS on the desktop are used to help organize groups of relationships among menu items. On a CE device, scarcity of memory and screen real estate make this approach cumbersome and wasteful.
Windows CE Menu Bars
From a realistic point of view, users aren't likely to be doing (or attempting to do) a very large variety of things at one time on a CE device. Because of their small screen size and relatively slow processing speed, it's reasonable to assume task-oriented patterns of user behavior. Probably for this reason, as well as the physical limits of the device, the designers of Windows CE have emphasized a more flexible, dynamic method of displaying menus than the one on which we mostly relied on the desktop. CE's use of menu bars provides a highly efficient way of displaying compact menus that are tailored to the task in which the user is engaged.
Instead of creating one menu for an application that presents every possible action or mode, you dynamically create and display a variety of task specific menu bars. When the user signals a change in task activity, you destroy the old menu bar and create a new one that supports the require task.
Next, lets take a look at an application that demonstrates the versatility of menu bars. Before we do so, I'll say a word about the source files of the example apps. I use Visual C++ to build and test my Windows CE applications, both for the purposes of this book and in my business. I have found that in order to get things to build and link smoothly (most particularly, in order to avoid problems with unresolved function references at link time ), I start new projects using the following procedure:
Figure 2 - Create a Windows CE Project
Open the dialog box shown above from the File.New.Project Menu. Choose WCE Application from the left pane, and check every processor you wish to target in the Platforms pane. This last bit is important, because it's difficult to add platforms later.
Figure 3 - Choosing Initial Project Files
Choose "A typical "Hello World" application from the list in this dialog box. Though it's tempting to start with an empty project and import some of your own files into a clean space, it hasn't worked well for me. Using the "Hello World" files sets up all the linkage parameters and is much faster and less error prone.
Figure 4 - Files and target platforms for the new project
Build and run the Hello World app before you go on. In particular, check it's list of target platforms to make sure you got all of the ones you intended. There is a pair of toolbar dropdowns that you can check if you use Visual C++. The first is The WCE Configuration bar, which shows the available Windows CE configurations. It should include entries for the Handheld PC and the Palmtop PC, plus the version numbers of the SDK for each. Another control, the Build Toolbar, list all of the targets for which you can generate code in this project. The list should include all the processor types you specified in the Platforms pane of the New Project window, with Release and Debug build versions for each.
In the next installment, we'll fully explore the Windows CE menu bar. You'll learn how to build menu bars and insert controls. Since you'll probably be leaving at least some of your desktop application's menu functionality behind, we'll introduce alternative interface techniques which are both in the spirit of CE and in keeping with the limited screen size of typical CE devices. In particular, we'll focus on how to build, display and manage command bars, a key Windows CE interface construct.
About the Author
Nancy Nicolaisen is a software engineer who has designed and implemented highly modular Windows CE products that include features such as full remote diagnostics, CE-side data compression, dynamically constructed user interface, automatic screen size detection, entry time data validation.
In addition to writing for Developer.com, she has written several books including Making Win 32 Applications Mobile. She has also written numerous articles on programming technology for national publications including Dr. Dobbs, BYTE Magazine, Microsoft Systems Journal, PC Magazine; Computer Shopper, Windows Sources and Databased Advisor.