This article assumes youï¿½re familiar with Visual Basic and Visual C++
Level of Difficulty 1 2 3
Download the code for this article: CETools.exe (110KB)
SUMMARYThis article provides an overview of writing applications for Windows CE 3.0. Unicode support in Windows CE, the kernel, memory management, the object store, and COM and DCOM are discussed. The article also covers the user interface, graphics, the Internet, and how Windows CE compares to the desktop in each of these areas. eMbedded Visual Tools 3.0 is discussed in depth. To help the reader decide which tools to use, development with Visual Basic, Win32, MFC, and ATL are explained. Text editor samples with this article have been developed with Visual Basic and Win32 so their implementations can be compared.
f you are just jumping into the world of WindowsÂ® CE, I think you'll be pleasantly surprised with what you find. Microsoft has been growing and nurturing this compact version of Windowsâ"and the tools needed to develop software for itâ"since Windows CE 1.0 hit the streets in 1996. Today, there are hundreds of different types of devices that are powered by Windows CE. The most widely known include the Pocket PC and the Handheld PC (HPC). But many other devices are built on Windows CE. In the home entertainment arena, TV set-top boxes and the Sega Dreamcast use Windows CE. In the industrial automation arena, there are programmable logic controllers and other factory-floor devices built on Windows CE. Mobile data collection devices, cell phones, bar code readers, automatic teller machines, and digital cameras can be added to the list of Windows CE-based devices to name just a few. If you're new to software development for Windows CE, your watchword is choice. You have a broad range of tools to choose from for developing Windows CE-based applications. You can write to the Win32Â® API using C or C++ for the smallest and fastest code. If you are looking for a C++ class framework, you can use the MFC library. For creating ActiveXÂ® controls and components, ATL is also supported. If you're a fan of Visual BasicÂ®, you can build Visual Basic-based applications targeted for Windows CE using eMbedded Visual Basicâ"a cross between browser-based VBScript and Visual Basic for the desktop. And there are more tool choices to come. In the future, as the MicrosoftÂ® .NET initiative starts shipping, a C# compiler for Windows CE is scheduled, along with a .NET Framework runtime library for Windows CE. It's already pretty good, and it's just going to get better. The goal of this article is to describe what Windows CE can do, and to help you select development tools. For readers who are new to Windows CE, this article starts with a developer-oriented description of Windows CE with particular emphasis on the exact subset of Win32 that is supported on Windows CE 3.0. The second part of the article reviews existing development tools for Windows CE, along with a discussion of their relative strengths and weaknesses. I have also created two sample applications: a text editor called VBEdit written in eMbedded Visual Basic, and one called EDITOR for Win32. (The source code for each is available from the link at the top of this article.) Studying the two samples should provide a taste for what is involved in developing for Windows CE.
Windows CE is still new enough that there are myriad misconceptions about it. A Wall Street Journal article called it "Windows 98-Lite," a description that's inaccurate because Windows 98 is based in part on a 16-bit code base. Windows CE could more appropriately be considered a light version of Windows 2000 because it has a sophisticated memory manager, a scheduler that supports multithreaded programming, and almost all the features of an advanced modern operating system. The one exception is support for a page file, which is hardly an issue given that Windows CE was built to operate without a hard drive. One way to describe Windows CE is in terms of the design goals that guided the original development team. For details, see my article, "Microsoft Windows CE: It's Not Just for Handheld PCs Any More" in the May 1998 issue of MSJ.
Windows CE contains a subset of the features you have on your desktop. But by subset I don't mean to imply incompleteness. The features contained in Windows CE represent a carefully selected subset, balancing the benefits of a given feature against the costâ"measured by memory used. The most useful, most used, most popular, and most powerful features have been ported from desktop versions of Windows to Windows CE. So what has been left out Redundant functions have been severely trimmed so that, for example, you only have one text drawing function instead of two. Another category of omission is support for legacy (Win16) applications on the desktop, so that there is no support for reading or writing .INI filesâ"in Windows CE you use registry functions to store program settings. Things that are just too big have been left out, like the Messaging API (MAPI). While MAPI itself is not supported, there is a message store API for accessing the Pocket OutlookÂ® inbox programmatically. In general, you'll find rich support for the features your application needs. Occasionally a developer will get grumpy about something that didn't make the cut to Windows CE. Maybe it's a Win32 function call, an MFC class, or a Visual Basic control. When you encounter one of these, there's often another way to do what you want. In some cases, though, you have to choose between rewriting the feature from scratch or cutting it from the Windows CE-based version of your application.
Windows CE is the first operating system from Microsoft to require Unicode characters in text strings. Unicode is a character set created by a consortium of computer companies, and blessed by international standards organizations. Unlike the single-byte character sets used for European and North American languages, or the mix of single and double-byte characters used for Far Eastern Asian languages, all Unicode characters take up two bytes. All the programming APIs for Windows CE â"Win32, MFC, or Visual Basicâ"lean heavily on Unicode for text strings. The impact this has on your programming depends on whether your Windows CE-based program gets data from the outside world. If you use data files that were created on a PC, you might need to convert strings to Unicode. Many modems send status information and accept command strings using one-byte character strings. Other devices, like GPS devices described in Joshua Trupin's article in this issue, also use one-byte strings. For all of these, you'll have to perform the appropriate conversion if you're writing Win32-based code. There are a few odd departures from a Unicode-only approach that you should be aware of: two involve networking, and one involves Visual Basic. When working with sockets, all string parameters are ANSI strings, not Unicode. This is more surprising than anything else, given the Unicode-only approach everywhere else. I suspect this has to do with the fact that technically speaking, the Windows Sockets functions are not a part of the Win32 API. After all, Winsock was created by a group of network programmers working together to create a new API. Imposing Unicode on it would no doubt break some applications. The second departure involves the Windows Internet (WinInet) API library. For these functions, you'll find both ANSI and Unicode versions for each function that takes a string. For example, you'll find both InternetOpenA and InternetOpenW supported on Windows CE-based devicesâ"handy, if unexpected. The third departure is in the FileSystem control provided with eMbedded Visual Basic for doing file I/O. Unlike the desktop version of Visual Basic, there are no built-in statements for accessing files. Instead, you need to use an ActiveX control. While the ActiveX control can read both ANSI and Unicode, it only writes ANSI strings. In my VBEdit sample application, you can see a workaround using native Win32 functions to write Unicode strings to files. Figure 1 describes the functions for converting between Unicode and non-Unicode (ANSI) character strings. My personal favorites are the two C runtime functions, mbstowcs and wcstombs. They take the fewest parameters, and are therefore the easiest to use. While these two functions come from the C Runtime Library, they are so useful that they have been added to the core Windows CE library (coredll.dll), making them also available to Visual Basic-based applications for Windows CE.
Windows CE sports great core operating system support. If you are familiar with the key features of Windows 2000, you'll find that almost every feature from the desktop is available. Windows CE is a multiprocess operating system, although there is a limit of 32 processes that can be createdâ"a limitation not found on desktop versions of Windows. Windows CE is a multithreaded operating system, and there are 256 thread priorities that give you a high level of control over how the scheduler distributes CPU time. All four synchronization objects from desktop versions of Windows are present in Windows CE: critical sections, mutexes, semaphores (new with Windows CE 3.0!), and events. For more information see my article, "Windows CE 3.0: Enhanced Real-Time Features Provide Sophisticated Thread Handling" in the November 2000 issue of MSDN Magazine. Windows CE supports Win32 exception handling (the __try and __except keywords) as well as termination handling (__try and __finally). These will help you weave a safety net into your code to catch problems with bad pointers, overflows and underflows in math, and division-by-zero errors, to name just a few. While the Win32 exceptions are present, C++ exceptions are not. C++ programmers know this feature as the object-oriented equivalent of Win32 exceptions, accessed with keywords like try, catch, and throw. Just like desktop versions of Windows, Windows CE is built on a foundation of dynamic link libraries. You'll quickly find that the familiar DLLs from the desktopâ"kernel32.dll, user32.dll, and gdi32.dllâ"have been replaced with a single main library, coredll.dll. And just like on the desktop, DLLs can hold code, data, and resources. As on the desktop, a program can statically link to a DLL, or link dynamically by calling LoadLibrary (or LoadDriver to load and lock the DLL in memory). There are a few other omissions in kernel-level support from what you find on desktop versions of Windows. For one thing, there is no support for fibersâ"the lightweight scheduling objects found in Windows 2000. Also, the sophisticated security model of Windows 2000â"with its security descriptors and access control listsâ"is not available in Windows CE. Security has not entirely been abandoned, however, as Windows CE supports Secure Sockets Layers (SSL) and the encryption APIs.
In general, Windows CE was built to perform well on small devices, in a small pool of memory, on portable, battery-operated devices. Windows CE requires a little-endian, 32-bit processor and was built to run using paged virtual memory. Each Windows CE process has a virtual address space of 32MB. This is quite a bit smaller than on desktop versions of Windows, which provide a 2GB process address space. At first glance, this might seem to be a significant difference. But when you consider that a typical Windows CE-based device has between 16 and 32MB of physical RAM, it seems likely you'll run out of physical memory before you run out of virtual address space. Applications that need to work with larger objects have a back door: shared memory is allocated from a gigabyte-sized part of the address space. In spite of the emphasis on a small footprint, Microsoft did not skimp on any memory-related feature. With one exceptionâ"the GlobalAlloc family of functionsâ"the entire Win32 memory API is present in Windows CE. You allocate pages by calling VirtualAlloc, allocate from a private heap with malloc, LocalAlloc, or the C++ new operator. You have the same kinds of thread local storage as you have on the desktopâ"the dynamically allocated kind that you get by calling TlsAlloc, as well as the statically allocated kind that comes with the __declspec (thread) keyword. And just like on the desktop, you can allocate memory to be sharedâ"and objects that break the 32MB limitâ"by calling MapViewOfFile. Another important difference from the desktop is that Windows CE does not support a page file. So while the pieces of executable (.EXE and .DLL) files can be demand-loaded into memory, Windows CE has no pagefile.sys file to create the kind of virtual memory that you find on operating systems built for larger machines.
Windows CE provides three basic places to store data: in the file system, in a registry (much like the registry on desktop versions of Windows), and in databases. All three live together in RAM in an area called the object store. In Windows CE 3.0, the object store can be up to 256MB (the limitation on previous versions of Windows CE was 16MB). The file system supports a hierarchical directory structure that has the same maximum path lengthâ"260 characters, or MAX_PATHâ"as on the desktop. This common limit means that you can freely move data filesâ"with paths intactâ"between a Windows CE-based device and a Windows-based PC. One difference from the desktop is that drive letters (A:, C:, D:, and so on) are not supported in Windows CE. The object store itself is stored as a RAM image, but Windows CE can easily accommodate magnetic media such as floppy diskettes, hard drives, and CDs. Many devices also have a Compact Flash (CF) slot into which you can plug a storage card that uses flash memory. The memory in these cards is available solely to extend the file system; it does not extend the available program execution space.
Two basic types of support can be provided by a given Windows CE implementation. Basic COM support, introduced with Windows CE version 2.0, consists of support for in-process servers. In-process servers are DLLs that contain a component and runâ"like all DLLsâ"in the address space of the calling application. Basic support includes component memory management (CoTaskMemAlloc), compound files (StgCreateDocfile), and Automation (the ability to expose functions and methods to Visual Basic). Devices running Windows CE 2.0, such as the HPC and Palm-size PC, all provide basic COM support. The same level of support is also provided on the newer Windows CE 3.0-based devicesâ"including the Pocket PC. All of these devices basically support the ability to create and access DLL-based COM objects. Developers of COM clients and servers on desktop versions of Windows know that DLL-based COM objectsâ"also known as in-process serversâ"are just one of three basic types of COM objects that can be created. The other two are local servers and remote servers. A local server resides on the same computer as its client, except that it runs in a different address space. A remote server runs on a different computer entirely. Windows CE 3.0 provides support for these two additional types of COM servers, and lumps them together as DCOM components. This is a slightly different packaging than may be familiar to you from desktop versions of Windows, where DCOM typically refers just to support for remote servers and not local servers. The difference is probably an accident of history. On the desktop, support for in-process servers and for local servers was introduced at the same time. Support for remote servers came much later. Support for COM in Windows CE, on the other hand, first consisted of in-process server support in Windows CE 2.0. The other two types are only now being made available with Windows CE 3.0.
Like on the desktop, a Windows CE-based system can have a graphical output screen and provide pretty much the same set of user interface objects. A key difference is that Windows CE-based devices tend to have much smaller display screens. So while a typical desktop runs with a minimum resolution of 1024x768, the Pocket PC ships with a sideways quarter VGA (240x320) screen. Windows CE provides a handful of user interface helpers, including common dialog boxes (although only four of the eight found on the desktop are present) and common controls. With the common controls, only a subset of what you have on the desktop is present. But again, they represent the best of the controls available on desktop versions of Windows. Windows CE provides a few new ways for a user to interact with a computer. Actually, a type of pointing device, the touch screen, isn't really new at all. I recall that Hewlett-Packard had a PC with a touch screen at least 10 years ago. But it never caught on, and the concept was dropped. Lots of different Windows CE-based devices have this feature, which provides a more convenient alternative to a mouse. Programmatically, a touch screen is treated just like a mouse. For example, programmers using Win32 get WM_MOUSEMOVE messages; programmers using Visual Basic get MouseDown and MouseUp events, just as they do on the desktop. An important area of innovation has been voice recognition. It was introduced first for the Windows CE for Automotive products, where it provides a safer alternative to a keypad. But even when safety is not an issue, voice input is an area that has already begun to have an impact on information systems. It promises to help enhance man to machine interactions by making every telephoneâ"cellular or wire-basedâ"into a computer terminal.
Desktop versions of Windows have always been graphical systems, and the same is true of Windows CE. And while the size of the graphical output libraries is smaller than on the desktop, Windows CE provides very reasonable support for graphical output. On the desktop, there are three basic graphical libraries: the Graphics Device Interface (GDI), DirectDrawÂ® (the game API first introduced with Windows 95), and OpenGL, a 3D drawing package licensed from Silicon Graphics. Windows CE provides 85 of the 325 or so GDI functions that are available on the desktop. While this makes it sound like Windows CE doesn't have much support for graphical output, in fact, the opposite is true. You can pretty much draw any text string, line, polygon, or bitmap that you can on the desktop GDI. You can even rotate text when you draw it. The only thing not supported is coordinate mappingâ"the ability to draw in inches, centimeters, or twips. Instead, all drawing must be in pixels. Microsoft introduced support for DirectDraw, the high-performance graphical API, with the Sega Dreamcast, a device that supports Windows CE 2.01. It was made more widely available in Windows CE 3.0, and is even included on the Pocket PC. There is currently no support for OpenGL on any version of Windows CE.
The importance of the Internet is undeniable, so it's not surprising to find tons of support for it in Windows CE. Every version has always supported sockets, which is a low-level network communications API. In fact, support for infrared devicesâ"which are on almost every Windows CE-based deviceâ"is provided in part by sockets. Windows CE has always supported the WinInet APIs, which provide for direct control over Web server connections (HTTP), as well as connections to FTP servers. Windows CE 3.0 can also host a Web server, complete with support for Active Server Pages and ISAPI extensions, as outlined in the article "Windows CE Web Server: Using Web Tools to Monitor and Manage Embedded Devices" by Leonid Braginski and Matthew Powell in the May 2000 issue of MSDN Magazine. On the browser end of things, Windows CE has a broad range of choices. At the low end, any program can host the HTML viewer control. This control, which is the same one used by the Windows CE help engine (peghelp.exe), does basic display of rich text. You can embed this control into any C or C++ program (but not into a Visual Basic-based program). It's not as great as it may sound at first, though, since you have to display any graphic imageâ"GIF or JPEGâ"yourself. Windows CE supports two Web browsers: Microsoft Pocket Internet Explorer and Microsoft Internet Explorer 4.0. Pocket Internet Explorer was written from scratch for Windows CE. As released, it is very small (1.3MB) and supports basic browsing. The second browser is Internet Explorer for Windows CE. It is a port from the desktop version of Internet Explorer 4.0, Service Pack 2. It is quite a bit larger (3.1MB) than Pocket Internet Explorer, and also has support for most of the bells and whistles that you find on the desktopâ"frames, cascading style sheets (CSS), and Dynamic HTML to name just a few. However, it doesn't support VBScript, just JScriptÂ®. A few other features, such as client-side data binding (DATASRC and DATABIND attributes), are not supported. You'll find more details on browsers compatible with Windows CE in "Internet Programming with Windows CE" in the May 1999 issue of Microsoft Internet Developer.
Since the first version of Windows CE shipped, Microsoft has added to the list of available development tools for the platform. Currently there are two basic development tool products for Windows CE: Platform Builder 3.0 and eMbedded Visual Tools 3.0. I mention Platform Builder because it is out there and many application developers want to know what it is and whether they will need it. My guess is that only a few developers will need it. Instead, the tool to use is eMbedded Visual Tools 3.0. Platform Builder is the tool you can use to create custom configurations of Windows CE itself. Perhaps you're an OEM who wants to embed Windows CE into a laser printer, a flatbed scanner, a digital camera, or a cell phone. You would use Platform Builder to determine whether you wanted to include, for example, support for property sheets and dialog boxes. If you've been working with Windows CE long enough, you might remember the old name for this toolâ"the Windows CE Embedded Toolkit. Platform Builder has two different modes of operation: command-line and GUI-driven (see Figure 2). The two are basically equivalent, although the graphical front end is somewhat easier to learn. Whichever approach you take, you select elements to include by editing Binary Image Builder (BIB) files. You have the ability to specify the device drivers to be included, which parts of the API to include, as well as applications and application support files to include. You also specify the settings in the system registry when a device is first turned on. Once a platform has been builtâ"including the hardware, the device drivers, and the operating system itselfâ"the next step is to build application software. One nice feature of Platform Builder is the ability to spin a custom SDK to support the efforts of application developers working with your version of the platform. The eMbedded Visual Tools 3.0 package is an all-in-one environment for Windows CE-based development, similar to Visual StudioÂ®. It rolls into a single package all the support that used to require four separate products. Unlike previous application development products for Windows CE, it is not simply an add-on to the existing tools for Visual C++Â® and Visual Basic. Instead, it provides all that you need from both environments in a single, standalone package. You can order this package for the cost of shipping from the Microsoft Web site at http://www.microsoft.com/PocketPC/developer.asp. Inside this package, you access each of the four programming interfaces that I discussed earlier in this article. I will look at each of the four in turn: Visual Basic, Win32, the MFC library, and ATL.
When you install the eMbedded Visual Tools, three items are added to your Start Menu: eMbedded Visual Basic 3.0, eMbedded Visual C++ 3.0, and the Api Text Viewer. The names of these toolsâ"and their associated iconsâ"won't look in the least bit familiar to anyone, whether you've developed for Windows CE before or not.Figure 3 eMbedded Visual Basic 3.0 But when you start running the tools, you'll see a lot that is familiar. It is, as Yogi Berra says, "dï¿½jï¿½ vu all over again." eMbedded Visual Basic 3.0 looks a lot like Visual Basic 6.0 (see Figure 3). Similarly, eMbedded Visual C++ 3.0 looks a lot like its counterpart on the desktop, Visual C++ 6.0 (see Figure 4).Figure 4 eMbedded Visual C++ 3.0 This is your first clue that while the names and the packaging of the development tools for Windows CE have changed, what you find inside is very familiar. A brief perusal of the eMbedded Visual Basic menus shows that a few things are missing from Visual Studio, but that the majority of core functionality remains. eMbedded Visual C++ is practically a clone of Visual C++ 6.0; you'll have to look very hard to find the few places where the two are not the same. Both environments feature familiar editors, menus, and settings windows. Both offer a starting point for building apps, although in this arena the eMbedded Visual C++ environment offers the richer collection. Its wizards let you create Win32 and MFC applications, and it also supports the creation of ATL components. When you create a new eMbedded Visual Basic-based project, you get to choose between four project types: a formless project (good for headless Windows CE-based systems), a Palm-size project, a Pocket PC project, and a Handheld PC Pro (HPC Pro) project. Developers who are used to the dozen or so project types in Visual Basic 6.0 will no doubt miss the lack of flexibility, but I assume that more project types will appear in future releases. Both eMbedded Visual Basic and eMbedded Visual C++ support a set of remote tools, which are described in Figure 5. To use these tools, a Windows CE-based device must be connected to a development workstationâ"either by a serial or USB cable or through a network. I have used all of these tools at one time or another. I've found the Remote Registry Editor to be particularly useful when working with COM and ActiveX controls. I use the File Viewer to copy files onto or from a Windows CE-based device (although you don't use this tool for executable files, since this is automatically done for you as part of the build process). Sometimes I find that I need to use the Process Viewer to kill a process that isn't responding. Spy and Zoom behave the same as their desktop counterparts, so they don't need further introduction here. A key part of both eMbedded Visual Basic and eMbedded Visual C++ is support for downloading and debugging applications. While it might not seem obvious to Windows CE newbies, a key issue for developers using Windows CE is getting new programs loaded onto an actual device and then being able to debug on that device. This is supported pretty well, and you can download either via a serial line or using a network. Of the two, the preferred method is to download and debug over a network. The key issue here is speed. Especially when stepping through code, it's painful to have to wait several seconds for the debugger command to be shipped to the device, executed, and then shipped back. To postpone this pain, eMbedded Visual Tools includes the Windows CE emulator. There is an emulator for each type of device running Windows CE. Running your Windows CE-based programs on the emulator gives you a chance to fine-tune it during the early stages of your development project. The emulators can run on Windows NTÂ® 4.0 or Windows 2000, but are not able to run on Windows 95, Windows 98, or Windows Me (due to lack of Unicode support). Figure 6 shows my sample application, VBEdit, running in the emulator for the Pocket PC. Each target device needs its own emulator, so when you develop for Windows CE you discover there is one emulator for the HPC, another one for the HPC Pro, yet a third for the Palm-size PC, and still another one for Pocket PC. Of course, you'll still need to test and debug all software on all available devices. The reason is simple: the emulators don't provide 100 percent of the same behaviors that you find on an actual device. This is due to the fact that the emulators come from a different code base, instead of having a common code base with the emulated device. While overall emulation is quite good, the few differences mean that you can't rely on it for final testing.
If you've written Visual Basic-based programs for the desktop using any version of Visual Basic, you'll be happy to find that you can use your knowledge to build applications for Windows CE. And, indeed, there are many similarities between Visual Basic and eMbedded Visual Basic. At the same time, Windows CE was built to run on small devices. For this reason, the Visual Basic team created a significantly scaled-down version of Visual Basic. Perhaps the most important point to be made is that eMbedded Visual Basic does not contain a compiler. Applications run in an interpreter that is summoned when PVBLOAD.EXE, the Pocket Visual Basic Loader program, is run. The eMbedded Visual Basic environment does not create an .EXE file, but rather a .VB file that contains a tokenized version of your program. Unlike regular Windows CE executable files, this is a CPU-independent file that can be copied to any Windows CE-based device. That fileâ"plus the runtime libraries and other support files, which are device-dependentâ"are what you need to run a Visual Basic-based program on Windows CE-based device. Just like on the desktop, eMbedded Visual Basic lets you call into any available dynamic link library using the Declare statement. For example, here is the declaration for calling the Win32 MessageBox function:
Public Declare Function MessageBoxW Lib "coredll" (ByVal hWnd As Long, ByVal strText As String, ByVal strCaption As String, ByVal uType As Long) As Integer
Public Declare Function MessageBoxW Lib "coredll"
(ByVal hWnd As Long,
ByVal strText As String, ByVal strCaption As String,
ByVal uType As Long) As Integer
The Visual Basic runtime inherits from desktop versions of Visual Basic the odd convention of referring to string parameters with ByVal, not ByRef. A friend on the Visual Basic team told me that strings are pointers to pointers in Visual Basic. It logically follows that ByVal causes a pointer to be passed, and ByRef passes a pointer to a pointer. To call the function declared a moment ago, use a statement like the following:
MessageBoxW frmMain.hWnd, "Clicked on Menu", "VBEDIT", vbOKOnly
You might have noticed that the name of the function has an extra W on it. That's because Windows CE only supports Unicode characters. On Windows NT, the names of functions that accept strings are appended with either an A (for ANSI) or a W (for wide). This convention allows support for two different character sets to peacefully coexist. Windows CE inherits this oddity of Win32, and you'll need to remember it anytime you call a Win32 function that takes a character string. Functions that don't take a character string (MessageBeep, for example) stay unchanged. Unfortunately, the Visual Basic runtime doesn't support the Type statement, which means you cannot define your own structures. This is problematic because it means you cannot directly call any DLL function that requires a pointer to a structure. Of course, this is hardly an unsolvable problemâ"you can simply create your own DLL that wraps whatever DLL functions you want to call. To create DLLs in Windows CE, you'll need to use C or C++, which means you'll need to use eMbedded Visual C++. That environment provides a built-in wizard that makes it pretty quick to create a DLL. Another point that should be made about the Visual Basic runtime is that the only supported data type is VARIANT. If you are a student of COM and Automation, you may know that this is a compound data typeâ"a union in C programmer termsâ"that is large enough to hold any of the basic numeric data types. It also has a flag that identifies whether the element being held is a short or long integer, a short or long floating point number, or a string (to name just a few). The chief benefit of supporting a single data type is simplicity. Internally, all parameters to all functions are all the same, as is the type returned by functions. The chief drawback to a VARIANT-only system is the memory overhead. A basic VARIANT occupies 16 bytes, whether you are storing a 2-byte Integer or a 4-byte Long value. Purists won't like this at all, since it represents a tax of 700 percent for the 2-byte value and a tax of 300 percent for the 4-byte value. Among other things, avoid making arrays much larger than what you actually need. The ReDim statement is supported in the Visual Basic runtime to help you resize arrays as you need to. (Yes, arrays are supported in the Visual Basic runtime.) However, I don't see this as a huge problem. In general, I believe that developers of large applications will hide most complexity inside a DLL or in an ActiveX control. Most of the variables that you'll need will be used to manage both the user interface and the interactions between components. Developers who have used the Api Text Viewer tool from the desktop will be happy to know that it can also be used with eMbedded Visual Basic. As mentioned earlier, it gets placed within the Start menu next to the other eMbedded Visual Tools. It provides function declarations, constants, and structure type information for calling Win32 functions from Visual Basic. Since eMbedded Visual Basic doesn't support user-defined types, only the function declarations and constants are useful. A quick perusal of the definitions file showed that not all Win32 functions supported in Windows CE are present (CreateWindow, for example, is missing). You might prefer to use the input file (WIN32API.TXT) from Visual Basic for any missing functions, and substitute the Windows CE library coredll.dll in place of user32.dll, kernel32.dll, or gdi32.dll.
VBEdit is an application that I wrote using eMbedded Visual Basic 3.0 (see Figure 6). Assuming that you are familiar with Visual Basic, the first application you write for Windows CE will probably take a bit more effort than would be required on the desktop. That was certainly the case for me when I wrote VBEdit. Part of the extra work was due to the fact that fewer features are present in eMbedded Visual Basic than I had anticipated. Another commonly overlooked fact is that it simply takes longer to build on one computer and then run on another. The downloading of the application takes time, as does the downloading of all the sundry support files (like the Visual Basic runtime and the supporting ActiveX controls). Even if things have been downloaded once, a check is done every time to make sure that things are as they need to be. VBEdit lets you create and edit Unicode text files. The user interface is just a simple edit controlâ"or textbox, in the terminology of Visual Basicâ"that does most of the real work of dealing with the text. Most of the code in this program handles the various menu selections. I incorporated three ActiveX controls that were part of the standard set that ships with a common dialog control, a file system control, and the Pocket PC menu control. When I was finished designing my program, I ran the Application Install Wizard, which packaged up everything that would be needed to ship my program. Figure 7 lists and describes the files that were included. The code that I wrote had gotten parsed and tokenized, so that my original source code isn't available for you to read (unless you want to go to the trouble of reverse-engineering this file). My program by itself was a mere 8KB. As written, my program required another 290KB of ActiveX controls. It is reasonable, I think, to regard this as overhead for my program, since these controls are not installed on a typical Pocket PC. The final set of files make up the Visual Basic runtime, and are present in ROM on a typical Pocket PC device. This 557KB image is listed here as part of the total cost to run my program, although you'll have to determine whether these are in ROM on the device you are targeting. If not, they'll need to be installed to the object store of the target device. Object store compression will ease this cost somewhat because of the 2x compression that you get for free.
Charles Petzold, a Windows pioneer and author, once remarked to me that the Windows API was "the macro language of Windows." Indeed, it provides the lowest-level API that can be used for programming in Windows. It provides the way to write the smallest and fastest applications. Even if you don't write your entire application using Win32, you'll need to write some code using it in one form or another no matter which programming technology you adopt. Win32 is important to Windows CE because it represents the only programming API supported natively by the operating system. This is the first time in many years that an operating system from Microsoft only supported one API. As shown in Figure 8, every version of Windows has at least supported the MS-DOSÂ® API. In the case of Windows NT and Windows 2000, five APIs are supported. But with Windows CE, there's just one: Win32.
If you're just getting started with programming in Win32, you'll find the eMbedded Visual C++ wizards to be very helpful. In particular, with a few mouse clicks you'll be able to create everyone's favorite first program: Hello World. Even if you're an old hand at programming in Win32, you'll probably want to review the code that the wizard creates. The reason is that there are some device-specific function calls that are demonstrated very nicely. In particular, if you are getting started with the Pocket PC, you'll want to know how to tame the software input panel (SIP). Figure 9 shows two example SIPs taken from the Pocket PC emulator.Figure 9 Software Input Panels So why do you need to tame the SIP The key issue is that screen real estate is scarce on the Pocket PC, as it is on any Windows CE-based device. But since this device doesn't have a keyboard, the user will need the SIP to enter or edit textâ"and the SIP itself chews up this precious screen space. In some cases, your program will display the SIP automatically, which will certainly be the case when focus gets passed to an edit control. In other cases, a user can manipulate the SIPâ"making it appear, disappear, or make a change from keyboard to handwriting recognizer. For all of these cases, you want to make sure you respond in an appropriate manner: a window might need to be resized, some scroll bars might have to be moved, or drawings might have to be scaled. In general, the Hello World program created by the eMbedded Visual C++ IDE provides a good starting point for seeing how to handle the SIP. Unfortunately, there were a few changes made to the Pocket PC at the last minute, and some of these changes mean that you'll need to edit the Hello World program that the wizard creates. Figure 10 describes the SIP handling that the eMbedded Visual C++ IDE wizard puts into the typical Hello World program for you; you'll want to make sure to incorporate these into your own Win32-based Pocket PC programs. Figure 11 outlines two changes that you'll want to make to a Hello World application to bulletproof its SIP handling. While these changes are pretty simple, it took a bit of futzing around to figure out that they were needed. The first is that a data structure needs to be initialized. While there are many places you could do this, I tend to prefer to do it in response to the WM_CREATE message:
case WM_CREATE: memset(&s_sai, 0, sizeof(SHACTIVATEINFO)); s_sai.cbSize = sizeof(SHACTIVATEINFO); // New! hwndCB = CreateRpCommandBar(hWnd); break;
memset(&s_sai, 0, sizeof(SHACTIVATEINFO));
s_sai.cbSize = sizeof(SHACTIVATEINFO); // New!
hwndCB = CreateRpCommandBar(hWnd);
The second item is to respond to the WM_ACTIVATE message by calling one of the SIP helper functions, SHHandleWMActivate. The primary benefit of calling this function is that it resizes your program's main window to accommodate the SIP. This is especially important if your program tries to draw into its entire client area because the SIP will clip any such drawing if the window is not properly sized. A window that's not sized properly also becomes obvious if you have a scroll bar, because the SIP will likely also clip a scroll bar that is attached to an improperly sized window. Here is the code to handle this:
case WM_ACTIVATE: SHHandleWMActivate(hWnd, wParam, lParam, &s_sai, 0); break;
SHHandleWMActivate(hWnd, wParam, lParam, &s_sai, 0);
One final change that I always like to make to the typical Hello World application is to add an OK button to the caption bar. This makes it convenient to shut down an application that you are developing. The code for this involves changing the CreateWindow call into a call to CreateWindowEx. Here is the code I like to use:
hWnd = CreateWindowEx(WS_EX_CAPTIONOKBTN, szWindowClass, szTitle, WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
hWnd = CreateWindowEx(WS_EX_CAPTIONOKBTN, szWindowClass, szTitle,
WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
If you haven't used a Pocket PC before, you might wonder why an extra step is needed to shut down a program. After all, isn't there a system menuâ"like on any normal system Well, the answer is not normally. The Pocket PC is meant to behave more like an information appliance than like a PC on a bun. That is, a program on the system is assumed to be always availableâ"just like a toaster always has a darkness setting. Users don't shut down applications; they just run forever. (Although Windows CE itself might ask a program to go away if memory is scarceâ"but that is done without user intervention or knowledge.) Users don't save dataâ"when a change has been entered, it is automatically saved. Programs don't ask users if they're sure; a program always assumes that a user is sure. If a user erases something, it is gone for good. In other words, you'll probably want to have an OK button on the caption bar of your programs while you are developing them. And OK buttons will appear in dialog boxes. But, in general, your shipping Pocket PC-based applications won't have a Close menu, an OK menu, or any desktop trappings that allow them to close (or require a user to think about closing) an application.
To get a better sense of the differences between Visual Basic and Win32 on Windows CE, I wrote another text editor program. Like the Visual Basic version, the version using Win32â"which I call EDITORâ"uses the system's built-in edit control, reads and writes Unicode text to the file system, and has clipboard support. Like VBEdit, my Win32-based editor uses the built-in common dialog boxes to allow the user to select a file to open, and also to pick a name (and a location) for saving a file. On the subject of opening and closing files, it's worthwhile to point out how files are viewed on the Pocket PC, since it is different from the desktop. There are two views that are interesting here: what really exists, and what the user sees. What really exists is a hierarchical file system that looks an awful lot like what you have on the desktop. There is a Windows subdirectory and a Program Files subdirectory, both of which contain the kind of things you find on their desktop counterpart. Another subdirectory, Windows\Start, contains executables (or links to executables) for all of the items that the user sees on the Start menu. In short, when you browse through the file systemâ"which can easily be accomplished with the Remote File Viewerâ"you see a lot that is familiar. Things look a bit different to a user. In particular, the common dialog boxes only let the user see into a directory named My Documents. For programs that bother to show users the file system, what they can show the user is an area set aside to hold user files. This is a nice thing, since it prevents users from mucking about with OS or application files. Of course, developer types always like to see what is really there. Fortunately, there is a File Explorer program, which is basically a Pocket PC version of the desktop file explorer. With this utility, you can look into any subdirectory, as well as onto a CF storage card you might have plugged into the CF card slot. To build EDITOR, I started with a typical Hello World programâ"which gave me a 244-line head start toward my program. Once I'd put in the fixes to make it work properly with the SIP (discussed earlier in the "Hello Again" section), it took another 200 lines or soâ"for a total of 456â"to get the same behavior as VBEdit. For its part, VBEdit had only 132 lines of code, not to mention the help of three ActiveX controls. From a pure lines-of-code perspective, Visual Basic came out ahead as the smaller of the two. From the perspective of final executable images, though, the Win32-based program was clearly the leader. Weighing in at only 8-10KB (depending on the CPU), it had a much smaller footprint. Although the tokenized (compiled) version of the Visual Basic code was only 8KB, you have to add in the 300KB or so for the ActiveX controls. To make an apples-to-apples comparison, of course, I should probably add in the cost of the Win32 libraries. I am pretty biased towards the Win32 API. While it is the least popular API on the desktopâ"a scant five percent of all development uses Win32 aloneâ"for the present, at least, it is my own personal preference for Windows CE-based development.
When Microsoft introduced the first Windows operating system back in 1985, it was an environment designed to be easy to use. However, it was not necessarily an environment for which it was easy to write code. For this reasonâ"to help programmers be productiveâ"Microsoft created the MFC library. MFC provides an object-oriented encapsulation of the Windows API that can be accessed from C++. It provides a framework that hides a lot of the fussiness of the Win32 API. At the same time, it introduces its own particular type of complexity, which can make it somewhat hard to learn. To a certain extent, this is compensated for by all the helper utilities that are availableâ"in the form of various wizardsâ"that organize things like message handling, COM, ActiveX handling, and Automation. There are also a slew of helper classesâ"such as the CString string class, to name just oneâ"which tremendously simplifies the handling of otherwise complex tasks. One issue with MFC programming in Windows CE has to do with the size of the runtime library. On the Pocket PC platform, mfcce300.dll varies in size from 276KB (on x86 processor based units) to 506KB (on the Power PC processor-based units). This becomes something of a nonissue on platforms where the redistributable is in ROM, of course, which is the case on devices such as the Pocket PC and the HPC Pro. A second issue is that there are multiple versions of the MFC library. This is, in fact, one of the sources of DLL Hellâ"the problems caused by proliferations of libraries with similar but slightly different services in a set of libraries that all have the same name. On the HPC Pro Edition of Windows CE, the name of the MFC library is mfcce211.dll. This is not an unsolvable problem, but it is a complication that requires time and energy on the part of any software's test and deployment teams. Failing to address this issue early only passes the problem on to the support and training groups. I have found that, at some point, the issue of whether to use Win32 or MFC comes down to thinking about your existing code base and the experience of your development (and support) staff. In general, I have heard good reports from MFC programmers who have made the move from programming for Windows for the desktop to programming MFC for Windows CE. As always, your mileage may vary.
I had lunch with one of my Microsoft friends back in 1995, and she informed me that Microsoft was readying a new, lightweight library for deploying Internet-capable components. That library, of course, was ATL and it has been available for many years now. COM is a very important technology for every Microsoft operating system that's currently shipping. You can implement COM objects in any of several forms: in Win32, in MFC, or using ATL. One reason to use Win32 is that it provides the leanest and most lightweight approach. The downside to using Win32 is that when you create more complex ActiveX components, there isn't a whole lot of support available. MFC is also an option, and its ActiveX support is quite good. If you are already building an MFC application, then using the built-in COM support in MFC makes a lot of sense. But, as I mentioned earlier, MFC brings with it the overhead of its runtime library. The structure of MFC makes it hard to tease out the specific pieces that you need for COM, and leave behind the pieces you don't really need. So if you just want to create a simple COM object, the overhead from MFC makes it hard to justify the memory (both in the file system and when loaded to run) that it costs. ATL was created to provide the benefits of an object-oriented C++ approach combined with the lightness of C++ template libraries. ATL components are a bit heavier than bare-bones Win32 components, but you also get some help from the eMbedded Visual C++ IDE, mostly in the form of nice wizards to help you frame and spin your support code. The good news is that you can use ATL to build your ActiveX components to run in Windows CE. And they can be used to build ActiveX controls to run under eMbedded Visual Basic. The code for the ActiveX controls themselves won't be Visual Basic, however. Instead, it will be C++ using templates from the ATL library.
So which API and tools should you use when building your Windows CE-based applications Everyone has a favorite, and you know what mine is. If your favorite is supported on Windows CE, then you will undoubtedly gravitate toward that one. It is important, however, to realize that winning tool wars is not the point of your workâ"shipping great software on schedule and under budget is. I strongly suspect that the most successful software developers are the ones who learn about all available tools and then pick the most suitable one for each job. Eventually, you'll probably end up using all of these tools at one point or another. In many cases, you'll use two or more of them together. eMbedded Visual Basic, after all, is made all the stronger for having Win32 to fall back on. MFC gives you a reasonable compromise between Visual Basic and Win32. And ATL gives you a good leg up when building ActiveX controls. In short, then, you'll findâ"as I haveâ"that you have a lot of choices available when you jump into programming for Windows CE.
For related articles see:Microsoft Windows CE 2.0: Itï¿½s Not Just for Handheld PCs Any MoreWindows CE Web Server: Using Web Tools to Monitor and Manage Embedded DevicesPocket PC: Migrating a GPS App from the Desktop to eMbedded Visual Basic 3.0
Paul Yao is a Windows programming guru, Windows CE expert, and co-author of the first book published on Windows programming. His company specializes in training programmers in Windows and Windows-related technologies. Visit his Web site at http://www.paulyao.com.
From the January 2001 issue of MSDN Magazine
More MSDN Magazine Blog entries >
Browse All MSDN Magazines
Subscribe to MSDN Flash newsletter
Receive the MSDN Flash e-mail newsletter every other week, with news and information personalized to your interests and areas of focus.