Electronic Design

Going From Windows to Window CE: The Keys To Programming Success

There are important differences between the two environments to be aware of , such as API set issues, support for different processors, and Unicode.

This article is the first of a two-part series. Part II is scheduled to appear in the June 26 issue.—ED

Microsoft's Windows operating system—originally designed for desktop and laptop computers—is now available in configurations that are optimized for embedded device development. Within the past 18 months, Microsoft has released several versions of its embedded Windows operating systems. This has brought the familiar Windows programming environment to developers of almost any type of new intelligent computing device. These "smart" units are a rapidly growing class of non-PC computing devices. They include digital set-top boxes, gaming systems, personal Internet access devices, handheld data collectors, and much more.

The first and most established of these embedded operating systems is Microsoft's Windows CE. This operating system takes advantage of an extensive set of familiar programming languages, APIs, and protocols. Yet, there are important differences in the programming of Windows CE in comparison to traditional desktop Windows operating systems. Some of these include issues relating to the API set, support for different processors, multiple-operating-system configurations, Unicode, display, memory management, and debugging.

The Unicode string format, with its broad multilanguage utility, continues to gain ground against the ASCII format. Unlike Windows NT and Windows 98, Windows CE exclusively supports Unicode strings. Instead of simply using the WCHAR (double-byte or wide-character) version of string functions in a program, it's better to use the generic-text routine mapping (TCHAR). TCHAR maps to WCHAR when UNICODE is defined and to char when UNICODE is not defined. All string functions have a mapping version for TCHAR. For example, the _tcslen() function maps to wcslen() when UNICODE is defined and to strlen() when UNICODE is not defined. Note that both UNICODE and _UNICODE must be defined to get the full mapping. By using TCHAR instead of WCHAR, the code is portable to non-Unicode systems.

Because Windows CE supports Unicode exclusively, the WinMain() prototype is a little different. Notice that the third parameter often has to be an LPTSTR, instead of an LPSTR, as it is under Windows NT or Windows 98 (Listing 1).

Streamlined API
In many cases, devices that run Windows CE are mobile and lightweight. These have significantly lower memory and processing resources than traditional desktop PCs, so Windows CE was designed to be much leaner than desktop Windows operating systems. As a result, some desktop Windows API functions aren't available for CE applications. Usually, if you want to use an API function that isn't available, you can easily reproduce the desired effect with other API functions. For instance, OffsetClipRgn(), which moves the clip region of a given device context, might not be available on CE. The same task can be accomplished incrementally by using CreateRectRgn(), GetClipRgn(), OffsetRgn(), SelectClipRgn(), and DeleteObject(). Though this process requires a few more steps, it generates the same result (Listing 2).

At times, you have to get very creative with what you have available. Suppose you wanted to make circular and oval buttons. Windows CE doesn't support nonrectangular windows. But design engineers accomplished their goals by subclassing the button window class and adding some customization for the handling of certain window messages (Listing 3).

This code to "fools" the button class into treating the button as the desired shape. InternalHitTest() is a routine that determines if a point is within the circular part of the button window that engineers want to treat as the button. If the point is outside that part and the message received is a WM_LBUTTONDOWN, the function simply returns. And the button class doesn't know that the button was ever pressed.

On the other hand, if the message is a WM_LBUTTONUP, the function can't simply return. The button might already have been pressed and would remain stuck in that state. Designers can fool the button class by setting the click point to (-1, -1) before handing it on to the standard button class' WndProc(). Then it thinks that mouse button was released with the cursor outside of the button area. Similar code was incorporated to handle WM_MOUSEMOVE.

This doesn't perfectly substitute a round button window. To account for an arbitrary background to be visible around, say, the button's boundary you would need something more. It was still sufficient for the desired purpose.

The bottom line is, expect to run into situations where you won't be able to use your favorite API function or feature. But, you shouldn't get discouraged. There's usually a way to overcome the problem.

There are also various subtle and not-so-subtle differences and quirks between API functions for desktop Windows and for Windows CE. Look at the ExtractIconEx() API function, for instance:

HICON ExtractIconEx(LPCTSTR lpszFile,
int nIconIndex,
HICON FAR *phiconLarge,
HICON FAR *phiconSmall,
             UINT nIcons); 

The nIconIndex argument on Windows CE is interpreted completely different from how it is on the desktop. Except for 0, it specifies a resource identifier rather than an index. Plus, lpszFile can only be an .exe or a .dll, not an .ico file. Thus, it's usually a good idea to take a glance at the documentation before using an API function that you've never used on Windows CE. Sometimes the behavior of the function or the interpretation of arguments may not be the same, as above. In other situations you might discover that a particular flag isn't supported, even though it might be present in the headers and will still compile.

Windows CE isn't always disadvantaged in terms of APIs. In fact, it has some nice API methods and flags that aren't available on desktop Windows systems, such as the loading of a bitmap from a .bmp file. The standard Windows method for performing this requires a number of steps. An API function that's normally used, CreateDIBitmap(), isn't supported on CE. The Windows CE-only API method, called SHLoadDIBitmap(), solves this problem with one simple call (Listing 4).

A Useful Addition
Another example is the window style WS_EX_NOACTIVATE. This style prevents a window from ever getting keyboard focus. It critically aided the writing of a software keyboard and still came in handy elsewhere (software keyboards are probably the reason it was added to Windows CE in the first place). Recently, one of the authors even found himself missing it when he worked on an NT application. Therefore, before beginning a particular task, it's worth while to browse through the documentation that's related to the subject in question, even the headers. You never know what might turn up.

When developers write software for a desktop Windows operating system, it's usually to be run on an x86 platform. Windows CE, on the other hand, is intended to run on an entire range of very dissimilar types of intelligent computing devices. That comprises anything from digital set-top boxes to bar code scanners. Hence, Windows CE supports a wide and growing variety of processor families, including MIPS, SHx, PowerPC, ARM, and x86. If a Windows CE application is to be as widely available as possible, it must be built and tested on each.

What sort of issues can arise when targeting different processors? Any assembly code, of course, needs to be written for all target platforms. The same holds true for any bit-twiddling that makes assumptions about the target architecture. That's another reason to avoid such code whenever possible. Further, alignment issues surprise a lot of people who haven't worked with RISC processors before. For example, code like:

BYTE buf\[10\];
DWORD pdw = (DWORD*)&buf\[5\];
*pdw = 15;

will work fine on x86 processors, but it will cause unaligned access exceptions on RISC processors. Always try to avoid unaligned access. In addition, compiler, header, and chip bugs crop up occasionally. In fact, it's possible for a piece of code to mysteriously crash on only a single platform. Eventually it's discovered that a compiler bug was at fault. These situations are rare but, because no tools are perfect, they will occur on occasion.

For all of these reasons, diligent quality assurance (QA) on every single target processor is of the utmost importance. BSQUARE Corp. offers a QA product that provides application and system-level testing for any Windows CE device.

For those of you looking for additional information on programming for Windows CE, there are a number of resources you can turn to (see "Windows CE Resources" on this page) PC, ARM, and x86. If a Windows CE application is to be as widely available as possible, it must be built and tested on each processor.

What sort of issues can arise when targeting different processors? Any assembly code, of course, needs to be written for all target platforms. The same holds true for any bit-twiddling that makes assumptions about the target architecture. That's another reason to avoid such code whenever possible. Further, alignment issues surprise a lot of people who haven't worked with RISC processors before. For example, code like:

BYTE buf\[10\];
DWORD pdw = (DWORD*)&buf\[5\];
*pdw = 15;

will work fine on x86 processors, but it will cause unaligned access exceptions on RISC processors. Always try to avoid unaligned access. In addition, compiler, header, and chip bugs crop up occasionally. In fact, it's possible for a piece of code to mysteriously crash on only a single platform. Eventually it's discovered that a compiler bug was at fault. These situations are rare but, because no tools are perfect, they will occur on occasion.

QA Is Critical
For all of these reasons, diligent quality assurance (QA) on every single target processor is of the utmost importance. BSQUARE Corp. offers a QA product that provides application and system-level testing for any Windows CE device.

For those of you looking for additional information on programming for Windows CE, there are a number of resources you can turn to (see "Windows CE Resources" on this page).



Windows CE Resources
  • Teach Yourself Windows CE Programming in 24 Hours, www.amazon.com/exec/obidos/ASIN/0672316587
  • CE Developers FAQ, www.cegadgets.com/wince
    devfaq.htm
  • Windows CE-Dev Mailing List, www.lists.windowsce.com/lyris.pl?enter=windowsce-dev&text_mode=0&lang=english
  • USENET Newsgroups: microsoft.public.win32.programmer.wince, and comp.os.ms-windows.ce


Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish