The Windows CE Shell
Unlike desktop Windows, Windows CE does not have a standard user interface. Rather, the target hardware determines which user interface components are present, and the various CE devices differ dramatically in this respect. Collectively, the user interface elements are called the "shell." While the H/PC Pro and the HPC are very highly congruent with the interface of desktop Windows, the palmtop devices share little in the way of "look-and-feel" with their larger progenitors. In terms of deciding what parts of an existing Win32 application to port, the differing nature of the CE shells is the first critical evaluation you will face. Shell programming is one of those contexts in which it's worth weighing whether a thing that can be done should be done.
Some of the example code in the aritcles I've presented here on Developer.com is portable across most CE platforms, but makes the most sense on a specific class of device. Working from the premise that the ultimate aim of application programming is to provide users with the best tools, we'll want to take advantage of the strengths of various CE platforms. If there is one bit of advice I'd offer in this context, it's this: If you have to make a choice between maintaining a single, portable code base and allowing an application to evolve in ways that amplify the unique features of a given platform, choose evolution.
The Job of the CE Shell
As far as a user can tell, the CE Shell performs two basic functions: It provides a means by which to launch programs, and it provides a view of the CE file system. From the user's point of view, these two tasks are handled very differently by the smaller CE devices (the palmtops) than they are by the larger ones (HPC and HPC Pro) or by desktop Windows. The small size of the palmtop devices imposes a new, abbreviated set of user interface controls. In addition, the palmtop devices don't include a "Windows Explorer" type construct.
Put another way, users can't browse the palmtop CE file system by navigating through folders, opening files, or launching programs along the way. User file access relies exclusively on a very lightweight version of the "File Open" dialog, which is displayed by applications that give users the ability to operate on specific files. The palmtop CE platforms make the Start menu the sole tool for launching programs. For the smallest devices, this restricted access to the file system reinforces the palmtop CE bias against file- and text-oriented applications.
Porting Tip: As you consider porting to the CE Shell style of user interface, ask a few probing questions, with an eye to getting version 1.0 out quickly:
- Could you target the H/PC Pro or H/PC exclusively?
- If you target the palmtop devices, could you present the application's functionality in a single dialog box?
- Can you minimize or eliminate the need for the user to locate specific files?
In general, you can assume that Win 32 shell behaviors will port readily to the H/PC Pro family of devices, and with a few more modifications to the H/PC class of devices. In the palmtop class of targets, you will need to be much more discerning about what shell-related features you choose to port to CE.
Where the Files Are
CE "flattens" the standard Windows file system, and this flattening occurs in different degrees on different platforms. The practical impact of this is that the "special folders" (the Recycling Bin is an example of a special folder) that your application references may be in different locations than they were on the desktop. The path to the special folders also differs among CE platforms. Our first example program, FindDirs, shows how to use the shell functions to find the paths for the special folders. This job is accomplished differently on the palmtop devices than on the others. FindDirs.cpp is the main source file for an application that retrieves special folder locations on the palmtop CE devices. Following this example and its accompanying explanation, I'll show how to modify the FindDirs code so that it will work properly on HPC and HPC Pro class devices.
As with previous examples, we omit the support files in the interest of brevity. Full source for the FindDirs project can be found in accompanying files at developer.com.
Figure 5—The FindDirs Example Running on the Pocket PC Emulator
Click here for a larger image.
Examining the FindDirs Example
The rubber meets the road, so to speak, in the initialization sequence of the SpecialDirsDlgProc(). First, we get the handle to the list box and insert a title string.
hWndList = GetDlgItem(hWnd,IDC_SPECIAL_DIRS );
_stprintf( szBuff, TEXT("%s"),TEXT("Special Folders"));
ListBox_InsertString(hWndList, -1, &szBuff);
Next, we loop to fill the list box with the paths to specific special directories. Notice that we use an array of structures, iaSpecialDirs. Here is the declaration of the structures that make up this array:
typedef struct tagSDirs
The typedef for the SPECIAL_DIRS structure includes two members. The first, csidl, contains a CE-defined constant that identifies a special folder. The second, pszCSIDL, is a literal string that contains the CE constant's defined name. The possible values for the csidl values and their meanings appear in the following table. The physical directories identified by the constants may or may not be present on a given device, so it's very important to test the return from SHGetSpecialFolderLocation().
Table 5—SHGetSpecialFolderLocation() Constants For Special Folders
|Manifest Constant Identifier
||How This Folder Is Used|
||File system directory for the user's Recycle Bin. The Recycle Bin path is not in the Registry, and is marked with the hidden and system attributes to keep users from moving or deleting it.|
||This is a virtual folder. Contains Control Panel applications icons.|
||This is a virtual folder at the root of the namespace. Contains Windows Desktop shortcuts.|
||This is the actual physical directory used to store desktop file objects. It is not the same as the\Windows\Desktop folder.|
||This is a virtual folder that encapsulates the contents of the desktop "My Computer" icon. It shows everything on the local computer: storage devices, printers, and Control Panel. It may also contain mapped network drives.|
||Physical directory that contains the user's "Favorites" items.|
||This is a virtual folder. It contains fonts.|
||Physical directory that contains the Network Neighborhood objects.|
||This is a virtual folder. It represents the top level of the network hierarchy.|
||Physical directory that contains user documents.|
||This is a virtual folder. It contains installed printers.|
||Physical directory that contains the user's program groups.|
||Physical directory that contains the MRU documents.|
||Physical directory that contains Send To menu items.|
||Physical directory. The system starts any user programs stored here when the device powers on.|
||Physical directory that contains Start menu items.|
||This is a physical directory. It contains document templates.|
We test for a specific subset of the constants in this version of FindDirs. Here's the declaration and initialization of our array of SPECIAL_DIR structures, iaSpecialDirs:
SPECIAL_DIRS iaSpecialDirs =
This subset was chosen because it is likely to be implemented on a palmtop-class device. Now we loop through the array, calling SHGetSpecialFolderLocation() for each array element:
for ( i = 0; i < dim ( iaSpecialDirs ); i ++ )
rc = SHGetSpecialFolderLocation(hWnd,
iaSpecialDirs[i].csidl, &pidl );
The parameters to SHGetSpecialFolderLocation(), in the order shown, are the handle to the window that will display any message boxes or warnings required during the processing of this call, the CE-defined constant that identifies the folder for which we want a path, and the address of a pointer to an ITEMIDLIST structure. Here's how this variable, pidl, is declared at the top of the SpecialDirsDlgProc():
LPITEMIDLIST pidl = NULL;
This fragment of code is a bit deceptive and bears a little explanation. On the desktop, and on larger CE platforms, pidl is a pointer to a buffer that is allocated by the shell. To free this buffer, you need to get and use the shell's IMalloc COM interface. This isn't necessary on the palmtop CE devices because the value returned in pidl is a defined constant that you can pass to SHGetPathFromIDList() to retrieve a pathname. If the call to SHGetSpecialFolderLocation() is successful, we retrieve the pathname:
if( rc == NOERROR )
_stprintf( szBuff, TEXT(" %s "),iaSpecialDirs[i].pszCSIDL);
ListBox_InsertString(hWndList, -1, &szBuff);
SHGetPathFromIDList( pidl, &szBuff );
ListBox_InsertString(hWndList, -1, &szBuff);
Just one more thing. Note the declaration of szBuff:
Don't be tempted to save stack space by reducing the size of this buffer. In some cases, the SHGetPathFromIDList() function fills the buffer with null padding, using the entire MAX_PATH space, even though the actual pathname is only a few characters in length.
Download the source code: FindDirs.zip - 3 kb.
In the next installment, we'll see how to locate special folders on HPC and H/PC Pro devices.
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, entry time data validation.
In addition to writing for Developer.com, she has written several books including Making Win 32 Applications Mobile.
# # #