Microsoft Corporation
1999
Summary: A Palm-size PC is a compact device that utilizes the Microsoft® Windows® CE operating system. Developers can use the Microsoft Windows CE Toolkit for Visual C++® 6.0 to engineer applications for this device. Because of the physical constraints of a Palm-size PC and its intended audience, applications developed for a Palm-size PC must be quick to load, responsive to user input, and efficient in their use of system resources. (21 printed pages)
This paper discusses the process of writing applications for the Palm-size PC using the Windows CE Toolkit for Visual C++ 6.0. It introduces the Palm-size PC and the toolkit. It provides guidelines and code snippets for the following issues in designing applications for the Palm-size PC:
The Palm-size PC is a tool designed for professionals who use mobile devices. It is highly functional yet unobtrusive in size and easy to use. With a Palm-size PC, users can access their personal and business information from any location at any time. Access may be accomplished through a variety of programs. For example, with personal information manager (PIM) software, users can keep track of contacts and appointments, taking advantage of note-taking software to write down or record notes and e-mail software to send and receive messages. Files and other information stored on a Palm-size PC can be synchronized with one or more desktop systems, ensuring consistency across all points of access.
New Palm-size PCs have several enhancements, including color displays, TrueType font support, and Japanese language support. These enhancements offer developers the opportunity to elaborate existing applications and explore new areas of application development—for example, an application that takes advantage of color support, such as a computer-aided design (CAD) file viewer an engineer or architect can use to make notes on a project. Games and electronic books are other possible development projects that benefit from an enhanced display and TrueType font support.
Microsoft provides a variety of toolkits and libraries to support developers who want to engineer applications for the Palm-size PC. Using these toolkits, developers experienced with Win32® can create applications for the Palm-size PC in an integrated development environment (IDE) that is familiar, yet has been enhanced to provide the necessary functions to generate and debug Palm-size PC applications. For example, the Microsoft Windows CE Toolkit for Visual Basic 6.0 allows its users to develop applications for a Palm-size PC using a subset of the Visual Basic language and ActiveX controls. Similarly, the Microsoft® Windows® CE Toolkit for Visual C++ 6.0® gives developers the tools to develop Palm-size PC applications using Visual C++. Development may be further simplified using support libraries such as the Microsoft Foundation Classes (MFC).
Application development for the Palm-size PC using the toolkit closely parallels application development for the desktop using Visual C++ 6.0. The toolkit modifies the existing Visual C++ IDE to allow development for compact devices but maintains a user interface that is consistent with the IDE used for desktop-application development. Developers who have created desktop applications with Visual C++ 6.0 will be able to use the toolkit to produce applications for compact devices.
The toolkit consists of an integrated set of menus, tools, and toolbars that augment developers' ability to compile code for desktop emulation or to cross-compile code for the various processors that may be installed on a Palm-size PC. These processors include the MIPS or SH3 processors. The toolkit also provides the facilities to configure projects, copy Output files to the Palm-size PC, and debug applications in emulation or remotely on a Palm-size PC. To use system resources most efficiently, the toolkit supports an adaptation of the Windows-based desktop API from which extraneous functions have been removed and others replaced by functions tailored to Windows CE–based devices.
To develop applications for the Palm-size PC using the toolkit, the following software components need to be installed on the development system:
Note The Microsoft Windows NT operating system is required to support Palm-size PC emulation. Developers who do not require device emulation may use the Microsoft Windows 95 or Windows 98 operating system; however, a device emulator should be used for efficient testing and debugging. An actual target device should be used for final application testing to ensure correct application operation.
The integrated development environment of the Palm-size PC is designed so that developers who are new to the device can create highly functional applications by following some guidelines and learning a few basic techniques, some of which are described in the following sections.
Designing a user interface is an important step in all application development. Palm-size PC application development is no exception to this rule. The following user interface–related topics describe some basic considerations and offer selected examples to demonstrate design principles. Code snippets are also provided.
Following are some guidelines for tailoring an interface to the Palm-size PC.
The following screen shots illustrate these techniques by comparing the design of a blackjack option dialog box targeted for, respectively, a desktop PC and a Palm-size PC.
Figure 1. Blackjack option dialog box designed for a desktop PC
Figure 2. Blackjack option dialog box designed for a Palm-size PC
Following are some guidelines for designing controls and the input panel:
Note It is acceptable to leave static text and checkbox controls obscured by the input panel.
The following code sample shows how to detect different states of the input panel:
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
switch (msg)
{
.
.
.
// WM_SETTINGCHANGE is sent to all top-level windows whenever the
// state of the Input Panel changes. The change includes input
// method, visibility, docking, or size.
case WM_SETTINGCHANGE:
switch (wParam)
{
// Changes in the Input Panel information.
case SPI_SETSIPINFO:
// Insert code here to handle the case in which the Input
// Panel information is changed.
// ...
break;
// Changes in the current input method.
case SPI_SETCURRENTIM:
// Insert code here to handle the case in which the current
// input method is changed.
// ...
break;
.
.
.
}
break;
.
.
.
}
return 0;
}
Color depth of the screen may vary from device to device. There are two approaches to addressing this:
This requires the application to contain multiple sets of resources for varying color depths and code that detects the abilities of the device so the appropriate resources are used. This approach increases the size of the application as well as its complexity.
Choose colors for their resources that can be displayed under multiple color depths. This approach reduces complexity and the size of the application on the device but may not provide the most aesthetically pleasing display.
A developer will have to weigh the benefits and weaknesses of these two techniques and decide which is most appropriate for the given application.
Because the shell on a Palm-size PC automatically shuts down idle applications when memory is needed, you do not have to provide a manual method in an application's title bar or in its menus to exit an application. It is acceptable to utilize the shortcut key CTRL+Q.
Developers can use several features and controls that are specific to a Palm-size PC to enhance an application.
The Palm-size PC was designed for ease of use and one-handed operation. An application may utilize one or more of the hardware buttons in order to provide improved one-handed operability. An application that is mapped to one of the program launch buttons can provide special actions that are dependent on the length of time the button is pressed. For example, an application dialog can be activated on the hardware button-down event. If the button is still down one second later, the application creates a new document.
The following code sample demonstrates using hardware buttons for this effect:
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
.
.
.
// Determine if a navigational control is mapped to myprogram.exe.
if (g_byButton = SHGetAppKeyAssoc (TEXT("myprogram.exe")))
{
// Define a system-wide hot key.
g_bHotkey = RegisterHotKey (
g_hwndMain, // Window receives hot key notification
ID_HOTKEY, // Identifier of the hot key
MOD_WIN, // Either WINDOWS key was held down
g_byButton); // Virtual-key code
// Determine whether the hot key is up or down. If it is down,
// start the new document timer.
if (g_bHotkey && GetAsyncKeyState (g_byButton) < 0)
SetTimer (g_hwndMain, ID_NEWDOCTIMER, 1000, 0);
}
.
.
.
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
switch (msg)
{
.
.
.
case WM_HOTKEY:
// Kill the timer.
KillTimer (hwnd, ID_NEWDOCTIMER);
// Bring the main window foreground.
SetForegroundWindow (hwnd);
// If the button is still down, start the new document timer.
if (g_byButton != 0 && GetAsyncKeyState (g_byButton) < 0)
SetTimer (hwnd, ID_NEWDOCTIMER, 1000, 0);
break;
case WM_TIMER:
// Kill the timer.
KillTimer (hwnd, ID_NEWDOCTIMER);
// Determines whether a key is down. If it is, then create
// a new document.
if (g_byButton != 0 && (GetAsyncKeyState (g_byButton) < 0))
{
// Insert code here to create a new document.
// ...
}
break;
case WM_SETTINGCHANGE:
switch (wParam)
{
.
.
.
case SPI_APPBUTTONCHANGE:
// Determine if myprogram.exe is mapped to a button..
if (g_byButton = SHGetAppKeyAssoc (TEXT("myprogram.exe")))
{
// Define a system-wide hot key.
g_bHotkey = RegisterHotKey (g_hwndMain, ID_HOTKEY,
MOD_WIN, g_byButton);
// Determine whether the hot key is down. If it is,
// start the new document timer.
if (g_bHotkey && GetAsyncKeyState (g_byButton) < 0)
SetTimer (g_hwndMain, ID_NEWDOCTIMER, 1000, 0);
}
break;
.
.
.
}
break;
.
.
.
}
return 0;
}
Extra controls that are unique to the Palm-size PC enhance an application's ease of use. These controls are designed to provide quick help and assist users in entering information. The application must initialize these controls by calling the SHInitExtraControls function. Two such controls are the CAPEDIT control and the ToolTip control.
The CAPEDIT control works just like an Edit control but automatically capitalizes the first letter of each word entered in the control. This feature can be used to speed up the entry of information in a name field or other appropriate fields.
The following code snippet shows how to create a CAPEDIT control within a dialog box:
#define CAPEDITID 100 // Identifier of the CAPEDIT control
DWORD dwStyle; // Window style of the CAPEDIT control
HWND hwndDlg; // HWND of the dialog box
HWND hwndCapEdit; // HWND of the CAPEDIT control
int ixPos = 12, // Horizontal position of the CAPEDIT control
iyPos = 32, // Vertical position of the CAPEDIT control
iWidth = 170, // Width of the CAPEDIT control
iHeight = 20; // Height of the CAPEDIT control
// Initializes parameters for the CAPEDIT control.
if (!SHInitExtraControls ())
return 0;
// Create a dialog box.
hwndDlg = CreateDialog (g_hInst, MAKEINTRESOURCE(IDD_DLG),
g_hwndMain, DialogProc);
// Activate the dialog box and display it in its current size
// and position.
if (hwndDlg)
ShowWindow (hwndDlg, SW_SHOW);
dwStyle = ES_AUTOHSCROLL | WS_VISIBLE | WS_BORDER;
// Create a CAPEDIT control within the dialog box.
hwndCapEdit = CreateWindow (
WC_CAPEDIT, // Class name
NULL, // Window text
dwStyle, // Window style
ixPos, // x coordinate of the upper left corner
iyPos, // y coordinate of the upper left corner
iWidth, // Width of the edit control window
iHeight, // Height of the edit control window
hwndDlg, // Window handle of parent window
(HMENU) CAPEDITID, // Control identifier
g_hInst, // Instance handle
NULL); // Specify NULL for this parameter when
// creating a control
if (!hwndCapEdit)
return 0;
// Make the first letter to be capital for all words.
// If this message is not sent, only the first letter of the first word
// is capitalized.
SendMessage (hwndCapEdit, CEM_UPCASEALLWORDS, 0, 0L);
Developers familiar with Win32-based programming will know that a ToolTip adds help to an application by displaying a small rectangular window and a brief message when the mouse is placed over a control. The same mechanism is available on a Palm-size PC. A ToolTip is activated on a Palm-size PC when the stylus is held over a control for more than 0.5 seconds. If the stylus is lifted from the screen while it is still over the control, the control will be activated. If the stylus is moved away from the control, the control will not be activated. A developer can declare Palm-size PC static and button controls as ToolTip controls, TTSTATIC and TTBUTTON.
The following procedure demonstrates how to write ToolTip controls.
To develop ToolTip controls
This initializes the ToolTip. Even when using multiple ToolTip controls, call SHInitExtraControls only once.
Declare buttons, group boxes, check boxes, and radio buttons as TTBUTTON. Declare static controls as TTSTATIC. Declare all other ToolTips as standard Windows CE ToolTips.
Separate the sections with a double tilde: ~~. The text before the double tilde is the text that appears on the control. The text after the double tilde is the text that appears in the ToolTip. This text can be up to 253 characters long. If you do not add any text after the double tilde, the shell displays "No Help provided" when the user accesses the control's ToolTip. If the ToolTip is longer than the width of the screen, the ToolTip wraps to a new line. A line break may be forced by placing the \r character within the ToolTip text. However, do not use \r as a first or last character. Also, do not use \r consecutively, such as \r\r.
The following code sample shows how to add a ToolTip to a static text control, a button, and a checkbox in a control declaration of a resource file:
CONTROL "File Name:~~Name of the file to be\rcreated or opened",
IDC_STATIC,"TTSTATIC",WS_VISIBLE,7,8,56,8
CONTROL "New~~Create a new file",IDC_NEW,"TTBUTTON",
BS_PUSHBUTTON|WS_TABSTOP,7,37,50,14
CONTROL "Preview the file~~View the file properties",
IDC_PREVIEW,"TTBUTTON",BS_AUTOCHECKBOX|WS_TABSTOP,7,60,114,10
The following code sample shows how to modify ToolTips and the control text of a button control:
// Change the ToolTip text but keep the current control text.
SetWindowText (hwndBtn, TEXT("~~New ToolTip text"));
// Keep the current ToolTip text but change the control text.
SetWindowText (hwndBtn, TEXT("New Control Text"));
// Change the ToolTip text and the control text.
SetWindowText (hwndBtn, TEXT("New Control Text~~New ToolTip text"));
// Remove the ToolTip text and keep the control text.
// After this call, the ToolTip display "No Help provided".
SetWindowText (hwndBtn, TEXT("Old Control Text~~"));
Because of the memory constraints associated with a Palm-size PC, use discretion when allocating memory. The following guidelines describe a few methods of conserving memory.
Available memory is tracked automatically by the shell, which will send messages to applications in order to conserve memory. The WM_HIBERNATE message is sent to applications when system resources are becoming low. An application should respond to this message by releasing as many system resources as possible. An application can leave this state in one of two ways: through receiving a WM_ACTIVATE message or a WM_CLOSE message. If the application receives WM_ACTIVATE, it should restore its state prior to the receipt of WM_HIBERNATE. If the application receives WM_CLOSE, it should save its state for restoration on its next launch and then shut down.
The following code sample shows how to design an application to respond to WM_HIBERNATE, WM_ACTIVATE, and WM_CLOSE:
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
switch (msg)
{
.
.
.
case WM_HIBERNATE:
// The WM_HIBERNATE message is sent to an application when system
// resources are running low. An application should attempt to
// release as many resources as possible when sent this message.
// Insert code here to do this (unload dialogs, destroy windows,
// free up as much local storage as possible without killing the
// internal state.).
// ...
// The application leaves this state either by receiving a
// WM_ACTIVATE message, in which case it is the application's
// responsibility to attain the state it was in before the
// hibernate, or by getting a WM_CLOSE message, in which case
// the application will exit properly.
break;
case WM_ACTIVATE:
switch (LOWORD(wParam))
{
// The application window gets deactivated.
case WA_INACTIVE:
return DefWindowProc (hwnd, msg, wParam, lParam);
// The application window gets activated.
case WA_ACTIVE:
case WA_CLICKACTIVE:
// Insert code here to attain the state which the application
// was in before the hibernation.
// ...
break;
}
break;
case WM_CLOSE:
// Insert code here to exit properly.
// ...
break;
.
.
.
}
return 0;
}
Most of the details of a Palm-size PC's file system are hidden from the user. A user has access only to items contained within the My Documents folder and its subfolders. No application should expose other areas of the file system to a user.
Note the following important facts about the file system:
Using the GetOpenFileName and GetSaveFileName functions avoids improper exposure of the file system to the user.
To prompt the user to open a file or to choose a folder, the application should use the GetOpenFileName function. This function takes a long pointer to an OPENFILENAME structure as a parameter, which an application must first create and populate in order to use GetOpenFileName. The Flags field of OPENFILENAME will determine the type of dialog box to be displayed. An open folder dialog box will be displayed if Flags is set to the value OFN_PROJECT; otherwise, an open file dialog box will be displayed.
The return value of GetOpenFileName will indicate the user's response to the dialog box. If the return value of GetOpenFileName is not zero, the user selected a file name and chose OK. The file name and path of the chosen file will be in the buffer pointed to by the lpstrFile field of OPENFILENAME. If the return value is zero, the user canceled or closed the dialog box, or an error occurred. The GetLastError function can be used to get more information about the error.
The procedure to use the GetSaveFileName function to display a Save As dialog box is the same as the procedure for GetOpenFileName. The Flags field of OPENFILENAME will determine the type of dialog box to be displayed. A File Properties dialog box will be displayed if Flags is set to the value OFN_PROPERTY; otherwise the Save dialog box will be displayed. The return values of GetSaveFileName have the same meaning as the return values of GetOpenFileName.
The following code sample shows how to open a project, open a file, save a file, and view a file's properties.
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
TCHAR szFile[MAX_PATH] = TEXT("\0");
OPENFILENAME ofn;
memset (&ofn, 0, sizeof (ofn));
ofn.lStructSize = sizeof (OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
ofn.nMaxFile = MAX_PATH;
switch (msg)
{
.
.
.
case WM_COMMAND:
switch (GET_WM_COMMAND_ID (wParam,lParam))
{
// Open a project (Folder).
case IDM_OPENPRJ:
ofn.lpstrTitle = TEXT("Open Folder");
// Open project dialog for Palm-size PC.
ofn.Flags = OFN_PROJECT;
if (GetOpenFileName (&ofn))
{
MessageBox (hwnd, ofn.lpstrFile, TEXT("Info"), MB_OK);
// Insert code here to open a project.
// ...
}
break;
// Open a file.
case IDM_OPENFILE:
ofn.lpstrFilter = TEXT("All Files (*.*)\0*.*\0");
ofn.lpstrTitle = TEXT("Open File");
ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST;
if (GetOpenFileName (&ofn))
{
MessageBox (hwnd, ofn.lpstrFile, TEXT("Info"), MB_OK);
// Insert code here to open a file.
// ...
}
break;
// Save a file.
case IDM_SAVEFILE:
ofn.lpstrFilter = TEXT("Text Files (*.txt)\0*.txt\0");
ofn.lpstrTitle = TEXT("Save File As");
ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT |
OFN_PATHMUSTEXIST;
ofn.lpstrDefExt = TEXT("txt");
if (GetSaveFileName (&ofn))
{
MessageBox (hwnd, ofn.lpstrFile, TEXT("Info"), MB_OK);
// Insert code here to save a file.
// ...
}
break;
// View the properties of a choosen file.
case IDM_PROPERTY:
// Use GetOpenFileName to choose a file and then use
// GetSaveFileName to display its properties.
ofn.lpstrFilter = TEXT("All Files (*.*)\0*.*\0");
ofn.lpstrTitle = TEXT("File Property");
ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST;
if (GetOpenFileName (&ofn))
{
ofn.lpstrTitle = TEXT("Property");
ofn.Flags = OFN_PROPERTY;
// Open the property dialog.
GetSaveFileName (&ofn);
}
break;
default:
return DefWindowProc (hwnd, msg, wParam, lParam);
}
break;
.
.
.
}
return 0;
}
To give users a way to install an application, it is necessary to produce a cabinet (.cab) file. A .cab file contains all the necessary files in one file, ensuring that all files are present at installation time. A .cab file is generated by writing an .inf file, an .ini file, and using the CAB Wizard utility, cabwiz.exe, provided with the SDK. An .inf file consists of a number of sections that describe the target location of the files, shortcuts, and registry settings contained within the .cab file. The complete .inf file syntax is outside the scope of this article.
When writing .inf files for a Palm-size PC installation, use macro strings to represent destination directories within the .inf file. This is important because directories may have different names depending on the language into which the device has been localized.
The following table shows the available macro strings and their corresponding directory for a device intended for an English-speaking audience.
Macro String | Palm-size PC Directory |
%CE1% | \Program Files |
%CE2% | \Windows |
%CE4% | \Windows\StartUp |
%CE5% | \My Documents |
%CE6% | \Program Files\Accessories |
%CE7% | \Program Files\Communication |
%CE8% | \Program Files\Games |
%CE11% | \Windows\Start Menu\Programs |
%CE12% | \Windows\Start Menu\Programs\Accessories |
%CE13% | \Windows\Start Menu\Programs\Communications |
%CE14% | \Windows\Start Menu\Programs\Games |
%CE15% | \Windows\Fonts |
%CE17% | \Windows\Start Menu |
You must define a shortcut to the executable within the .inf file to be placed in the Start menu in order for the installed application to be executed. This is necessary because the Palm-size PC file system does not allow users to run applications by any means other than selecting them from the Start menu. For debugging purposes, applications can be placed directly into the \Windows\Start Menu directory so that they may be executed. Dynamic-link library (.dll) files must be placed in the \Windows directory.
The differences between typical applications designed for a Palm-size PC and those designed for other Win32-based platforms may present issues in moving code directly between platforms. However, since Windows CE is a Win32-based operating system, you can, in some cases, modify existing desktop application code to tailor it to the Palm-size PC.
The process of porting a desktop application to the Palm-size PC will be simplified if the desktop application was developed using APIs that are common to both platforms. The desktop user interface will probably need to be modified to suit a Palm-size PC, so it would be profitable to build a modular user interface layer.
For more information about Windows CE, see the Windows CE Web site at www.microsoft.com/windowsce/.
For more information about writing applications for Windows CE, see the following:
--------------------------------------------
The information contained in this document represents the current view of Microsoft Corporation on the issues discussed as of the date of publication. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after the date of publication. This document is for informational purposes only.
This White Paper is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, IN THIS DOCUMENT.
Microsoft, ActiveX, Visual Basic, Visual C++, Windows, and Windows NT are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.
Other product and company names mentioned herein may be the trademarks of their respective owners.