Examining Remote System Status

This month, we'll continue our examination of the RAPI Demo example program. The RAPI Demo illustrates the use of a great variety of tools for monitoring CE devices from the desktop, as well as some techniques for making embedded CE systems physical and logical extensions of desktop applications. The example code for this lesson is available here. In this lesson, we learn how to remotely monitor system status.

Initializing The System Status Property Page

Let's take a look at the code that implements the System Status page of the property sheet control. In the case of RAPI Demo, we don't have to make any changes to the header file for the CSystemStatusPage class. All of our modifications are to the implementation file SystemStatusPage.cpp. The first of these modifications is the inclusion of the RAPI header.

#include <rapi.h>

The behavior of the System Status page is entirely implemented in the initialization member function, CSystemStatusPage::OnInitDialog().

The data declaration in OnInitDialog() consists almost entirely of structures that will be familiar from earlier examples. The following code illustrates the use of their members, but not exhaustively. The key thing to keep in mind about these structures is that all of their string members will be reported to your program in Unicode format. To display them in the list control, all strings must first be translated back into multibyte character set format.

Before we can use the RAPI subsystem, we must make it available to our application by calling the function CeRapiInit(). Always test the return from this call before continuing with RAPI operations. When you are finished making RAPI calls, you must uninitialize the subsystem and free its resources by calling the companion function CERapiUninit().

//Uninitialize RAPI when you are finished making RAPI calls
CERapiUninit().

You may wonder why we didn't just initialize RAPI in the constructor of the application object RapiDemoApp and uninitialize it in the destructor. In theory, this seems the sensible thing to do. However, in my experience, the RAPI connection tends to be more stable if initialization and uninitialization closely bracket your RAPI operations.

The first RAPI call we make is CeGetVersionEx(). RAPI function names and argument lists are generally the same as the CE side counterpart, except "Ce" prefixes the function name. Notice we use sprintf() to format strings to insert in the listbox m_SysStatsList. The members of the CEOSVERSIONINFO structure being displayed are all of type DWORD. Being numeric, they need no translation and can be passed as arguments to single byte string handling routines.

The next call, CeGetSystemPowerStatusEx(), queries the power status of the CE device. The members of the returned structure specify whether the system is running on AC (wall outlet) or DC (battery) power, whether or not the batteries are currently charging, and the remaining life of main and backup batteries. If the system being queried doesn't support all these status requests, it returns -1 in unsupported members. Its arguments, in the order shown, are the address of a SYSTEM_POWER_STATUS_EX structure, and a Boolean flag that instructs the function to acquire the most current information directly from the driver as opposed to using older, cached information.

Notice the use of the sprintf() format string "%x" for ACLineStatus, BatteryFlag, BatteryLifePercent, BackupBatteryFlag, and BackupBatteryLifePercent structure members. These are all single byte values. We haven't used the CE side analog of this function in previous articles, and so include the typedef of the SYSTEM_POWER_STATUS_EX structure:

Now, we get detailed information on the CE device's processor, with a call to CeGetSystemInfo(). (Several of the processor constants are omitted from the switch() code below, but they are shown in their in their entirety in the SystemStatusPage.cpp file listing.)

Finally, we uninitialize RAPI, and make a clean exit from the SystemStatusPage initialization member.

CeRapiUninit();
return TRUE;

Looking Ahead

In our next installment, we'll learn about a true workhorse of the RAPI suite, CeFindAllFiles(). This function is an important tool because it has no analog on the CE side. To create a powerful, comprehensive tool for CE file handling, working from the desktop is our best approach.

About the Author

Nancy Nicolaisen is a software engineer who has designed and implemented highly modular Windows CE products that include features such as full remote diagnostics, CE-side data compression, dynamically constructed user interface, automatic screen size detection, and entry time data validation.