Accessing the Registry

< BACK  NEXT >
[oR]

The registry is used for storing application settings and preferences, together with device and other system settings. The registry is organized as a hierarchy of keys, and each key can contain zero, one or more values, and zero, one ormore keys. Each key can have one un-named (or default) value, and many named values. Each value has a data type, such as DWORD or Unicode string.

The Windows CE registry is accessed using the same functions as Windows NT/98/2000. However, unlike Windows 2000 and NT, the Windows CE registry does not support security on keys, and so security-related parameters in the registry access functions are ignored. You can use the Remote Registry Editor to view a device or emulator's registry from your desktop PC, or use one of the many third-party Windows CE registry editors that run on the Windows CE device itself.

The Windows CE registry has three primary, or root keys:

  • HKEY_CLASSES_ROOT Contains information on COM components and file extension associations. Known colloquially as "HCR".

  • HKEY_LOCAL_MACHINE Contains information about the configuration of the Windows CE device. Known colloquially as "HLM".

  • HKEY_CURRENT_USER Contains information about the user currently logged-on. Known colloquially as "HCU".

Generally, you should place your own data in a key under the "Software" key either in HKEY_CLASSES_MACHINE or HKEY_CURRENT_USER, depending on whether the data applies generally to the application or to a specific user running the application. The distinction between HKEY_CLASSES_MACHINE and HKEY_CURRENT_USER is not as significant as on Windows 2000 or NT, since Windows CE does not support the concept of different logged-on users.

In Windows CE the registry key names are limited to 255 characters and cannot be nested more than 16 keys deep. Further, deeply nested keys in Windows CE can affect performance.

The following sections show how to perform basic operations on registry keys, including adding keys and values, reading key values, deleting keys and values, and finally, enumerating all sub-keys and values for a particular key.

Adding and Updating Registry Keys and Values

First, let's look at creating a key in the registry, and then adding values to the key. Each key can have a default string value; zero, one, or more sub-keys; and zero, one, or more named values. Named values are typed and can be any one of the types listed in Table 4.24. Note that other data types are available but are not commonly used by applications.

Table 4.24. Common Registry value data types used by applications
Value Data type Description
REG_BINARY Binary data in any form
REG_DWORD A 32-bit number
REG_EXPAND_SZ A null-terminated string that contains unexpanded references to environment variables (for example, "%PATH%")
REG_MULTI_SZ An array of null-terminated strings, terminated by two null characters
REG_NONE No defined value type
REG_SZ A null-terminated string

The registry access code in Listing 4.20 does the following:

  • Creates or Opens a key using the function RegCreateKeyEx called HKEY_CLASSES_MACHINE\MyCompany\MyApplication

  • Calls the function RegSetValueEx to add values to the key

  • Calls the function RegCloseKey to close the key

Listing 4.20 Adds or updates registry values
 void Listing4_20() {   HKEY hKey;   DWORD dwDisp;   TCHAR szStr[200];   DWORD dwVal;   if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,       _T("Software\\MyCompany\\MyApplication"),       0, NULL, 0, 0, NULL,       &hKey, &dwDisp) != ERROR_SUCCESS)   {     // Warning! Key could have been created,     // but not opened.     cout    _T("Could not open/create key:");     return;   }   if(dwDisp == REG_CREATED_NEW_KEY)     cout    _T("Created new key")   endl;   else if(dwDisp == REG_OPENED_EXISTING_KEY)     cout   _T("Opened existing key")   endl;   wcscpy(szStr, _T("Contents of Key 'String'"));   if(RegSetValueEx(hKey, _T("StringTest"), NULL,       REG_SZ, (LPBYTE)szStr,       (wcslen(szStr) + 1) * sizeof(TCHAR))         != ERROR_SUCCESS)     cout   _T("Could not save key");   dwVal = 456;   if(RegSetValueEx(hKey, _T("DWORDTest"), NULL,       REG_DWORD, (LPBYTE)&dwVal,       sizeof(DWORD)) != ERROR_SUCCESS)     cout   _T("Could not save key");   wcscpy(szStr, _T("Default Value"));   if(RegSetValueEx(hKey, NULL, NULL, // default value       REG_SZ, (LPBYTE)szStr,       (wcslen(szStr) + 1) * sizeof(TCHAR))         != ERROR_SUCCESS)     cout   _T("Could not save key");   RegCloseKey(hKey);   return; } 

RegCreateKeyEx (Table 4.25) creates a new named key or opens an existing key. The advantage of using RegCreateKeyEx is that the function will create the key if it does not exist, or open the key if it does exist. Thus the same code can be used when the application first runs and the key does not exist, and for subsequent calls after the key has been created. Note that keys can be created under HKEY_CLASSES_MACHINE\MyCompany\MyApplication by calling RegCreateKeyEx again, passing hKey as the first parameter rather than HKEY_CLASSES_MACHINE. Don't include leading or trailing backslash characters in the key name. If you do, the key may be created but the call to RegCreateKeyEx will fail.

The function RegSetValueEx is used to add a new value to a key or, if the value already exists, to update the value. A key can have a default value which always has the REG_SZ data type. Any number of named values can be added, and these can have any of the data types described in Table 4.24.

In Listing 4.20, RegSetValueEx is called three times.

  • The first call adds or updates a REG_SZ value called "StringTest". Note that the number of bytes in the data includes the "\0" terminating character.

Table 4.25. RegCreateKeyEx Creates or opens a registry key
RegCreateKeyEx
HKEY hKey Handle to the parent key, or one of HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, or HKEY_LOCAL_MACHINE.
LPCWSTR lpszSubKey Pointer to the sub-key to open or create. The sub-key must not start with a "\" and this parameter cannot be NULL.
DWORD Reserved Set to 0.
LPWSTR lpszClass Pointer to a string that specifies the class (object) type of this key. This can be NULL. You are unlikely to use this feature in Windows CE.
DWORD dwOptions Ignored, pass as 0.
REGSAM samDesired Ignored, pass as 0.
LPSECURITY_ATTRIBUTES lpSecurityAttributes Ignored, pass as NULL.
PHKEY phkResult Pointer to an HKEY variable to receive the handle to the key.
LPDWORD lpdwDisposition Pointer to a DWORD that returns:
REG_CREATED_NEW_KEY Key did not exist, and the key was created.
REG_OPENED_EXISTING_KEY Existing key was opened.
LONG Return Result ERROR_SUCCESS on success, or error code.

Table 4.26. RegSetValueEx Adds a new value or updates an existing value
RegSetValueEx
HKEY hKey Handle to the open key where the value is to be added or updated
LPCWSTR lpValueName Name of the value, or NULL to set the default value
DWORD Reserved Reserved, pass as 0
DWORD dwType Data type of value, from Table 4.24
const BYTE *lpData Pointer to the data to be used for the value
DWORD cbData Length of the data pointed to by lpData in bytes
LONG Return Value ERROR_SUCCESS on success, or an error value

  • The second call adds or updates a REG_DWORD value called DWORDTest.

  • The third call sets or updates the default string value.

Finally, the code calls RegCloseKey to close the key. This function is passed a single parameter, the handle of the key to close.

Querying a Registry Value

When querying registry values, the key must first be opened using, for example, RegCreateKeyEx, and then the function RegQueryValueEx, called to read a specified key value. This is illustrated in Listing 4.21. The call to RegCreateKeyEx is identical to that made when creating the values in Listing 4.20.

Listing 4.21 Queries a registry value
 void Listing4_21() {   HKEY hKey;   DWORD dwDisp, dwcbData, dwType;   TCHAR szStr[200];   DWORD dwVal;   if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,       _T("Software\\MyCompany\\MyApplication"),       0, NULL, 0, 0, NULL,       &hKey, &dwDisp) != ERROR_SUCCESS)   {     cout  _T("Could not open/create key:");     return;   }   dwcbData = sizeof(szStr) * sizeof(TCHAR);   if(RegQueryValueEx(hKey, _T("StringTest"),       NULL, &dwType,       (LPBYTE)szStr, &dwcbData) != 0)     cout   _T("Could not open key")   endl;   else     cout   _T("StringTest:")   szStr   endl;   dwcbData = sizeof(DWORD);   if(RegQueryValueEx(hKey, _T("DWORDTest"),       NULL, &dwType,       (LPBYTE)&dwVal, &dwcbData) != 0)     cout   _T("Could not open key")   endl;   else     cout   _T("DWORDTest:")   dwVal   endl;   dwcbData = sizeof(szStr) * sizeof(TCHAR);   if(RegQueryValueEx(hKey, NULL,  // default value       NULL, &dwType,       (LPBYTE)szStr, &dwcbData) != 0)     cout   _T("Could not open key")   endl;   else     cout   _T("(default):")   szStr   endl;   RegCloseKey(hKey); } 

The function RegQueryValueEx (Table 4.27) is passed a pointer to a buffer and the length of the buffer. The value is copied into this buffer, and the data type of the value is returned. Further, the actual number of bytes of data read from the value is returned.

Table 4.27. RegQueryValueEx Retrieves the type and data for a specified value
RegQueryValueEx
HKEY hKey Handle to the open key for the value to be queried.
LPCWSTR lpValueName Name of the value, or NULL to get the default value.
LPDWORD lpReserved Reserved, pass as NULL.
LPDWORD lpType Pointer to a DWORD that receives the data type of the value, as one of the values in Table 4-24.
LPBYTE lpData Pointer to a buffer to receive the data.
LPDWORD lpcbData DWORD pointer that, on entry, contains the size of the buffer pointed to by lpData. On return, contains the number of bytes copied into the buffer.
LONG Return Value ERROR_SUCCESS on success, or an error value.

Obviously, you need to know the names of the values to read before calling RegQueryValueEx. If you need to enumerate all the values in a key, you can RegQueryInfoKey, which is described later in the section "Enumerating a Registry Key." As with any open key, in Listing 4.21 RegCloseKey is called to close the key.

Deleting a Registry Value

The function RegDeleteValue can be used to delete individual values in a key, or the RegDeleteKey (described in the next section) can delete a key and all the values in that key. The code in Listing 4.22 deletes the keys created in Listing 4.20. The function RegDeleteValue is passed a handle to an open key and the name of the value to delete. If this second parameter is NULL, the default value is deleted. Note that the key itself is not deleted if all the values themselves are deleted.

Listing 4.22 Deletes a registry value
 void Listing4_22() {   HKEY hKey;   DWORD dwDisp;   if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,   _T("Software\\MyCompany\\MyApplication"),         0, NULL, 0, 0, NULL,         &hKey, &dwDisp) != ERROR_SUCCESS)   {     cout   _T("Could not open/create key:");     return;   }   if(RegDeleteValue(hKey, _T("StringTest"))         != ERROR_SUCCESS)     cout   _T("Could not delete key")   endl;   if(RegDeleteValue(hKey, _T("DWORDTest"))         != ERROR_SUCCESS)     cout   _T("Could not delete key")   endl;   if(RegDeleteValue(hKey, NULL) != ERROR_SUCCESS)     cout   _T("Could not delete key")   endl;   RegCloseKey(hKey); } 

Deleting a Registry Key

Listing 4.23 calls the function RegDeleteKey to delete a key, and all the values and sub-keys associated with the key. The function takes the parent key handle (or one of the standard root key values, such as HKEY_LOCAL_MACHINE), and the name of the key. Note that the key being deleted is not opened first. The second parameter cannot be NULL, so the standard root keys (such as HKEY_LOCAL_MACHINE) cannot be deleted.

Listing 4.23 Deletes a registry key
 void Listing4_23() {   if(RegDeleteKey(HKEY_LOCAL_MACHINE,     _T("Software\\MyCompany")) != ERROR_SUCCESS)     cout   _T("Could not delete key");   else     cout   _T("Key deleted"); } 

Enumerating a Registry Key

The function RegQueryInfoKey can be used to determine information about a key, such as the number of sub-keys and values. Once this information has been determined, the function RegEnumValue can be used to enumerate the values associated with a particular key. Additionally, the function RegEnumKeyEx (not shown here) can be used to enumerate the keys associated with a key. The code in Listing 4.24 enumerates the values in the key HKEY_LOCAL_MACHINE\Platform This contains information on the manufacturer and other device information. This key has no sub-keys. As you would expect, calling RegOpenKeyEx first opens the key being enumerated.

Listing 4.24 Enumerates a registry key
 void Listing4_24() {   HKEY hKey;   DWORD dwSubKeys, dwValues, dwIndex, dwValueNameLen;   DWORD dwValueType, dwValueLen;   TCHAR szValueName[255];   TCHAR szValue[255];   DWORD dwValue;   cout    _T("Opening key HKEY_LOCAL_MACHINE\\Platform")          endl;   if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,       _T("Platform"), 0, 0,       &hKey) != ERROR_SUCCESS)     cout   _T("Could not open key")   endl;   else if (RegQueryInfoKey(hKey, NULL, NULL, NULL,       &dwSubKeys, NULL, NULL, &dwValues,       NULL, NULL, NULL, NULL) != ERROR_SUCCESS)   {     cout   _T("Could not query info")   endl;     RegCloseKey(hKey);   }   else   {     cout   _T("Key has ")          dwSubKeys   _T(" subkeys and ")          dwValues   _T(" values")   endl;     // now read each value     for(dwIndex = 0; dwIndex  dwValues; dwIndex++)     {       // First determine name and data type.       dwValueNameLen = sizeof(szValueName);       RegEnumValue(hKey, dwIndex,         szValueName, &dwValueNameLen,         NULL, &dwValueType, NULL, NULL);       cout   _T("Value Name: ")   szValueName;       switch (dwValueType)       {       case REG_SZ:         cout   _T(" String:");         dwValueLen = sizeof(szValue);         dwValueNameLen = sizeof(szValueName);         RegEnumValue(hKey, dwIndex,           szValueName, &dwValueNameLen,           NULL, &dwValueType,           (LPBYTE)szValue, &dwValueLen);         cout   szValue;         break;       case REG_DWORD:         cout   _T(" DWORD:");         dwValueLen = sizeof(DWORD);         dwValueNameLen = sizeof(szValueName);         RegEnumValue(hKey, dwIndex,           szValueName, &dwValueNameLen,           NULL, &dwValueType,           (LPBYTE)&dwValue, &dwValueLen);         cout   dwValue;         break;       default:         cout   _T(" Other");         break;       }       cout   endl;     }     RegCloseKey(hKey);   } } 

In Listing 4.24, the function RegQueryInfoKey (Table 4.28) is used to determine the number of sub-keys and values contained in the open key. Then, a "for" loop is executed, calling the function RegEnumValue for each value to determine the name of the value and its data type. This name is then passed again to RegEnumValue to obtain the data associated with the value. Two calls to RegEnumValue are made, so that the second call can pass the correct data pointer for the value's data type. The code contains a switch that makes a call to RegEnumValue passing a pointer to the appropriate data type. It is possible to do this with a single call to RegEnumValue with suitable casting of the lpData parameter.

Table 4.28. RegQueryInfoKey Returns information about a registry key
RegQueryInfoKey
HKEY hKey Handle to the open key where the value is to be added or updated.
LPWSTR lpClass Pointer to a buffer to receive the class name, or NULL if the data is not to be returned.
LPDWORD lpcbClass Length of the buffer pointed to by lpClass, or 0 if lpClass is NULL.
LPDWORD lpReserved Reserved, pass as NULL.
LPDWORDlpcSubKeys Pointer to a DWORD variable that will receive the number of sub-keys in the key. Can be NULL if this information is not to be returned.
LPDWORD lpcbMaxSubKeyLen Pointer to a DWORD variable that will receive the length in characters of the longest key name. This parameter can be NULL.
LPDWORD lpcbMaxClassLen Pointer to a DWORD variable that will receive the length in characters of the longest class name. This parameter can be NULL.
LPDWORD lpcValues Pointer to a DWORD variable that will receive the number of values in the key. Can be NULL if this information is not to be returned.
LPDWORD lpcbMaxValueNameLen Pointer to a DWORD variable that will receive the length in characters of the longest value name. This parameter can be NULL.
LPDWORD lpcbMaxValueLen Pointer to a DWORD variable that will receive the length in charactersw of the longest piece of data in the values. This parameter can be NULL.
LPDWORD lpcbSecurityDescriptor Not used, pass as NULL.
PFILETIME lpftLastWriteTime Not used, pass as NULL.
LONG Return Value ERROR_SUCCESS, or an error code.

The first call to RegEnumValue (Table 4.29) passes in the handle to the key and the index number. The name of the value is returned in szValueName.

Table 4.29. RegEnumValue Enumerates values in a Key
RegEnumValue
HKEY hKey Handle to an open key being enumerated.
DWORD dwIndex Index value for value. Use 0 for the first value.
LPWSTR lpszValueName Pointer to a buffer to receive the value's name.
LPDWORD lpcchValueName A DWORD pointer that, on calling the function, contains the size of the buffer, in characters, pointed to be lpszValueName. Function returns the number of characters copied into lpszValueName.
LPDWORD lpReserved Reserved, pass as NULL.
LPDWORD lpType Pointer to a DWORD that returns the data type of the value. See Table 4.24.
LPBYTE lpData Pointer to a buffer to receive the value's data.
LPDWORD lpcbData A DWORD pointer that, on calling the function, contains the size of the buffer, in bytes, pointed to be lpData. Function returns the number of bytes of data copied into lpData.
LONG Return Value ERROR_SUCCESS on success, or an error code.

Note how dwValueNameLen is initialized with the length of the szValueName buffer for each iteration, since the function RegEnumValue overwrites the value in dwValueNameLen with the number of bytes copied into szValueName. The value type constant (such as REG_SZ) is returned in the variable dwValueType. Note that you should not add or otherwise change values during an enumeration of values. Values have no particular order in the registry, so the index value used when calling RegEnumValue has no particular significance.

 // First determine name and data type. dwValueNameLen = sizeof(szValueName); RegEnumValue(hKey, dwIndex,     szValueName, &dwValueNameLen,     NULL, &dwValueType, NULL, NULL); cout   _T("Value Name: ")   szValueName; 

Implementing a Record Counter using the Registry

Many database designs rely on the database providing a counter field type, the value of which is set by the database when records are added and is auto-incremented. Windows CE property databases do not provide such a field type, but the same functionality can be implemented using the registry.

The registry needs a value in a key for each table in the database that requires a counter field. The code in Listing 4.25 maintains a single counter in the registry key Software\MyCompany\MyApplication\ with the value name "Counter". The data is stored as a DWORD. The registry access code is very straightforward:

  • Open the Key

  • Read the current value

  • Increment the value

  • Save the new value back into the registry

  • Return the value to the caller

However, in a multitasking or multithreading environment, we need to protect against two applications or threads attempting to increment the counter value at the same time. For this reason, a mutex is used to ensure that only one application or thread increments the counter at a time. In Listing 4.25, a named mutex is created by calling CreateMutex. This function will open an existing mutex with the name "CounterMutex" if another application has already created the mutex (which will occur when two applications attempt to execute this code simultaneously). The mutex is initially not owned and is therefore signaled.

The code then calls WaitForSingleObject on the mutex. On return from WaitForSingleObject the thread will own the mutex, and the mutex will be nonsignaled. This means that any other threads calling CreateMutex will block in the WaitForSingleObject function call. The function ReleaseMutex relinquishes the ownership on the mutex and changes it to signaled. You can find out more information about mutexes and thread synchronization in Chapter 6.

Listing 4.25 Creates a counter value using the registry
 LONG GetNextCounterValue() {   LONG dwCounter;   HKEY hKey;   DWORD dwDisp;   HANDLE hMutex;   hMutex = CreateMutex(NULL, FALSE, _T("CounterMutex"));   if(hMutex == NULL)   {     cout   _T("Could not create mutex");     return -1;   }   else     WaitForSingleObject(hMutex, INFINITE);   if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,       _T("Software\\MyCompany\\MyApplication"),       0, NULL, 0, 0, NULL,       &hKey, &dwDisp) != 0)   {     cout   _T("Could not open registry key");     ReleaseMutex(hMutex);     CloseHandle(hMutex);     return -1;   }   DWORD cbData, cbType;   cbData = sizeof(DWORD);   if(RegQueryValueEx(hKey, _T("Counter"), NULL, &cbType,         (LPBYTE)&dwCounter, &cbData) != 0)   {     dwCounter = 0;   }   dwCounter++;   if(RegSetValueEx(hKey, _T("Counter"), NULL, REG_DWORD,       (LPBYTE)&dwCounter,       sizeof(DWORD)) != 0)   {     cout   _T("Could not save Server key");     ReleaseMutex(hMutex);     CloseHandle(hMutex);     return 0;   }   RegCloseKey(hKey);   ReleaseMutex(hMutex);   CloseHandle(hMutex);   return dwCounter 1; } void Listing4_25() {   cout   _T("Next counter value:")          GetNextCounterValue()   endl; } 

< BACK  NEXT >


Windows CE 3. 0 Application Programming
Windows CE 3.0: Application Programming (Prentice Hall Series on Microsoft Technologies)
ISBN: 0130255920
EAN: 2147483647
Year: 2002
Pages: 181

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net