What You Need to Know About "Pegasus," Microsoft's Upcoming Handheld Device

Jeffrey Richter

Jeffrey Richter wrote Advanced Windows (Microsoft Press, 1995) and Windows 95: A Developer's Guide (M&T Books, 1995). Jeff is a consultant and teaches Win32-based programming seminars. He can be reached at v-jeffrr@microsoft.com.

I have become completely dependent on my computer for all sorts of things. Obviously, I use my computer to develop software, but I also use my computer for banking, email, my personal phone book, my appointment schedule, playing games, and so on.

I am not quite at the point where I leave my machine on 24 hours a day, 7 days a week, but soon I will be able to carry a computer in my pocket during those rare hours my desktop machine is not at easy reach (like when I'm flying back and forth between Seattle and San Francisco). This computer's official name has not been announced yet, but its codename is Pegasus. It's being created by Microsoft with six hardware partners. I'll start by showing you the Pegasus hardware from the user's perspective. In the second part of this article I'll dive into the details of the software platform and discuss the programming issues you need to understand to write cool Pegasus apps.

What is Pegasus?

Microsoft has been trying for years to come up with a hand-held computing device. First, there was WinPad. The WinPad machine ran on x86 CPUs only and had a stripped-down version of 16-bit Windows¨ 3.1 as its operating system. The system didn't have a keyboard, but instead used handwriting recognition as its input method (making the machine a poor input device). Its estimated price was $750. After extensive research, Microsoft felt that consumers would not pay the high price for this limited system and abandoned the project.

Next, Microsoft embarked on Pulsar. It was designed to be a super pager: a wireless product with a very small screen and no keyboard—just a few buttons. Microsoft hoped the simplicity of the device would interest consumers who had never even used a computer before. Again, Microsoft's research told them that the world was not ready for such a device and Pulsar was also scrapped.

At this point, Microsoft went back to the drawing board and came up with something totally new: Pegasus. What makes the Pegasus project different from WinPad and Pulsar? Microsoft reduced its intended consumer base and defined a product to meet their needs. Pegasus can be a standalone device, but this is not how Microsoft intends it to be used. Pegasus is a companion device that will most likely be used with a Windows 95- or Windows NT¨-based desktop machine. As of mid-1996, it is not possible to produce a full-featured computer small enough to fit in the palm of your hand that costs around $500. This means the Pegasus audience is restricted mainly to Windows users—not everyone in the world who uses a Day-Timer or some other paper information manager. In fact, the two most important features of Pegasus are that it looks and feels like Windows and that it connects very well with a Windows-based desktop machine. I'll discuss these features in more detail shortly. Let's first look at the actual Pegasus hardware platform.

The Pegasus Hardware Platform

The Pegasus project consists of two parts: hardware and software. Because Microsoft does not want to get into the hardware business (for the moment let's forget that they make mice, keyboards, and joysticks), they signed up six partners (Casio, Compaq, HP, LG Electronics, NEC, and Philips) to create the hardware based on a reference platform defined by Microsoft.

A Pegasus machine is guaranteed to have an embedded keyboard, including alphanumeric keys, standard punctuation keys, a Control key, an Alt key, and two Shift keys. Infrequently used keys like Insert, Pause, Scroll Lock, Print Screen, function keys, and the new Windows Start key are optional. (Note that some international versions of Pegasus, like Japanese and Chinese, may not have keyboards due to the complexity of the character set. These versions will use handwriting recognition as their main source of input. Also, since Pegasus is going to be marketed worldwide, all Pegasus machines use Unicode.) Pegasus will also have an embedded touch screen (480 ´ 240 pixels, 4 gray-scales, 2 bits-per-pixel) and a stylus that acts like a mouse when tapped on the touch screen. A docking cradle will recharge the machine's batteries and connect the Pegasus to your desktop machine (more on this later). It must feel like it can be worn on the body rather than being lugged around, so the device must not exceed 7.0" ´ 4.0" ´ 1.0" to easily fit into a shirt pocket or an inside jacket pocket. The Pegasus will include one PCMCIA slot, one serial connector, one infrared port (IrDA), at least 2MB of RAM for the file system and running applications, and 4MB of ROM.

The Pegasus Operating System

Pegasus introduces a new operating system from Microsoft that is super lightweight. The good news is that the Pegasus OS is a Win32¨ OS, which means that you already know how to develop software for it. The bad news is that this new kernel's functions have many little nuances and implementation details that are yet to be discovered by poor unsuspecting souls like you and me. To keep the kernel small, many of the Win32 functions are simply not implemented; most of the small implementation details will be discovering that the function you want to call just doesn't exist.

While this lightweight kernel is making its debut in Pegasus, it is not specific to Pegasus. Microsoft intends to incorporate this kernel into other devices. In the not-too-distant future you can expect to see this lightweight kernel used for the global positioning system in your automobile, in your television set, and in other household appliances. The software opportunities are enormous.

Since memory is limited, the Pegasus OS is small. It requires about 150KB of ROM and about 400KB of RAM to run. The system is also portable. Currently, versions exist for the Hitachi SH3, MIPS, and x86 processors. Since each of these processors use different instruction sets, Pegasus app developers will need to produce binary images for each of these processors. The Pegasus SDK does this for you—see the sidebar for more information on the Pegasus SDK.

The Pegasus Shell and User Interface

Figure 1 shows the Pegasus desktop. As you can see, there is a striking resemblance to Windows 95 and Windows NT 4.0. The shell includes the desktop, the taskbar, and a recycle bin. The taskbar is always visible and is the quickest way for the user to switch from one application to another. A nice feature of the Pegasus taskbar is the ability to minimize an active window by clicking on its button in the taskbar. The Start button offers the same features as seen on Windows NT and Windows 95. One big difference is that Pegasus does not support cascading menus; menu options that normally display a hierarchical menu now open a window that allows the user to go to the next level. The taskbar also supports those little icons, which are used quite frequently to notify the user of various events.

Figure 1 Pegasus desktop.

Pegasus does support shell links, but the normal way of creating and interacting with them using the IShellLink COM interface is not supported because Pegasus does not currently support COM. Instead, Pegasus offers two new functions, SHCreateShortcut (which creates a shortcut) and SHGetShortcutTarget (which returns the thing that the shortcut refers to).

You can use Explorer to locate files, drag and drop files, and execute applications. From the Start menu you can start applications, work on recently used documents, get help, visit the Control Panel, and suspend the machine. Programmers can write Control Panel applets to run under Pegasus.

Unlike Windows 95 and Windows NT, Pegasus has some limitations in its windowing subsystem. At first these limitations will probably scare you, but you must always keep in mind that the Pegasus OS is designed for a specific purpose: hand-held, low-memory, small-display devices. If you keep this in mind, these limitations will not seem so strange.

The windowing subsystem does not allow the creation of owned or topmost windows. This is because the screen is so small that it is highly unlikely a user would be able to work with multiple, overlapped windows. There is special support in the system so that the help window can be a top window since users probably want to view help and work on their app at the same time. Note that Pegasus help files are HTML files based on the HTML 2.0 standard.

For similar reasons, the system does not allow resizable windows, and most windows are always maximized. It is possible to create overlapped windows but this is strongly discouraged unless there is a strong need. For example, the calculator supports two modes of operation: a maximized mode (see Figure 2), where all the number buttons are visible, and a nonmaximized mode (see Figure 3). In the latter, the window floats and contains nothing but a number field—you must enter your calculations through the keyboard.

Figure 2 Pegasus calculator when maximized.

Figure 3 Pegasus calculator when nonmaximized.

There is no cursor support since there is no mouse. Using the stylus, the user can move directly to any location on the display. When the stylus is not near the display, there is no mouse. This means you should avoid designing an application where the cursor's shape indicates what can be done. For example, Microsoft¨ Internet Explorer 3.0 (IE 3.0) usually changes the cursor to a hand when it's over a hyperlink. This type of feedback is not possible with Pegasus. However, Pegasus does support a wait "cursor" that always appears in the middle of the user's display.

You'll also notice that windows don't have a nonclient area. This is because Pegasus considers a nonclient area a waste of the display's precious real estate. In fact, your window procedures will never get any WM_NCXXX messages. Pegasus does define a new control called a CommandBar. Figure 4 shows a CommandBar at the top of the display. The CommandBar combines a window's caption bar, menu bar, and toolbar into a single entity.

Figure 4 Pegasus CommandBar

The CommandBar is based on the ToolBar common control. You populate the control with buttons and combo boxes. You can also add a menu control to the left side of the bar and you can add adornments to the right side of the bar. The OK and Close buttons are examples of adornments. Note that the CommandBar is in the window's client area, so if you want to put stuff under the CommandBar you must either create another child window of the main window or adjust your painting to account for the height of the CommandBar. Draw to that area and you draw right over the CommandBar.

Almost all of the standard controls and common controls exist. However, some forms of the controls are not available. For instance, you cannot create a simple combo box (you know, the kind that is always dropped down). You can create owner-draw buttons, but the system does not support owner-draw list boxes or combo boxes. Static controls exist, but the frame and rectangle styles are not supported. And, while property sheets are supported, wizards aren't due to the additional screen real estate required by the Back and Next buttons. Pegasus only supports two common dialogs: File Open and File Save As. Most of the other common dialog boxes, like the color and print dialogs, don't make sense on Pegasus.

As far as GDI goes, the Pegasus OS supports only two types of device contexts. The first is a 2 bits-per-pixel grayscale, which is the resolution of the LCD display. The second is a memory DC that supports either 1 or 2 bits-per-pixel. Of course, there is no printing, palette, color support, or coordinate transforms.

Memory Architecture

The Pegasus has two types of physical memory: ROM and RAM. Out of the box, the ROM contains the Pegasus OS kernel and a set of applications such as the Explorer, a calculator, Control Panel applets, and so on. The information on the ROM is not compressed in any way, and obviously never changes. When new versions of the OS or any of the applications become available, a new ROM will be released and users can easily upgrade their machines by replacing their existing ROM with the new one.

Most Pegasus machines will ship with 2MB of RAM. By default, the RAM is divided into two 1MB sections. The first section is called the object store, which is analogous to the hard drive on your desktop PC. When the user installs a new application, the EXE and DLL files get copied to the object store. When the user saves a data file, the file is saved to the object store. (Everything in the object store appears to be on a single drive; Pegasus does not support the concept of multiple drives.) The other 1MB of RAM is system storage. The system storage is where the run-time memory needed for process heaps, thread stacks, application code, global/static variables, and virtual memory allocations comes from.

When you invoke an application, the Pegasus first looks for the executable file in the RAM object store. If the file is found, it's decompressed into the system storage and the application runs. If the executable is found on the ROM, the code does not have to be decompressed first and can actually be referenced directly from the ROM without having to load the code into the system storage. This makes the RAM usage more efficient. Of course, the dynamic parts of the application must still be loaded into RAM before the application can run.

The user can actually tell Pegasus how the RAM should be divided between the object store and the system storage. This is done using the Memory tab in the Control Panel's System applet (see Figure 5). The programmer uses the new Pegasus Get/SetSystemMemoryDivision APIs.

Figure 5 Pegasus memory Control Panel applet.

Because the first version of Pegasus does not support demand paging, the entire executable file and any required DLLs must fit entirely into the system storage before the application can run. Future versions of Pegasus will be able to decompress pages of the executable code into the system storage as required as the application runs.

File System

The portion of the RAM that the user has dedicated to the object store is where the file system can be found. For manipulating the files in this RAM you can use the standard Win32 file functions like CreateFile, ReadFile, WriteFile, CloseHandle, FindFirstFile, and FindNext–File. Obviously, the system maintains the integrity of the file system's files even when the power to the unit is off.

The directory hierarchy is similar to that of Windows 95 except that there are no drive letters. The RAM is considered to be a single volume. The \Windows directory is special because all the files on the ROM chip also appear in this directory. When you see a file in the \Windows directory, most likely that file is on the ROM chip. You can also copy files into the \Windows directory. If you place a file in the \Windows directory that has the same name as a file on the ROM, the file in RAM takes precedence and you can no longer get access to the file in ROM.

The \Windows directory is where all EXE and DLL files should be placed. This means that you must take extra precaution when naming your files. Don't create a DLL with a name like Socket.DLL because it is too likely that another company might create a file with the exact same name. Pegasus does support long filenames so take advantage of this to make your filenames unique. There is no PATH environment variable either, and no concept of a current directory, so the system always looks in the \Windows directory when trying to locate DLLs.

The entire file system is always compressed to conserve RAM. This helps increase the number of files that can be stored on the Pegasus. I have been told that the compression ratio is about 2:1. There is no way for you to turn compression off, but there should be no need to since this is completely transparent. Also, the object store is not like a FAT drive. In particular, the object store does not have cluster sizes and does not waste space when storing files in memory. It should be clear that memory is at a premium in this environment so the file system is optimized for size, not speed. The system does perform minimal caching, however.

The file system also contains the registry and databases. These objects are not visible via the Explorer. Instead, the registry and databases are maintained on the file system so they are also compressed.

Databases

A Pegasus machine will probably be used to manage personal information such as phone book entries, to-do lists, meeting schedules, and email. You can also easily imagine Pegasus-specific versions of Intuit's Quicken being developed so you can track every penny you spend while you spend it. All of these applications are based on databases. When using these types of applications on the desktop and on Pegasus it would save transfer time if only new records had to be transferred between machines instead of transferring entire databases. Because this is such a common scenario for Pegasus, Microsoft has built database functionality directly into the Pegasus OS.

A database contains records, and a single record contains a set of properties. A property can be an integer, a null-terminated string, a FILETIME structure, or an array of bytes (BLOB). Each record can be up to 128KB and each property can be as large as 64KB. There is also an overhead of 32 bytes per record and 4 bytes per property. Keep in mind, all of Pegasus is Unicode, including the strings in these databases.

You assign each database a 32-character name and all databases share a single namespace. When you create a database, you get to specify up to four properties to sort on. This causes Pegasus to index the records as they're added, removed, or modified in the database. Databases are stored in the RAM used by the file system, which means that they are always compressed. However, database files are not visible when viewed using Explorer.

Several features are specific to databases. First, as I already mentioned, the database support makes it easier for you to develop applications that keep records of information. The system indexes these records automatically so you can retrieve records in an order useful to the user. Databases can be shared across processes, and the system ensures the integrity of the database records. In other words, when you write a record to the database, the system guarantees that all the properties of the record get written to the database or that none of the properties get written even if a power failure occurs while performing the transaction.

Finally, the system has built-in support for synchronizing databases. Imagine that you have an address book program's file on your desktop machine that you copy to the Pegasus. Then, while on the road, you edit the file with an app on the Pegasus. You also edit the file on the desktop machine. If you use a proprietary data format, this would cause a synchronization headache because the system can't figure out how to resolve the conflict. Your address book program must examine both files and merge the changes manually. However, when you use Pegasus databases, the system is able to merge records from the desktop and records from the Pegasus automatically, so that synchronizing the database does not require user intervention and can be done automatically. That means less code for the programmer to write.

Power Management

Since Pegasus machines will usually be used while on the road, a constant power supply is not available and batteries will have to power the device. Because battery power is so precious, the OS is constantly monitoring the system looking for ways to conserve power.

The first level of power management suspends the processor. This happens whenever all the threads are waiting for events and the user is not typing. Since this is the most common state of the machine, the processor is suspended most of the time. In fact, under normal usage, the processor is running only 5 percent of the time when the machine is on. In this mode, other peripherals like the display stay on and continue to drain power.

The second level of power management occurs when the machine is turned off. This happens when the user shuts it off or when the user is idle for some period of time (the user sets the idle period through the Control Panel). In this mode, all hardware devices including the processor, the display, and the communications devices are shut off.

Applications are not notified when the power is shut off and consequently are not offered the ability to force the machine to stay on. Applications should not care that they were suspended. Pegasus makes suspension of the machine transparent to applications. In fact, if an application first calls GetTickCount, then Pegasus is suspended for five days, then it wakes up again and the app calls GetTick-Count a second time, the difference in the two times does not include the five days during which the machine was suspended.

Device drivers, on the other hand, are notified when the system is being suspended and do get the ability to veto the suspend. This was done so that drivers receiving incoming data (from a serial port, for example) will not lose data.

Notifications

Because Pegasus is a personal information manager, it has a special set of functions for notifying the user of various events. For example, a schedule application would ask how the user wants to be notified of a scheduled reminder. The application would call the new API PegGet–UserNotificationPreferences to display a dialog box (see Figure 6) prompting the user for notification settings (see the sidebar for SDK information). Since different Pegasus hardware devices may support different notification mechanisms, the contents of this dialog box will vary depending on the device. Typical notifications are to flash an LED, play a sound, or display a message box.

Figure 6 Pegasus notification options dialog.

After the user has selected the desired notification options, PegSetUserNotificationPreferences would be called to register the event and its time with the system. When the system detects that the time matches that of the event, the system places an icon on the taskbar. When the user clicks on the taskbar's icon, the system spawns another instance of the application that registered the event. This instance then calls PegHandleAppNotifications, which removes the icon from the taskbar. Then the application can show the user whatever it desires. A schedule application would show the name of the meeting and its location in a window. The cool thing about all of this is that the system keeps track of the registered events and their times even when the power to the unit is off. This is possible due to special hardware in the Pegasus platform that will wake up the machine when the internal clock reaches its specified time.

Pegasus also supports the ability to run an application when certain system events occur. For example, you can tell the system to run an application whenever the system boots, when an external power supply is connected or disconnected, when data synchronization ends, when a network connection is made or disconnected, when the PCMCIA device changes, when an infrared device is found, or when an RS-232 connection is made or disconnected. It is also possible to tell the system to run an application at a specific time.

Communications and Connectivity

An important feature of Pegasus is its ability to connect and interoperate with Windows 95 and Windows NT-based desktop machines. To talk to the outside world, a Pegasus machine is guaranteed to have built-in serial and infrared ports. The machine can also communicate using other PCMCIA devices such as modems or flash-RAM cards.

Rather than producing some proprietary communication protocol, the Pegasus team added TCP/IP and PPP protocol stacks that sit under a sockets layer. This means sockets programmers already know how to develop communications software for Pegasus. It also means server software will not need any modifications to work with a Pegasus client. For sending and receiving data over the serial port you can use sockets or the normal Win32 functions such as CreateFile, ReadFile, WriteFile, CloseHandle, and other serial-specific functions like ClearCommBreak and WaitCommEvent.

In addition, Microsoft added subsets of the TAPI, Unimodem, and RAS APIs so users can create dial-up connections and developers don't have to write the difficult code needed to establish connections. Because of all this connectivity support, a Pegasus machine makes a competent Internet PC. In fact, Microsoft has an HTML 2.0-compatible Internet Explorer available for Pegasus. Of course, browsing the Internet is limited by the small LCD display, so you'll probably not want to browse the net for hours on end.

This connectivity support is provided so users can do most of their work on desktop machines and then transfer the documents required for travel-computing to the Pegasus. The Pegasus machine is best used as a document viewer and for making small changes to documents. Of course, if you do make changes to any documents you'll want to be able to transfer these files back to your desktop machine.

Ideally, the way to transfer files from the desktop to the Pegasus machine would be to simply connect the Pegasus up to your network and copy the files using the Explorer. Unfortunately, Pegasus currently does not come with any network redirectors. Microsoft does provide an application called Pegasus Manager (see Figure 7) that offers the same look and feel as the Explorer. The Pegasus Manager allows users, via a serial cable included with the Pegasus, to drag and drop files between Pegasus and the desktop and allows you to change a file's properties on the Pegasus. It also allows for browsing, backup and restore operations, and database synchronization.

Figure 7 Pegasus Manager

When you design a Pegasus application, you can customize the Pegasus Manager using standard shell extensions. For example, you can register your own icons and context menus for files residing on the Pegasus machine.

The Pegasus Manager also supports a file-filter extension. File filters are DLLs that load into the Pegasus Manager when the user transfers a file from the desktop to the Pegasus or vice versa. A file filter performs data conversion during the transfer. For example, Pegasus comes with a file filter that converts color bitmap/icon files to 2 bits-per-pixel bitmap/icon files when they are copied to the Pegasus device. There are also filters for Pocket Word and Pocket Excel (both applications ship with Pegasus), which convert these file types.

Remote APIs

For most applications, you do not want to simply port your desktop application to run on Pegasus. Pegasus machines will be used differently than desktop machines. You should create your full-fledged desktop application, then also create a Pegasus companion application, which will probably be much smaller in size and will not support your application's full feature set. Users will do most of their work using the desktop machine and then copy the data from the desktop to the Pegasus.

To make communication between the desktop machine and the Pegasus machine easy, Microsoft has added a number of remote APIs (RAPI) that are available to applications running on the desktop. The RAPI functions fall into various categories:

Using these functions could not be simpler. All you have to do is initialize the RAPI service in your desktop application, call the various functions that perform the work on the Pegasus machine, and then uninitialize the RAPI service. For example, if you want to copy a file from the desktop to the Pegasus, you can simply do the following:


 // Initialize the RAPI subsystem
PegRapiInit();

// Same arguments as Win32's CopyFile
// Note that destination (Pegasus machine) has no drive // letter on the filename
PegCopyFile("C:\\Readme.Txt", "\\ReadMe.txt", FALSE);
// We're finished using the RAPI subsystem PegRapiUninit();

What's Missing?

Obviously, if you are implementing an operating system to fit on a machine with severe memory and disk restrictions, you must compromise on several features. For this reason there are some big services missing from the Pegasus OS.

First and foremost, Pegasus OS currently does not support OLE, COM, ActiveXª, MAPI, ODBC, DDE, or multimedia (except playing WAV files). The runtime for these services is simply too big to fit in the machine. DirectXª is not supported, but is likely to be added in the near future; Microsoft strongly believes that Pegasus would make an excellent game machine. Currently there is no printing support, which at first might not seem like such a horrible omission. If the Pegasus OS did support printing, you'd be able to fax documents from the Pegasus—a very cool feature indeed.

I haven't said too much about how you'd go about developing software for Pegasus. I will try to cover this in a future article. Be aware that Pegasus OS does not currently support hooks. This means that you cannot use MFC and Visual Basic¨. Console applications are not supported either, so you cannot create Win32 console applications and you cannot use the C runtime's console I/O functions like printf. Finally, the Pegasus OS cannot run 16-bit MS DOS or Windows-based applications at all.

Future

If you let your imagination go, the possibilities of a Pegasus device are incredible. I can foresee whole new genres of software. For example, a golfing or bowling application that keeps your statistics; a travel-expense application that keeps your expenses up-to-date and faxes them back to the office; travel itinerary applications that let you know what sites/restaurants there are—the list goes on and on.

WHAT YOU NEED TO KNOW TO WRITE PEGASUS APPS

Michelle Votava

If you are interested in developing applications for Pegasus you will need the Pegasus SDK and tools. A cross-development add-on package for use with Visual C++¨ will be available early next year. MSDN members will receive the Pegasus Emulation SDK (for building source-compatible Pegasus applications on the desktop) early next year. Developers interested in getting an early start on developing applications for Pegasus may join the Pegasus Technical Beta Program. This beta program includes beta versions of the tools, the SDK, the DDK, developer support, and an invitation to enroll in a hardware preview program (access to beta hardware from Pegasus OEMs at a reasonable fee). For information about joining the Pegasus Technical Beta Program, email pegdvlpr@microsoft.com.

Pegasus Development Environment

Developing applications for Pegasus is similar to building applications for Windows 95 and Windows NT using C/C++ and Win32. There are two main differences.

First, Win32 for Pegasus is mostly a pure subset of Win32. Many of the basic User, GDI, and Kernel functions are present and work similarly to their Windows counterparts. There are some functions missing (such as the security API, MAPI, ODBC, OLE, and DirectX) and there are some new Pegasus-only functions to support Pegasus-specific features in the OS (the object store database API, shell notification, SMTP transport, and so on).

Second, Pegasus application development is performed in a cross-platform environment where edit, compile, link, resource edit, and debug functions occur on a Windows-based desktop computer. The resulting executables, DLLs, and other data files are transferred to a Pegasus device using a direct serial cable connection. Desktop development will be supported on Windows NT 4.0 and, possibly, Windows 95.

Pegasus Emulation

The Pegasus Emulation SDK provides an environment for building applications for Pegasus on the desktop computer using standard Win32 DLLs and libraries. It includes a restricted header file set, DLLs and libs for Pegasus-specific features, many Pegasus-specific samples, and a Pegasus shell and object store. Using only this SDK and a standard desktop compiler, a developer can build, debug, and run Pegasus apps on a desktop computer. This environment provides most of the behavior of the actual device, though performance and hardware-specific emulation characteristics are not realistic. The Pegasus development team estimates that 90 percent of Pegasus application development can be done using emulation only.

Visual C++ Cross Development Edition for Pegasus

Building Pegasus applications requires cross-compilers and other cross-platform tools developed for Pegasus. Early next year, the Visual C++ Cross Development Edition for Pegasus will be available as an add-on package for Visual C++. This package will include cross-compilers, Pegasus Win32p libraries, remote debuggers, remote tools (Spy, Zoomin, RegEdit, MemView, and pView), and all of the Emulation SDK components described above. Taking advantage of the Visual C++ installable package model, these tools are all seamlessly integrated into Visual C++, allowing edit, resource edit, compile, link, download to device, and run or debug all from within the Visual C++ integrated development environment.

Just for fun, I have included a sample program written for the Pegasus—it's the implementation of the half-page Manhattan address locator algorithm found in the NYC phone books. Figure A shows the listing of NYCAddress.c, which you will notice looks strikingly familiar to a regular Win32 program. Figure B shows the program actually running on the Pegasus. As you can see, locating a cross street based on an address in New York City is clearly not trivial, but writing a Pegasus application is easy.

Figure A NYCAddress.c


 /*****************************************************************
Module name: NYCAddress.c
Written for Win32 by:  Dave Edson
Ported to Pegasus by:  Jeffrey Richter
****************************************************************/
#ifndef STRICT
#define STRICT
#endif
#include <Windows.h>
#include <WindowsX.h>
#include "Resource.h"
////////////////////////////////////////////////////////////////////
typedef enum { AVEOP_ADD, AVEOP_SUBTRACT, AVEOP_FIFTH_AVE,
  AVEOP_SEVENTH_AVE, AVEOP_BWAY, AVEOP_CPW, AVEOP_RIVERSIDE
} AVEOP;

struct {
   LPTSTR szName;   // Avenue name
   AVEOP  aveop;    // How address on this ave should be interpreted
   int    nKeyNumber;  // Used for AVEOP_ADD / AVEOP_SUBTRACT
} Avenues[] = {
   {__TEXT("Avenue A"),            AVEOP_ADD,        3 },
   {__TEXT("Avenue B"),            AVEOP_ADD,        3 },
   {__TEXT("Avenue C"),            AVEOP_ADD,        3 },
   {__TEXT("Avenue D"),            AVEOP_ADD,        3 },
   {__TEXT("Broadway"),            AVEOP_BWAY,       0 },
   {__TEXT("1st Ave"),             AVEOP_ADD,        3 },
   {__TEXT("2nd Ave"),             AVEOP_ADD,        3 },
   {__TEXT("3rd Ave"),             AVEOP_ADD,       10 },
   {__TEXT("4th Ave"),             AVEOP_ADD,        8 },
   {__TEXT("5th Ave"),             AVEOP_FIFTH_AVE,  0 },
   {__TEXT("Ave of Americas"),     AVEOP_SUBTRACT,  12 },
   {__TEXT("7th Ave"),             AVEOP_SEVENTH_AVE,0 },
   {__TEXT("8th Ave"),             AVEOP_ADD,        9 },
   {__TEXT("9th Ave"),             AVEOP_ADD,       13 },
   {__TEXT("10th Ave"),            AVEOP_ADD,       14 },
   {__TEXT("11th Ave"),            AVEOP_ADD,       15 },
   {__TEXT("Amsterdam Ave"),       AVEOP_ADD,       59 },
   {__TEXT("Audobon Ave"),         AVEOP_ADD,      165 },
   {__TEXT("Central Park West"),   AVEOP_CPW,        0 },
   {__TEXT("Columbus Ave"),        AVEOP_ADD,       59 },
   {__TEXT("Convent Ave"),         AVEOP_ADD,      127 },
   {__TEXT("Edgecomb Ave"),        AVEOP_ADD,      134 },
   {__TEXT("Ft. Washington Ave"),  AVEOP_ADD,      158 },
   {__TEXT("Lenox Avenue"),        AVEOP_ADD,       10 },
   {__TEXT("Lexington Avenue"),    AVEOP_ADD,       28 },
   {__TEXT("Madison Avenue"),      AVEOP_ADD,       27 },
   {__TEXT("Manhattan Avenue"),    AVEOP_ADD,      100 },
   {__TEXT("Park Avenue"),         AVEOP_ADD,       34 },
   {__TEXT("Park Avenue South"),   AVEOP_ADD,        8 },
   {__TEXT("Pleasant Avenue"),     AVEOP_ADD,      101 },
   {__TEXT("Riverside"),           AVEOP_RIVERSIDE,  0 },
   {__TEXT("St. Nicholas Avenue"), AVEOP_ADD,      110 },
   {__TEXT("Wadsworth Avenue"),    AVEOP_ADD,      173 },
   {__TEXT("West End Avenue"),     AVEOP_ADD,       59 },
   {__TEXT("York Avenue"),         AVEOP_ADD,        4 }
};
////////////////////////////////////////////////////////////////////
BOOL NYCAddr_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) {  int i;
   HWND hwndAvenues = GetDlgItem(hwnd, IDC_AVENUE);
   for (i = 0; i < (sizeof(Avenues) / sizeof(Avenues[0])); i++)
      ComboBox_AddString(hwndAvenues, Avenues[i].szName);
   ComboBox_SetCurSel(hwndAvenues, 0);
   return(TRUE);
}
//////////////////////////////////////////////////////////////////
int FigureCrossStreet (int nNumber, int nAvenue) {
   int nXStreet = -1;   // Cross street
   switch (Avenues[nAvenue].aveop) {
      case AVEOP_ADD:
         nXStreet = nNumber / 20 + Avenues[nAvenue].nKeyNumber;
         break;
      case AVEOP_SUBTRACT:
         nXStreet = nNumber / 20 - Avenues[nAvenue].nKeyNumber;
         break;
    case AVEOP_FIFTH_AVE:
         if      (nNumber <=  108) nXStreet = nNumber / 20 + 11;
         else if (nNumber <=  200) nXStreet = nNumber / 20 + 13;
         else if (nNumber <=  400) nXStreet = nNumber / 20 + 16;
         else if (nNumber <=  600) nXStreet = nNumber / 20 + 18;
         else if (nNumber <=  775) nXStreet = nNumber / 20 + 20;
         else if (nNumber <= 1286) nXStreet = nNumber / 10 - 18;
         else if (nNumber <= 1494) 
            nXStreet = nNumber / 10 - 20 - (nNumber - 1310) / 20;
         break;
    case AVEOP_SEVENTH_AVE:
         if (nNumber <=  1800) nXStreet = nNumber / 20 + 12;
         else nXStreet = nNumber / 20 + 20;
         break;
    case AVEOP_BWAY:
        if (nNumber <=  754) ;
        else if (nNumber <=  846) nXStreet = nNumber / 20 - 29;
        else if (nNumber <=  953) nXStreet = nNumber / 20 - 25;
        else nXStreet = nNumber / 20 - 31;
        break;
    case AVEOP_CPW:
        nXStreet = nNumber / 10 + 60;
        break;
    case AVEOP_RIVERSIDE:
        if (nNumber <=  567) nXStreet = nNumber / 10 + 72;
        else nXStreet = nNumber / 10 + 78;
        break;
   }
   return(nXStreet);
}

//////////////////////////////////////////////////////////////////
void NYCAddr_OnCommand(HWND hwnd, int id, HWND hwndCtl, 
                       UINT codeNotify) {
   int   nNumber;
   int   nAvenue;
   int   nXStreet;
   BOOL  fTranslated;
   TCHAR szAnswer[128];
   switch (id) {
      case IDOK:
         nNumber = GetDlgItemInt(hwnd, IDC_NUMBER, &fTranslated,
                                 FALSE);
         nAvenue = ComboBox_GetCurSel(GetDlgItem(hwnd, IDC_AVENUE));
         nXStreet = FigureCrossStreet(nNumber, nAvenue);
         if (-1 != nXStreet) {
            wsprintf(szAnswer, 
               __TEXT("The nearest cross-street for %d %s is")
               __TEXT("approximately Street #%d"),
               nNumber, Avenues[nAvenue].szName, nXStreet);
         } else
            wsprintf(szAnswer, __TEXT("Can't calculate cross
                                      street"));
         SetDlgItemText(hwnd, IDC_CROSSSTREET, szAnswer);
         break;
      case IDCANCEL:  
         EndDialog(hwnd, 0); 
         break;
   }
}
/////////////////////////////////////////////////////////////////
// Normal HANDLE_MSG macro in WINDOWSX.H doesn't work properly for
// dialog boxes because DlgProcs return BOOL instead of LRESULT
//(like WndProcs). This chHANDLE_DLGMSG macro corrects the problem:
#define chHANDLE_DLGMSG(hwnd, message, fn)  \
   case (message): return (SetDlgMsgResult(hwnd, uMsg,  \
      HANDLE_##message((hwnd), (wParam), (lParam), (fn))))

//////////////////////////////////////////////////////////////////
BOOL WINAPI NYCAddr_DlgProc(HWND hwnd, UINT uMsg, 
   WPARAM wParam, LPARAM lParam) {
    switch(uMsg) {
      chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, NYCAddr_OnInitDialog);
      chHANDLE_DLGMSG(hwnd, WM_COMMAND,    NYCAddr_OnCommand);
   }
   return(FALSE);
}

//////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE hinstExePrev,
#ifdef TARGET_NT
    LPSTR pszCmdLine,
#else
    LPWSTR pszCmdLine,
#endif
   int nCmdShow) {
   return(DialogBox(hinstExe, MAKEINTRESOURCE(IDD_NYCADDRESS), 
      NULL, NYCAddr_DlgProc));
} ///////////////////////////// End of File ////////////////////

Figure B NYCAddress

This article is reproduced from Microsoft Systems Journal. Copyright © 1995 by Miller Freeman, Inc. All rights are reserved. No part of this article may be reproduced in any fashion (except in brief quotations used in critical articles and reviews) without the prior consent of Miller Freeman.

To contact Miller Freeman regarding subscription information, call (800) 666-1084 in the U.S., or (303) 447-9330 in all other countries. For other inquiries, call (415) 358-9500.