Up to this point, I have mostly discussed registry keys, without much mention of how to work with registry values. The registry value is the actual meat and potatoes of the registry. Registry values store the actual configuration data for your applications. Once you have a valid handle to an open registry key, you are ready to retrieve data contained within that key.
Three functions retrieve values from the system registry: RegQueryValueEx, RegEnumValue, and RegQueryMultipleValues. I will focus on RegQueryValueEx and RegEnumValue now. I'll discuss RegQueryMultipleValues shortly, in the section "Accessing the Registry Remotely."
You should use the RegEnumValue function when you do not know the name of the value that contains the data you want to retrieve, or when you want to systematically retrieve the data for all values contained within a given key. Conversely, you should use RegQueryValueEx to obtain data from a single value within a key, whose name (or lack of a name, in the case of the default value) is known ahead of time. The RegQueryValueEx function is prototyped as follows:
LONG RegQueryValueEx( HKEY hkey, PTSTR pszValueName, PDWORD pdwReserved, PDWORD pdwType, PBYTE pbData, PDWORD pcbData); |
The hkey parameter is the handle to an open key with KEY_QUERY_VALUE access, and the pszValueName is the name of the value you wish to retrieve. If you pass NULL or a pointer to an empty string for the pszValueName parameter, the system will retrieve data from the default value for the key.
The pdwType parameter is a pointer to a DWORD variable that the system will fill with one of the data type values (such as REG_SZ or REG_BINARY) listed in Table 5-2, indicating the registry value's data type.
The pbData parameter is a pointer to a buffer that the function fills with the registry value's data, and the pcbData parameter points to a DWORD that contains the size of the passed buffer. You can also pass NULL for the pbData parameter, in which case the function fills the DWORD pointed to by pcbData with the size, in bytes, of the data contained in the registry value.
NOTE
RegQueryValueEx returns the error ERROR_MORE_DATA if your buffer size is not sufficient to retrieve all the data from the value. Under all circumstances, your application should be able to deal gracefully with this error. Usually the response is to allocate a larger buffer and execute the call to the function again. Checking the size of a value's data before calling RegQueryValueEx is not a guarantee of success, because some other process might make changes to the registry value after your application checked its data size.The CAutoBuf class included on this book's companion CD offers an elegant (if I do say so myself) way to handle functions that require data buffers of varying sizes. This C++ class is used frequently in the sample applications in this book.
Typically if an application is going to retrieve only a single registry value, it will make two calls to RegQueryValueEx. The initial call is used to retrieve the required size of the buffer. After allocating a buffer of the proper size, a second call to RegQueryValueEx is made to actually retrieve the data.
There is, however, a second approach that might be more efficient depending largely on the number of registry values that you will be reading: make a single call to RegQueryInfoKey that returns the size of the largest value contained in the key. Then your application can allocate a single buffer to be used in multiple calls to RegQueryValueEx.
NOTE
The shell registry functions implement a function for retrieving data from registry values, named SHGetValue. It is defined as follows:
Notice that this function is very similar to RegQueryValueEx, but it also includes a pszSubKey parameter that allows you to specify the name of the key containing the value. This frees your application from the responsibility of calling RegOpenKeyEx and RegCloseKey.
DWORD SHGetValue( HKEY hkey, PCTSTR pszSubKey, PCTSTR pszValue, PDWORD pdwType, PVOID pvData, PDWORD pcbData);
If you do not know the name of the registry value in question, or if you wish to retrieve the data for every value contained within a single key, you should use RegEnumValue, which is prototyped as follows:
LONG RegEnumValue( HKEY hkey, DWORD dwIndex, PTSTR pszValueName, PDWORD pcbValueName, PDWORD pdwReserved, PDWORD pdwType, PBYTE pbData, PDWORD pcbData); |
As you can see, RegEnumValue is very similar to RegQueryValueEx, except that rather than passing RegEnumValue a value name, you pass it an index value that correlates to the sequential location of the value within the key referenced in hkey. RegEnumValue returns the value name in a buffer pointed to by the pszValueName parameter.
To find the proper size of the buffer so that you can retrieve the value's name, your application can make an initial call to RegQueryValueEx, specifying NULL for pbData. Doing so retrieves the length of the longest value name contained within the key.
The RegScan sample application ("05 RegScan.exe"), shown in Listing 5-1, demonstrates how to enumerate keys and values under a specified key, as well as how to retrieve data from the enumerated values. The source code and resource files for the application are in the 05-RegScan directory on the companion CD. The sample application will recursively traverse the registry as it searches for a specified text string either in a key name or in a value.
When you launch RegScan, you can enter the machine name whose registry you wish to search. Then you select a root key and a starting subkey and enter a search string in the String edit box. Figure 5-2 shows the results of my search.
Later in this chapter (in the section "Accessing the Registry Remotely"), I'll discuss how RegScan can search a remote machine's registry.
Listing 5-1. The RegScan sample application
|
|