Windows CE Win32 API Programming

Bruce examines Windows CE and its development environment, focusing on the differences between Version 1.0 and 2.0.



April 01, 1998
URL:http://www.drdobbs.com/windows/windows-ce-win32-api-programming/184410532

Windows CE Win32 API Programming

Bruce is an independent systems developer and can be contacted at [email protected].


Sidebar: Windows CE 1.0 versus Windows CE 2.0

The typical Windows CE-based handheld computer has a minimum of four MB of ROM and two MB of RAM. The operating system and bundled applications are stored in ROM. The processors currently supported by CE include the NEC 4100 MIPS, Hitachi SH3, and Phillips 3900 MIPS. The CPUs and operating system have been designed to conserve energy wherever and whenever possible. Most models include RAM extension cards so that some handhelds can have as much as 12 MB of combined RAM/ROM.

Windows CE provides a multitasking preemptive environment that manages threads, processes, and resources. It provides synchronization objects such as critical sections, mutexes, and events (semaphores, however, are not supported). It schedules the execution of a thread based on a priority time-sliced algorithm. Threads with the same priority are selected on a round-robin basis. Priorities are fixed and are not changed by the scheduler (in other words, there is no aging algorithm). Priorities can change if the CE scheduler detects a priority inversion problem. The Windows CE kernel supports a maximum of 32 processes.

The greatest constraint for application programs is limited memory. With the absence of a fixed disk, all persistent data is stored in memory. The object store is the portion of memory that has been allocated to store all files. Users can set the size of the object store through a Control Panel applet.

The display screen is also a consideration in application design. It is a minimum size of 480×240 pixels and allows for four colors -- two bits per pixel (bpp) in Version 1.0; see the accompanying text box entitled "Windows CE 1.0 versus CE 2.0" for information on CE 2.0. There is a small keyboard but it lacks a numeric keypad and function keys. A pen stylus and touch-sensitive screen is used instead of a mouse.

The User and GDI components from Windows 95/NT are combined into the Graphic Windows Event Subsystem -- the GWES component. This includes support for RAPI, Winsock, Telephony, serial connections, and infrared communications. Windows CE 1.0 does not support ActiveX, DDE, ODBC, OLE, COM, or printing. It provides limited support of the multimedia API functions -- wave files only (no MIDI, CD audio, and so on).

The Windows CE API is a subset of Win32; anything you write for CE will run on Win32. However, Win32 experience does not prepare Windows programmers for the differences between CE and the desktop. As the story goes, if the compatibility is 90 percent, developers will probably spend 90 percent of their time determining the 10 percent of the API that is different. Unfortunately, it is not as simple as setting a switch in the IDE to "compile my program for Windows CE."

The optimal way to develop for Windows CE, and to leverage your Win32 API expertise in the process, is to quickly learn which portion of the Win32 API is not supported by CE.

Compiler

To develop for CE, I used Visual C++ 5.0 with the CE-compiler add-on. The add-on contains the compilers for each of the chip sets (MIPS, SH3, Intel emulation). After installing the add-on, you then have several more target platforms (MIPS, SH3, Emulation) to choose from. The add-on also contains an emulation environment that you can run on NT. You can compile, build, download, and debug programs under 95 or NT; however, the emulation only links and runs under NT.

There are a number of functions from the Standard C Runtime libraries missing under CE. Microsoft has compressed the run-time libraries and thrown away functions that are duplicated in the Win32 API. This is done to minimize the run-time footprint on the handheld.

For example, an application I was writing made extensive use of the mktime function to calculate time to expiration for option derivatives. Although this function is missing from the CE run-time library, you can replace calls to mktime with calls to GetSystemTime (and adjust for the global time base).

All of the standard C run-time file operations do not exist on CE. You are expected to use the Win32 API equivalents (CreateFile() for _open(), and so forth). The sprintf function does not exist in the CE run-time library, but you can use wsprintf from the Win32 API instead. Unfortunately, however, wsprintf in the Win32 API does not support formatting floating-point numbers ("%f", for instance). If you wish to format a float value, you have to use _fcvt() to convert the float to string, then wsprintf the string.

The Microsoft Visual C++ CE compiler(s) does not support RTTI. It does not support the Microsoft implementation of STL either. This was a major disappointment since I was writing C++ code and expected my code to be portable between desktops and handhelds. I wanted to use the STL for its list and vector template classes. Consequently, I ended up using a version of the STL from Hewlett-Packard, then retrofitting the template library code for CE.

If you wish to use the string class in your code, you will have to write your own version for the CE platform to emulate the string class. The Microsoft implementation of the string class and STL code is so tangled up in the fstream class that it will not work on CE without major retooling. This is because the CE run time does not use the standard C functions for file I/O upon which the STL codes are built.

The loading mechanism of your program is different on CE. Since there is no such thing as a "path" environment variable on CE, all support DLLs must be in the \Windows subdirectory on the handheld. There is no concept of a current working directory. Consequently, any pathname to data that your program uses must be fully qualified or the function will fail.

Windows CE API versus Win32 API

The CE API is a subset of the Win32 API. The optimal way to write a portable program would be to write specifically for the CE API, almost guaranteeing that the program will compile on the desktop. If you write for the desktop and then port to CE, you will have lots of "undefined function call" errors in your compilation. The trick is to learn which API calls are not available on CE so you do not include them in your code.

Applications written for CE don't have a lot of pop-up windows opened as on desktop applications. Nor do they have a mechanism to resize the windows or normal menus. The screen real estate is at a premium and consequently there are significant specific API differences in the area of window management:

Command bars are specific to Windows CE and are similar to toolbars. They can contain menus, buttons, and combo boxes. They are the preferred method on CE for adding a menu to a window. However, since they more or less interact with your window and the OS like any other control, there are a number of cases where undesirable side effects occur.

For instance, the client rectangle retrieved by calling GetClientRect() under Windows 95/NT does not include the menu area. Consequently, the coordinate (0,0) begins directly below the menu. However, on CE with a window with a command bar, the coordinate (0,0) refers to the top left, uppermost point of the command bar. So calling GetClientRect on CE includes the command bar area.

This difference requires you to adjust the coordinates by the size of the command bar (assuming that you are using a command bar with a menu inserted in it). Since the command bar is included in the client area, you have to be sure that you do not overlay this area when positioning any child windows or controls.

A side effect of this difference is that you also cannot rely on CE to add vertical scrollbars to a window by adding the WS_VSCROLL window style to the window (usually during the call to CreateWindow). Since the command bar is part of the client area, when the CE windowing system adds the vertical scrollbar it covers up the command bar. If the scrollbars are added to the right portion of the screen (and they usually are), then the Close (X) button is covered up on the command bar. Users have no way to close the window. One alternative is to create and add the scrollbars yourself. This way you can manually maintain the z-order so that the command bar's Close button is never obstructed by the scrollbar.

The differences in API functions relating to drawing are (also see Table 3):

CE uses a two-bpp grayscale display. The colors available are white, black, light gray, and dark gray (the associated COLORREF's are 0x01000003, 0x01000000, 0x01000002, and 0x01000001, respectively). (The leftmost byte is a 0x01 denoting a custom palette.) You can then use the PALETTEINDEX macro to pass the COLORREF value to SetBkColor. For example, to set the background color to white:

SetBkColor( hdc, PALETTEINDEX(3))

I prefer to code with COLORREFs that are conditionally compiled according to the platform; see Example 1. Of course, if your desktop application makes extensive use of color, you do not want to leave it up to CE to select the nearest color. This is another instance where conditional directives are needed.

The resource and common controls available to your program are also different:

There are a set of CE-specific command bar functions to create, destroy, and manipulate the control. If you are using MFC to build your application, using the LoadFrame function within your derived CFrameWnd class will provide a menu or command bar to your program transparently depending on your platform. Otherwise, you will need to create and insert the command bar into your window.

Everything on the handheld is done in Unicode. If you want your code to be portable to Windows 95, you can use the tchar.h header macros and definitions to select whether to use a char or wchar_t for TCHAR at compile time. When making calls to standard string manipulation functions, you would then use the _tcsxxx equivalent. For example, you would use the _tcslen function in place of strlen. When compiling on CE, the _tcslen call is then replaced with wcslen. When compiling on Windows 95, the call is replaced with strlen. All string constants are then qualified with a _T() macro that prepends an L to the string on CE to designate a wide character string (for instance, _T("foo") becomes L"foo"); see Example 2.

I built one application using MFC and found some quirks in the MFC CE implementations. Some codes just broke on the CE platform though they worked on the desktop. If you dynamically subclass a window using the CWnd::SubclassWindow() method, for example, it is imperative that you reverse the operation (via CWnd::UnsubclassWindow()) at the parent window deletion. Failure to do so is fatal on the handheld. On the desktop, however, the code works fine (that is, without the call to CWnd::UnsubclassWindow).

MFC for Windows CE implements a CommandBar class, which is a data member of the CFrameWnd object. If you need to manipulate a menu item, you will want to do this through the CommandBar object. Unfortunately, some of the canned code, which Visual C++ gives to you when creating an application, is not CE aware and gives you compile errors. For example, adding an About menu item to the system menu is part of the standard code in CFrameWnd::OnInitDialog. However, the GetSystemMenu() API function call is implemented as a macro under CE and fails to compile. In fact, there isn't any system menu under CE, so you just enclose the code with conditional predefined constants (#ifdef _WIN32_WCE, for instance). For further discussion of the MFC implementation, see George Shepherd and Scot Wingo's "Undocumented Corner" column (DDJ, October 1997; available electronically, see "Resource Center," page 3).

Windows CE supports multiple threads for a single process. It supports all of the synchronization objects except semaphores. Events are supported via the CreateEvent() API call; named events are not. Like Windows 95, the CE API does not support the security attributes associated with Win32 object handles.

Development Process

Debugging under CE is a matter of connecting the handheld to the development machine via a serial cable. The executable is then downloaded to the HPC. The debugging communications is handled via the TCP/IP protocol between the HPC and desktop. Control of the program is handled much the same way that you would debug any other program with single step, execution breakpoints, examining variables, and so on. It is, however, incredibly slow. In fact, it is so slow that probably the only time you should actually debug on the handheld is for handheld-related issues. Using the emulation environment is much faster and avoids the extra step of having to download the executable.

Obviously, with a smaller screen the visual design of your applications will be different. I found that having two templates for some dialogs is useful. The dialog template for CE had the controls positioned and sized for the smaller screen. When the program was compiled, the identifier for the dialog is defined according to which platform is being built.

Unfortunately, I did run into a few minor problems when using MSVC to set up the build options for a platform. Visual C++ forgets to put the directives /subsystem:windowsce and /machine:xxx in the link options when setting up the build. When you then try to run the executable, you get a run-time error from the CE loader saying the file is not an executable file.

A small percentage of applications may also experience problems related to going to a slower platform. Obviously, CE is slower than the desktop, which can result in deadlocks, race conditions, or starvation in multithreaded applications that may run just fine on the desktop.

DDJ


Copyright © 1998, Dr. Dobb's Journal

Dr. Dobb's Journal April 1998: Windows CE 1.0 versus Windows CE 2.0

Windows CE 1.0 versus Windows CE 2.0

By Bruce Radtke

Dr. Dobb's Journal April 1998

Example 1: COLORREFs that are conditionally compiled according to the platform.


Copyright © 1998, Dr. Dobb's Journal

Dr. Dobb's Journal April 1998: Windows CE 1.0 versus Windows CE 2.0

Windows CE 1.0 versus Windows CE 2.0

By Bruce Radtke

Dr. Dobb's Journal April 1998

Example 2: Designating a wide character string.


Copyright © 1998, Dr. Dobb's Journal

Windows CE 1.0 versus Windows CE 2.0

Dr. Dobb's Journal April 1998

Windows CE 1.0 versus Windows CE 2.0


The major differences between Windows CE 1.0 and Windows 2.0 include the following:

The CE Embedded Toolkit

The CE Embedded Toolkit for Visual C++ 5.0 has been announced to enable embedded developers to customize the CE kernel. This enables a specialized version of CE using a minimum set of software modules to support the platform's requirements (in order to minimize the memory footprint and maximize performance of the operating system).

For example, you could build a version of the OS that contains the kernel and a selected set of communications modules but which does not provide a graphical user interface. In addition, Visual Basic 5.0 and Visual J++ have add-on packages to support CE as one of their target platforms. A Visual Basic run-time interpreter and Java virtual machine are part of these add-on packages.

-- B.R.


Copyright © 1998, Dr. Dobb's Journal

Dr. Dobb's Journal April 1998: Windows CE 1.0 versus Windows CE 2.0

Windows CE 1.0 versus Windows CE 2.0

By Bruce Radtke

Dr. Dobb's Journal April 1998

Table 1: Win32 window styles not supported by CE.


Copyright © 1998, Dr. Dobb's Journal

Dr. Dobb's Journal April 1998: Windows CE 1.0 versus Windows CE 2.0

Windows CE 1.0 versus Windows CE 2.0

By Bruce Radtke

Dr. Dobb's Journal April 1998

Table 2: Win32 class styles not supported by CE.


Copyright © 1998, Dr. Dobb's Journal

Dr. Dobb's Journal April 1998: Windows CE 1.0 versus Windows CE 2.0

Windows CE 1.0 versus Windows CE 2.0

By Bruce Radtke

Dr. Dobb's Journal April 1998

Table 3: Win32 API functions not supported by CE: (a) drawing functions; (b) window management; (c) keyboard functions; (d) message functions.


Copyright © 1998, Dr. Dobb's Journal

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.