Programming Microsoft Windows Ce Net 3Rd [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Programming Microsoft Windows Ce Net 3Rd [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید






The Registry

The registry is a system database used to store configuration information in applications and in Windows itself. The registry as defined by Windows CE is similar but not identical in function and format to the registries under other versions of Windows. In other words, for an application, most of the same registry access functions exist, but the layout of the Windows CE registry doesn't exactly follow Windows XP.

As in all versions of Windows, the registry is made up of keys and values. Keys can contain keys or values or both. Values contain data in one of a number of predefined formats. Since keys can contain keys, the registry is distinctly hierarchical. The highest-level keys, the root keys, are specified by their predefined numeric constants. Keys below the root keys and values are identified by their text name. Multiple levels of keys can be specified in one text string by separating the keys with a backslash (\).

To query or modify a value, the key containing the value must first be opened, the value queried or written, and then the key closed. Keys and values can also be enumerated so that an application can determine what a specific key contains. Data in the registry can be stored in a number of different predefined data types. Among the available data types are strings, 32-bit numbers, and free-form binary data.


Registry Organization


The Windows CE registry supports three of the high-level, root, keys seen on other Windows platforms: HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, and HKEY_CLASSES_ROOT. As with other Windows platforms, Windows CE uses the HKEY_LOCAL_MACHINE key to store hardware and driver configuration data, HKEY_CURRENT_USER to store user-specific configuration data, and the HKEY_CLASSES_ROOT key to store file type matching and OLE configuration data.

As a practical matter, the registry is used by applications and drivers to store state information that needs to be saved across invocations. Applications typically store their current state when they are requested to close and then restore this state when they are launched again. The traditional location for storing data in the registry by an application is obtained by means of the following structure:

{ROOT_KEY}\Software\{Company Name}\{Company Product}

In this template, ROOT_KEY is either HKEY_LOCAL_MACHINE for machine-specific data, such as what optional components of an application can be installed on the machine, or HKEY_CURRENT_USER for user-specific information, such as the list of the user's last-opened files. Under the Software key, the name of the company that wrote the application is used followed by the name of the specific application. For example, Microsoft saves the configuration information for Pocket Word under the key

HKEY_LOCAL_MACHINE\Software\Microsoft\Pocket Word

While this hierarchy is great for segregating registry values from different applications from one another, it's best not to create too deep a set of keys. Because of the way the registry is designed, it takes less memory to store a value than it does a key. Because of this, you should design your registry storage so that it uses fewer keys and more values. To optimize even further, it's more efficient to store more information in one value than to have the same information stored across a number of values.

The window in Figure 8-1 shows the hierarchy of keys used to store data for Pocket Word. The left pane shows the hierarchy of keys down to the Settings key under the Pocket Word key. In the Settings key, three values are stored: Wrap To Window, Vertical Scrollbar Visibility, and Horizontal Scrollbar Visibility. In this case, these values are DWORD values, but they could have been strings or other data types.


Figure 8-1: The hierarchy of registry values stored by Pocket Word


The Registry API


Now let's turn toward the Windows CE registry API. In general, the registry API provides all the functions necessary to read and write data in the registry as well as enumerate the keys and data store within. Windows CE doesn't support the security features of the registry that are supported under Windows XP. However, Windows CE does prohibit untrusted applications from modifying certain critical registry keys.

Opening and Creating Keys


You open a registry key with a call to this function:

LONG RegOpenKeyEx (HKEY hKey, LPCWSTR lpszSubKey, DWORD ulOptions, 
REGSAM samDesired, PHKEY phkResult);

The first parameter is the key that contains the second parameter, the subkey. This first key must be either one of the root key constants or a previously opened key. The subkey to open is specified as a text string that contains the key to open. This subkey string can contain multiple levels of subkeys as long as each subkey is separated by a backslash. For example, to open the subkey HKEY_LOCAL_MACHINE\Software\Microsoft\Pocket Word, an application could either call RegOpenKeyEx with HKEY_LOCAL_MACHINE as the key and Software\Microsoft\Pocket Word as the subkey or open the Software\Microsoft key and then make a call with that opened handle to RegOpenKeyEx, specifying the subkey Pocket Word. Key and value names aren't case specific.

Windows CE ignores the ulOptions and samDesired parameters. To remain compatible with future versions of the operating system that might use security features, these parameters should be set to 0 for ulOptions and NULL for samDesired. The phkResult parameter should point to a variable that will receive the handle to the opened key. The function, if successful, returns a value of ERROR_SUCCESS and an error code if it fails.

Another method for opening a key is

LONG RegCreateKeyEx (HKEY hKey, LPCWSTR lpszSubKey, DWORD Reserved, 
LPWSTR lpszClass, DWORD dwOptions,
REGSAM samDesired,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
PHKEY phkResult, LPDWORD lpdwDisposition);

The difference between RegCreateKeyEx and RegOpenKeyEx, aside from the extra parameters, is that RegCreateKeyEx creates the key if it didn't exist before the call. The first two parameters, the key handle and the subkey name, are the same as in RegOpenKeyEx. The Reserved parameter should be set to 0. The lpClass parameter points to a string that contains the class name of the key if it's to be created. This parameter can be set to NULL if no class name needs to be specified. The dwOptions and samDesired and lpSecurityAttributes parameters should be set to 0, NULL, and NULL respectively. The phkResult parameter points to the variable that receives the handle to the opened or newly created key. The lpdwDisposition parameter points to a variable that's set to indicate whether the key was opened or created by the call.

Reading Registry Values


You can query registry values by first opening the key containing the values of interest and calling this function:

LONG RegQueryValueEx (HKEY hKey, LPCWSTR lpszValueName, 
LPDWORD lpReserved, LPDWORD lpType,
LPBYTE lpData, LPDWORD lpcbData);

The hKey parameter is the handle of the key opened by RegCreateKeyEx or RegOpenKeyEx. The lpszValueName parameter is the name of the value that's being queried. The lpType parameter is a pointer to a variable that receives the variable type. The lpData parameter points to the buffer to receive the data, while the lpcbData parameter points to a variable that receives the size of the data. If RegQueryValueEx is called with the lpData parameter equal to NULL, Windows returns the size of the data but doesn't return the data itself. This allows applications to first query the size and type of the data before actually receiving it.

Writing Registry Values


You set a registry value by calling

LONG RegSetValueEx (HKEY hKey, LPCWSTR lpszValueName, DWORD Reserved, 
DWORD dwType, const BYTE *lpData, DWORD cbData);

The parameters here are fairly obvious: the handle to the open key followed by the name of the value to set. The function also requires that you pass the type of data, the data itself, and the size of the data. The data type parameter is simply a labeling aid for the application that eventually reads the data. Data in the registry is stored in a binary format and returned in that same format. Specifying a different type has no effect on how the data is stored in the registry or how it's returned to the application. However, given the availability of third-party registry editors, you should make every effort to specify the appropriate data type in the registry.

The data types can be one of the following:



REG_SZ A zero-terminated Unicode string



REG_EXPAND_SZ A zero-terminated Unicode string with embedded environment variables



REG_MULTI_SZ A series of zero-terminated Unicode strings terminated by two zero characters



REG_DWORD A 4-byte binary value



REG_BINARY Free-form binary data



REG_DWORD_BIG_ENDIAN A DWORD value stored in big-endian format



REG_DWORD_LITTLE_ENDIANEquivalent to REG_DWORD



REG_LINKA Unicode symbolic link



REG_NONENo defined type



REG_RESOURCE_LISTA device driver resource list



Deleting Keys and Values


You delete a registry key by calling

LONG RegDeleteKey (HKEY hKey, LPCWSTR lpszSubKey);

The parameters are the handle to the open key and the name of the subkey you plan to delete. For the deletion to be successful, the key must not be currently open. You can delete a value by calling

LONG RegDeleteValue (HKEY hKey, LPCWSTR lpszValueName);

You can glean a wealth of information about a key by calling this function:

LONG RegQueryInfoKey (HKEY hKey, LPWSTR lpszClass, LPDWORD lpcchClass,
LPDWORD lpReserved, LPDWORD lpcSubKeys,
LPDWORD lpcchMaxSubKeyLen,
LPDWORD lpcchMaxClassLen,
LPDWORD lpcValues, LPDWORD lpcchMaxValueNameLen,
LPDWORD lpcbMaxValueData,
LPDWORD lpcbSecurityDescriptor,
PFILETIME lpftLastWriteTime);

The only input parameter to this function is the handle to a key. The function returns the class of the key, if any, as well as the maximum lengths of the subkeys and values under the key. The last two parameters, the security attributes and the last write time, are unsupported under Windows CE and should be set to NULL.

Closing Keys


You close a registry key by calling

LONG RegCloseKey (HKEY hKey);

When a registry key is closed, Windows CE flushes any unwritten key data to the registry before returning from the call.

Enumerating Registry Keys


In some instances, you'll find it helpful to be able to query a key to see what subkeys and values it contains. You accomplish this with two different functions: one to query the subkeys, another to query the values. The first function

LONG RegEnumKeyEx (HKEY hKey, DWORD dwIndex, LPWSTR lpszName,
LPDWORD lpcchName, LPDWORD lpReserved,
LPWSTR lpszClass,
LPDWORD lpcchClass, PFILETIME lpftLastWriteTime);

enumerates the subkeys of a registry key through repeated calls. The parameters to pass the function are the handle of the opened key and an index value. To enumerate the first subkey, the dwIndex parameter should be 0. For each subsequent call to RegEnumKeyEx, dwIndex should be incremented to get the next subkey. When there are no more subkeys to be enumerated, RegEnumKeyEx returns ERROR_NO_MORE_ITEMS.

For each call to RegEnumKeyEx, the function returns the name of the subkey and its classname. The last write time parameter isn't supported under Windows CE.

Values within a key can be enumerated with a call to this function:

LONG RegEnumValue (HKEY hKey, DWORD dwIndex, LPWSTR lpszValueName, 
LPDWORD lpcchValueName, LPDWORD lpReserved,
LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);

Like RegEnumKey, this function is called repeatedly, passing index values to enumerate the different values stored under the key. When the function returns ERROR_NO_MORE_ITEMS, no more values are under the key. RegEnumValue returns the name of the values and the data stored in each value, as well as its data type and the size of the data.


The RegView Example Program


The following program is a registry viewer application. It allows a user to navigate the trees in the registry and examine the contents of the data stored. Unlike RegEdit, which is provided by Windows XP, RegView doesn't let you edit the registry. However, such an extension wouldn't be difficult to make. Listing 8-2 contains the code for the RegView program.

Listing 8-2: The RegView program







RegView.rc
//======================================================================
// Resource file
//
// Copyright (C) 2003 Douglas Boling
//======================================================================
#include "windows.h"
#include "regview.h" // Program-specific stuff
//----------------------------------------------------------------------
// Icons and bitmaps
//
ID_ICON ICON "regview.ico" // Program icon
ID_BMPS BITMAP "TVBmps.bmp"
//----------------------------------------------------------------------
// Menu
//
ID_MENU MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", IDM_EXIT
END
POPUP "&Help"
BEGIN
MENUITEM "&About...", IDM_ABOUT
END
END
//----------------------------------------------------------------------
// About box dialog template
//
aboutbox DIALOG discardable 10, 10, 135, 40
STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_CENTER |
DS_MODALFRAME
CAPTION "About"
BEGIN
ICON ID_ICON, -1, 3, 5, 10, 10
LTEXT "RegView - Written for the book Programming Windows CE Copyright 2003 Douglas Boling"
-1, 30, 5, 102, 33
END


RegView.h
//======================================================================
// Header file
//
// Written for the book Programming Windows CE
// Copyright (C) 2003 Douglas Boling
//======================================================================
// Returns number of elements
#define dim(x) (sizeof(x) / sizeof(x[0]))
//----------------------------------------------------------------------
// Generic defines and data types
//
struct decodeUINT { // Structure associates
UINT Code; // messages
// with a function.
LRESULT (*Fxn)(HWND, UINT, WPARAM, LPARAM);
};
struct decodeCMD { // Structure associates
UINT Code; // control IDs with a
LRESULT (*Fxn)(HWND, WORD, HWND, WORD); // function.
};
struct decodeNotify { // Structure associates
UINT Code; // control IDs with a
LRESULT (*Fxn)(HWND, UINT, HWND, LPNMHDR); // notify handler.
};
//----------------------------------------------------------------------
// Generic defines used by application
#define ID_ICON 1 // App icon resource ID
#define ID_BMPS 2 // Bitmap resource ID
#define IDC_CMDBAR 10 // Command band ID
#define ID_MENU 11 // Main menu resource ID
#define ID_TREEV 12 // Tree view control ID
#define ID_LISTV 13 // List view control ID
// Menu item IDs
#define IDM_EXIT 101 // File menu
#define IDM_ABOUT 150 // Help menu
//----------------------------------------------------------------------
// Function prototypes
//
HWND InitInstance (HINSTANCE, LPWSTR, int);
int TermInstance (HINSTANCE, int);
INT EnumChildren (HWND, HTREEITEM, HKEY, LPTSTR);
DWORD CountChildren (HKEY, LPTSTR, LPTSTR);
INT EnumValues (HWND, HKEY, LPTSTR);
INT DisplayValue (HWND, INT, LPTSTR, PBYTE, DWORD, DWORD);
INT GetTree (HWND, HTREEITEM, HKEY *, TCHAR *, INT);
HTREEITEM InsertTV (HWND, HTREEITEM, TCHAR *, LPARAM, DWORD);
INT InsertLV (HWND, INT, LPTSTR, LPTSTR);
HWND CreateLV (HWND, RECT *);
HWND CreateTV (HWND, RECT *);
// Window procedures
LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);
// Message handlers
LRESULT DoCreateMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoSizeMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoNotifyMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoCommandMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoDestroyMain (HWND, UINT, WPARAM, LPARAM);
// Command functions
LPARAM DoMainCommandExit (HWND, WORD, HWND, WORD);
LPARAM DoMainCommandAbout (HWND, WORD, HWND, WORD);
// Notify functions
LPARAM DoMainNotifyListV (HWND, UINT, HWND, LPNMHDR);
LPARAM DoMainNotifyTreeV (HWND, UINT, HWND, LPNMHDR);
// Dialog procedures
BOOL CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM);


RegView.c
//======================================================================
// RegView - WinCE registry viewer
//
// Written for the book Programming Windows CE
// Copyright (C) 2003 Douglas Boling
//======================================================================
#include <windows.h> // For all that Windows stuff
#include <commctrl.h> // Command bar includes
#include <commdlg.h> // Common dialog includes
#include "RegView.h" // Program-specific stuff
//----------------------------------------------------------------------
// Global data
//
const TCHAR szAppName[] = TEXT ("RegView");
HINSTANCE hInst; // Program instance handle
INT nDivPct = 40; // Divider setting between windows
// Message dispatch table for MainWindowProc
const struct decodeUINT MainMessages[] = {
WM_CREATE, DoCreateMain,
WM_SIZE, DoSizeMain,
WM_COMMAND, DoCommandMain,
WM_NOTIFY, DoNotifyMain,
WM_DESTROY, DoDestroyMain,
};
// Command message dispatch for MainWindowProc
const struct decodeCMD MainCommandItems[] = {
IDM_EXIT, DoMainCommandExit,
IDM_ABOUT, DoMainCommandAbout,
};
// Notification message dispatch for MainWindowProc
const struct decodeNotify MainNotifyItems[] = {
ID_LISTV, DoMainNotifyListV,
ID_TREEV, DoMainNotifyTreeV,
};
//======================================================================
//
// Program entry point
//
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, int nCmdShow) {
HWND hwndMain;
MSG msg;
int rc = 0;

// Initialize this instance.
hwndMain = InitInstance (hInstance, lpCmdLine, nCmdShow);
if (hwndMain == 0)
return 0x10;
// Application message loop
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
// Instance cleanup
return TermInstance (hInstance, msg.wParam);
}
//----------------------------------------------------------------------
// InitInstance - Instance initialization
//
HWND InitInstance (HINSTANCE hInstance, LPWSTR lpCmdLine, int nCmdShow){
WNDCLASS wc;
INITCOMMONCONTROLSEX icex;
HWND hWnd;
// Save program instance handle in global variable.
hInst = hInstance;
#if defined(WIN32_PLATFORM_PSPC)
// If Pocket PC, allow only one instance of the application.
hWnd = FindWindow (szAppName, NULL);
if (hWnd) {
SetForegroundWindow ((HWND)(((DWORD)hWnd) | 0x01));
return 0;
}
#endif
// Register application main window class.
wc.style = 0; // Window style
wc.lpfnWndProc = MainWndProc; // Callback function
wc.cbClsExtra = 0; // Extra class data
wc.cbWndExtra = 0; // Extra window data
wc.hInstance = hInstance; // Owner handle
wc.hIcon = NULL, // Application icon
wc.hCursor = LoadCursor (NULL, IDC_ARROW);// Default cursor
wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wc.lpszMenuName = NULL; // Menu name
wc.lpszClassName = szAppName; // Window class name
if (RegisterClass (&wc) == 0) return 0;
// Load the command bar common control class.
icex.dwSize = sizeof (INITCOMMONCONTROLSEX);
icex.dwICC = ICC_BAR_CLASSES | ICC_TREEVIEW_CLASSES |
ICC_LISTVIEW_CLASSES;
InitCommonControlsEx (&icex);
// Create main window.
hWnd = CreateWindow (szAppName, TEXT ("RegView"), WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
// Return fail code if window not created.
if (!IsWindow (hWnd)) return 0;
// Standard show and update calls
ShowWindow (hWnd, nCmdShow);
UpdateWindow (hWnd);
return hWnd;
}
//----------------------------------------------------------------------
// TermInstance - Program cleanup
//
int TermInstance (HINSTANCE hInstance, int nDefRC) {
return nDefRC;
}
//======================================================================
// Message handling procedures for MainWindow
//----------------------------------------------------------------------
// MainWndProc - Callback function for application window
//
LRESULT CALLBACK MainWndProc (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
INT i;
//
// Search message list to see if we need to handle this
// message. If in list, call procedure.
//
for (i = 0; i < dim(MainMessages); i++) {
if (wMsg == MainMessages[i].Code)
return (*MainMessages[i].Fxn)(hWnd, wMsg, wParam, lParam);
}
return DefWindowProc (hWnd, wMsg, wParam, lParam);
}
//----------------------------------------------------------------------
// DoCreateMain - Process WM_CREATE message for window.
//
LRESULT DoCreateMain (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
HWND hwndCB, hwndChild;
RECT rect;

// Create a minimal command bar that has only a menu and an
// exit button.
hwndCB = CommandBar_Create (hInst, hWnd, IDC_CMDBAR);
// Insert the menu.
CommandBar_InsertMenubar (hwndCB, hInst, ID_MENU, 0);
// Add exit button to command bar.
CommandBar_AddAdornments (hwndCB, 0, 0);
// The position of the child windows will be set in WM_SIZE
SetRect (&rect, 0, 0, 10, 10);
// Create the tree view control
hwndChild = CreateTV (hWnd, &rect);
if (!IsWindow (hwndChild)) {
DestroyWindow (hWnd);
return 0;
}
// Create the list view control
hwndChild = CreateLV (hWnd, &rect);
// Destroy frame if window not created.
if (!IsWindow (hwndChild)) {
DestroyWindow (hWnd);
return 0;
}
// Insert the base keys.
InsertTV (hWnd, NULL, TEXT ("HKEY_CLASSES_ROOT"),
(LPARAM)HKEY_CLASSES_ROOT, 1);
InsertTV (hWnd, NULL, TEXT ("HKEY_CURRENT_USER"),
(LPARAM)HKEY_CURRENT_USER, 1);
InsertTV (hWnd, NULL, TEXT ("HKEY_LOCAL_MACHINE"),
(LPARAM)HKEY_LOCAL_MACHINE, 1);
InsertTV (hWnd, NULL, TEXT ("HKEY_USERS"),
(LPARAM)HKEY_USERS, 1);
return 0;
}
//----------------------------------------------------------------------
// DoSizeMain - Process WM_SIZE message for window.
//
LRESULT DoSizeMain (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam){
HWND hwndLV, hwndTV;
RECT rect, rectLV, rectTV;
INT nDivPos, cx, cy;
hwndTV = GetDlgItem (hWnd, ID_TREEV);
hwndLV = GetDlgItem (hWnd, ID_LISTV);
// Adjust the size of the client rect to take into account
// the command bar height.
GetClientRect (hWnd, &rect);
rect.top += CommandBar_Height (GetDlgItem (hWnd, IDC_CMDBAR));
cx = rect.right - rect.left;
cy = rect.bottom - rect.top;
// For Pocket PC, stack the windows; otherwise, they're side by side.
if (GetSystemMetrics (SM_CXSCREEN) < 480) {
nDivPos = (cy * nDivPct)/100;
SetRect (&rectTV, rect.left, rect.top, cx, nDivPos);
SetRect (&rectLV, rect.left, nDivPos + rect.top, cx, cy - nDivPos);
} else {
nDivPos = (cx * nDivPct)/100;
SetRect (&rectTV, rect.left, rect.top, nDivPos, cy);
SetRect (&rectLV, nDivPos, rect.top, cx - nDivPos, cy);
}
// The child window positions
SetWindowPos (hwndTV, NULL, rectTV.left, rectTV.top,
rectTV.right, rectTV.bottom, SWP_NOZORDER);
SetWindowPos (hwndLV, NULL, rectLV.left, rectLV.top,
rectLV.right, rectLV.bottom, SWP_NOZORDER);
return 0;
}
//----------------------------------------------------------------------
// DoCommandMain - Process WM_COMMAND message for window.
//
LRESULT DoCommandMain (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
WORD idItem, wNotifyCode;
HWND hwndCtl;
INT i;
// Parse the parameters.
idItem = (WORD) LOWORD (wParam);
wNotifyCode = (WORD) HIWORD (wParam);
hwndCtl = (HWND) lParam;
// Call routine to handle control message.
for (i = 0; i < dim(MainCommandItems); i++) {
if (idItem == MainCommandItems[i].Code)
return (*MainCommandItems[i].Fxn)(hWnd, idItem, hwndCtl,
wNotifyCode);
}
return 0;
}
//----------------------------------------------------------------------
// DoNotifyMain - Process WM_NOTIFY message for window.
//
LRESULT DoNotifyMain (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
UINT idItem;
HWND hCtl;
LPNMHDR pHdr;
INT i;
// Parse the parameters.
idItem = wParam;
pHdr = (LPNMHDR) lParam;
hCtl = pHdr->hwndFrom;
// Call routine to handle control message.
for (i = 0; i < dim(MainNotifyItems); i++) {
if (idItem == MainNotifyItems[i].Code)
return (*MainNotifyItems[i].Fxn)(hWnd, idItem, hCtl, pHdr);
}
return 0;
}
//----------------------------------------------------------------------
// DoDestroyMain - Process WM_DESTROY message for window.
//
LRESULT DoDestroyMain (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
PostQuitMessage (0);
return 0;
}
//======================================================================
// Command handler routines
//----------------------------------------------------------------------
// DoMainCommandExit - Process Program Exit command.
//
LPARAM DoMainCommandExit (HWND hWnd, WORD idItem, HWND hwndCtl,
WORD wNotifyCode) {
SendMessage (hWnd, WM_CLOSE, 0, 0);
return 0;
}
//----------------------------------------------------------------------
// DoMainCommandAbout - Process the Help | About menu command.
//
LPARAM DoMainCommandAbout(HWND hWnd, WORD idItem, HWND hwndCtl,
WORD wNotifyCode) {
// Use DialogBox to create modal dialog box.
DialogBox (hInst, TEXT ("aboutbox"), hWnd, AboutDlgProc);
return 0;
}
//======================================================================
// Notify handler routines
//----------------------------------------------------------------------
// DoMainNotifyListV - Process notify message for list view.
//
LPARAM DoMainNotifyListV (HWND hWnd, UINT idItem, HWND hwndCtl,
LPNMHDR pnmh) {
return 0;
}
//----------------------------------------------------------------------
// DoMainNotifyTreeV - Process notify message for list view.
//
LPARAM DoMainNotifyTreeV (HWND hWnd, UINT idItem, HWND hwndCtl,
LPNMHDR pnmh) {
LPNM_TREEVIEW pNotifyTV;
TCHAR szKey[256];
HKEY hRoot;
HTREEITEM hChild, hNext;
pNotifyTV = (LPNM_TREEVIEW) pnmh;
switch (pnmh->code) {
case TVN_ITEMEXPANDED:
if (pNotifyTV->action == TVE_COLLAPSE) {
// Delete the children so that on next open, they will
// be reenumerated.
hChild = TreeView_GetChild (hwndCtl,
pNotifyTV->itemNew.hItem);
while (hChild) {
hNext = TreeView_GetNextItem (hwndCtl, hChild,
TVGN_NEXT);
TreeView_DeleteItem (hwndCtl, hChild);
hChild = hNext;
}
}
break;
case TVN_SELCHANGED:
GetTree (hWnd, pNotifyTV->itemNew.hItem, &hRoot,
szKey, dim(szKey));
EnumValues (hWnd, hRoot, szKey);
break;
case TVN_ITEMEXPANDING:
if (pNotifyTV->action == TVE_EXPAND) {
GetTree (hWnd, pNotifyTV->itemNew.hItem, &hRoot,
szKey, dim(szKey));
EnumChildren (hWnd, pNotifyTV->itemNew.hItem,
hRoot, szKey);
}
break;
}
return 0;
}
//----------------------------------------------------------------------
// CreateLV - Create list view control.
//
HWND CreateLV (HWND hWnd, RECT *prect) {
HWND hwndLV;
LVCOLUMN lvc;
//
// Create report window. Size it so that it fits under
// the command bar and fills the remaining client area.
//
hwndLV = CreateWindowEx (0, WC_LISTVIEW, TEXT ("),
WS_VISIBLE | WS_CHILD | WS_VSCROLL |
WS_BORDER | LVS_REPORT,
prect->left, prect->top,
prect->right - prect->left,
prect->bottom - prect->top,
hWnd, (HMENU)ID_LISTV,
hInst, NULL);
// Add columns.
if (hwndLV) {
lvc.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT | LVCF_SUBITEM |
LVCF_ORDER;
lvc.fmt = LVCFMT_LEFT;
lvc.cx = 120;
lvc.pszText = TEXT ("Name");
lvc.iOrder = 0;
lvc.iSubItem = 0;
SendMessage (hwndLV, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc);
lvc.mask |= LVCF_SUBITEM;
lvc.pszText = TEXT ("Data");
lvc.cx = 250;
lvc.iOrder = 1;
lvc.iSubItem = 1;
SendMessage (hwndLV, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc);
}
return hwndLV;
}
//----------------------------------------------------------------------
// InitTreeView - Initialize tree view control.
//
HWND CreateTV (HWND hWnd, RECT *prect) {
HBITMAP hBmp;
HIMAGELIST himl;
HWND hwndTV;
//
// Create tree view. Size it so that it fits under
// the command bar and fills the left part of the client area.
//
hwndTV = CreateWindowEx (0, WC_TREEVIEW,
TEXT ("), WS_VISIBLE | WS_CHILD | WS_VSCROLL |
WS_BORDER | TVS_HASLINES | TVS_HASBUTTONS |
TVS_LINESATROOT, prect->left, prect->top,
prect->right, prect->bottom,
hWnd, (HMENU)ID_TREEV, hInst, NULL);
// Destroy frame if window not created.
if (!IsWindow (hwndTV))
return 0;
// Create image list control for tree view icons.
himl = ImageList_Create (16, 16, ILC_COLOR, 2, 0);
// Load first two images from one bitmap.
hBmp = LoadBitmap (hInst, MAKEINTRESOURCE (ID_BMPS));
ImageList_Add (himl, hBmp, NULL);
DeleteObject (hBmp);
TreeView_SetImageList(hwndTV, himl, TVSIL_NORMAL);
return hwndTV;
}
//----------------------------------------------------------------------
// InsertLV - Add an item to the list view control.
//
INT InsertLV (HWND hWnd, INT nItem, LPTSTR pszName, LPTSTR pszData) {
HWND hwndLV = GetDlgItem (hWnd, ID_LISTV);
LVITEM lvi;
INT rc;
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
lvi.iItem = nItem;
lvi.iSubItem = 0;
lvi.pszText = pszName;
lvi.iImage = 0;
lvi.lParam = nItem;
rc = SendMessage (hwndLV, LVM_INSERTITEM, 0, (LPARAM)&lvi);
lvi.mask = LVIF_TEXT;
lvi.iItem = nItem;
lvi.iSubItem = 1;
lvi.pszText = pszData;
rc = SendMessage (hwndLV, LVM_SETITEM, 0, (LPARAM)&lvi);
return 0;
}
//----------------------------------------------------------------------
// InsertTV - Insert item into tree view control.
//
HTREEITEM InsertTV (HWND hWnd, HTREEITEM hParent, TCHAR *pszName,
LPARAM lParam, DWORD nChildren) {
TV_INSERTSTRUCT tvis;
HWND hwndTV = GetDlgItem (hWnd, ID_TREEV);
// Initialize the insertstruct.
memset (&tvis, 0, sizeof (tvis));
tvis.hParent = hParent;
tvis.hInsertAfter = TVI_LAST;
tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_CHILDREN |
TVIF_IMAGE;
tvis.item.pszText = pszName;
tvis.item.cchTextMax = lstrlen (pszName);
tvis.item.iImage = 1;
tvis.item.iSelectedImage = 1;
tvis.item.lParam = lParam;
if (nChildren)
tvis.item.cChildren = 1;
else
tvis.item.cChildren = 0;
return TreeView_InsertItem (hwndTV, &tvis);
}
//----------------------------------------------------------------------
// GetTree - Compute the full path of the tree view item.
//
INT GetTree (HWND hWnd, HTREEITEM hItem, HKEY *pRoot, TCHAR *pszKey,
INT nMax) {
TV_ITEM tvi;
TCHAR szName[256];
HTREEITEM hParent;
HWND hwndTV = GetDlgItem (hWnd, ID_TREEV);
memset (&tvi, 0, sizeof (tvi));

hParent = TreeView_GetParent (hwndTV, hItem);
if (hParent) {
// Get the parent of the parent of the...
GetTree (hWnd, hParent, pRoot, pszKey, nMax);
// Get the name of the item.
tvi.mask = TVIF_TEXT;
tvi.hItem = hItem;
tvi.pszText = szName;
tvi.cchTextMax = dim(szName);
TreeView_GetItem (hwndTV, &tvi);
lstrcat (pszKey, TEXT ("\\"));
lstrcat (pszKey, szName);
} else {
*pszKey = TEXT ('\0');
szName[0] = TEXT ('\0');
// Get the name of the item.
tvi.mask = TVIF_TEXT | TVIF_PARAM;
tvi.hItem = hItem;
tvi.pszText = szName;
tvi.cchTextMax = dim(szName);
if (TreeView_GetItem (hwndTV, &tvi))
*pRoot = (HKEY)tvi.lParam;
else {
INT rc = GetLastError();
}
}
return 0;
}
//----------------------------------------------------------------------
// DisplayValue - Display the data, depending on the type.
//
INT DisplayValue (HWND hWnd, INT nCnt, LPTSTR pszName, PBYTE pbData,
DWORD dwDSize, DWORD dwType) {
TCHAR szData[512];
INT i, len;
switch (dwType) {
case REG_MULTI_SZ:
case REG_EXPAND_SZ:
case REG_SZ:
lstrcpy (szData, (LPTSTR)pbData);
break;
case REG_DWORD:
wsprintf (szData, TEXT ("%X"), *(int *)pbData);
break;
case REG_BINARY:
szData[0] = TEXT ('\0');
for (i = 0; i < (int)dwDSize; i++) {
len = lstrlen (szData);
wsprintf (&szData[len], TEXT ("%02X "), pbData[i]);
if (len > dim(szData) - 6)
break;
}
break;
default:
wsprintf (szData, TEXT ("Unknown type: %x"), dwType);
}
InsertLV (hWnd, nCnt, pszName, szData);
return 0;
}
//----------------------------------------------------------------------
// EnumValues - Enumerate each of the values of a key.
//
INT EnumValues (HWND hWnd, HKEY hRoot, LPTSTR pszKey) {
INT nCnt = 0, rc;
DWORD dwNSize, dwDSize, dwType;
TCHAR szName[MAX_PATH];
BYTE bData[1024];
HKEY hKey;
if (lstrlen (pszKey)) {
if (RegOpenKeyEx (hRoot, pszKey, 0, 0, &hKey) != ERROR_SUCCESS)
return 0;
} else
hKey = hRoot;
// Clean out list view.
ListView_DeleteAllItems (GetDlgItem (hWnd, ID_LISTV));
// Enumerate the values in the list view control.
nCnt = 0;
dwNSize = dim(szName);
dwDSize = dim(bData);
rc = RegEnumValue (hKey, nCnt, szName, &dwNSize,
NULL, &dwType, bData, &dwDSize);
while (rc == ERROR_SUCCESS) {
// Display the value in the list view control.
DisplayValue (hWnd, nCnt, szName, bData, dwDSize, dwType);
dwNSize = dim(szName);
dwDSize = dim(bData);
nCnt++;
rc = RegEnumValue (hKey, nCnt, szName, &dwNSize,
NULL, &dwType, bData, &dwDSize);
}
if (hKey != hRoot)
RegCloseKey (hKey);
return 1;
}
//----------------------------------------------------------------------
// CountChildren - Count the number of children of a key.
//
DWORD CountChildren (HKEY hRoot, LPTSTR pszKeyPath, LPTSTR pszKey) {
TCHAR *pEnd;
DWORD dwCnt;
HKEY hKey;
pEnd = pszKeyPath + lstrlen (pszKeyPath);
lstrcpy (pEnd, TEXT ("\\"));
lstrcat (pEnd, pszKey);
if (RegOpenKeyEx(hRoot, pszKeyPath, 0, 0, &hKey) == ERROR_SUCCESS){
RegQueryInfoKey (hKey, NULL, NULL, 0, &dwCnt, NULL, NULL, NULL,
NULL, NULL, NULL, NULL);
RegCloseKey (hKey);
}
*pEnd = TEXT ('\0');
return dwCnt;
}
//----------------------------------------------------------------------
// EnumChildren - Enumerate the child keys of a key.
//
INT EnumChildren (HWND hWnd, HTREEITEM hParent, HKEY hRoot,
LPTSTR pszKey) {
INT i = 0, rc;
DWORD dwNSize;
DWORD dwCSize;
TCHAR szName[MAX_PATH];
TCHAR szClass[256];
FILETIME ft;
DWORD nChild;
HKEY hKey;
TVITEM tvi;
// All keys but root need to be opened.
if (lstrlen (pszKey)) {
if (RegOpenKeyEx (hRoot, pszKey, 0, 0, &hKey) != ERROR_SUCCESS) {
rc = GetLastError();
return 0;
}
} else
hKey = hRoot;
dwNSize = dim(szName);
dwCSize = dim(szClass);
rc = RegEnumKeyEx (hKey, i, szName, &dwNSize, NULL,
szClass, &dwCSize, &ft);
while (rc == ERROR_SUCCESS) {
nChild = CountChildren (hRoot, pszKey, szName);
// Add key to tree view.
InsertTV (hWnd, hParent, szName, 0, nChild);
dwNSize = dim(szName);
rc = RegEnumKeyEx (hKey, ++i, szName, &dwNSize,
NULL, NULL, 0, &ft);
}
// If this wasn't the root key, close it.
if (hKey != hRoot)
RegCloseKey (hKey);
// If no children, remove expand button.
if (i == 0) {
tvi.hItem = hParent;
tvi.mask = TVIF_CHILDREN;
tvi.cChildren = 0;
TreeView_SetItem (GetDlgItem (hWnd, ID_TREEV), &tvi);
}
return i;
}
//======================================================================
// About Dialog procedure
//
BOOL CALLBACK AboutDlgProc (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
switch (wMsg) {
case WM_COMMAND:
switch (LOWORD (wParam)) {
case IDOK:
case IDCANCEL:
EndDialog (hWnd, 0);
return TRUE;
}
break;
}
return FALSE;
}











The workhorses of this program are the enumeration functions that query what keys and values are under each key. As a key is opened in the tree view control, the control sends a WM_NOTIFY message. In response, RegView enumerates the items below that key and fills the tree view with the child keys and the list view control with the values.

We've covered a fair amount of ground in this chapter. The Windows CE file system, while radically different from its predecessors under the covers, presents a standard Win32 interface to the programmer and a familiar directory structure to the user. The registry structure and interface are quite familiar to Windows programmers and should present no surprises. Now it's time to look at the other type of data that is stored in the object store, Windows CE databases. The database API is unique to Windows CE. Let's see how it works.

/ 169