Working with Registry Values

[Previous] [Next]

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:

 DWORD SHGetValue(  HKEY hkey, PCTSTR pszSubKey, PCTSTR pszValue, PDWORD pdwType, PVOID pvData, PDWORD pcbData); 

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.

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

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.

click to view at full size.

Figure 5-2. A search using the RegScan sample application

Listing 5-1. The RegScan sample application

 

RegScan.cpp

/****************************************************************************** Module: RegScan.cpp Notices: Copyright (c) 2000 Jeffrey Richter ******************************************************************************/ #include "..\CmnHdr.h" // See Appendix A. #include <WindowsX.h> #include <stdio.h> #include "Resource.h" #define UILAYOUT_IMPL #include "..\ClassLib\UILayout.h" // See Appendix B. #define PRINTBUF_IMPL #include "..\ClassLib\PrintBuf.h" // See Appendix B. #define AUTOBUF_IMPL #include "..\ClassLib\AutoBuf.h" // See Appendix B. #define REGWALK_IMPL #include "RegWalk.h" /////////////////////////////////////////////////////////////////////////////// class CRegScan : private CRegWalk { public: CRegScan() : m_pb(256 * 1024) { } BOOL Go(PCTSTR pszMachine, HKEY hkeyRoot, PCTSTR pszSubkey, PCTSTR pszString, BOOL fSearchKeyNames, BOOL fSearchValueNames, BOOL fSearchValueData, BOOL fCaseSensitive); PCTSTR Result() { return(m_pb); } void ForceSearchStop() { m_fStopSearch = TRUE; } BOOL WasSearchStopped() { return(m_fStopSearch); } private: PCTSTR m_pszString; // String to search for BOOL m_fSearchKeyNames; // Search key names? BOOL m_fSearchValueNames; // Search values names? BOOL m_fSearchValueData; // Search value string data? BOOL m_fShownThisSubkey; // Any matches from the current subkey? BOOL m_fStopSearch; // Prematurely stop the search? CPrintBuf m_pb; // Growable results buffer typedef PTSTR (WINAPI* PFNSTRCMP)(PCTSTR pszFirst, PCTSTR pszSearch); PFNSTRCMP m_pfnStrCmp; // String comparison function protected: REGWALKSTATUS onSubkey(PCTSTR pszSubkey, int nDepth, BOOL fRecurseRequested); REGWALKSTATUS onValue(HKEY hkey, PCTSTR pszValue, int nDepth); void ProcessUI(); }; /////////////////////////////////////////////////////////////////////////////// BOOL CRegScan::Go(PCTSTR pszMachine, HKEY hkeyRoot, PCTSTR pszSubkey, PCTSTR pszString, BOOL fSearchKeyNames, BOOL fSearchValueNames, BOOL fSearchValueData, BOOL fCaseSensitive) { m_pszString = pszString; m_fSearchKeyNames = fSearchKeyNames; m_fSearchValueNames = fSearchValueNames; m_fSearchValueData = fSearchValueData; m_pfnStrCmp = fCaseSensitive ? StrStr : StrStrI; m_fShownThisSubkey = FALSE; m_fStopSearch = FALSE; m_pb.Clear(); BOOL fOk = TRUE; if (!m_fSearchKeyNames && !m_fSearchValueNames && !m_fSearchValueData) { chMB("You must at least select one field to search."); } else fOk = CRegWalk::Go(pszMachine, hkeyRoot, pszSubkey, TRUE); return(fOk); } /////////////////////////////////////////////////////////////////////////////// void CRegScan::ProcessUI() { MSG msg; while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { // There are UI messages, process them. if (!IsDialogMessage(GetActiveWindow(), &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } /////////////////////////////////////////////////////////////////////////////// CRegWalk::REGWALKSTATUS CRegScan::onSubkey(PCTSTR pszSubkey, int nDepth, BOOL fRecurseRequested) { REGWALKSTATUS rws = RWS_FULLSTOP; if (fRecurseRequested || (nDepth == 0)) rws = RWS_RECURSE; // Get this subkey's name without the full path PCTSTR pszSubkeyName = PathFindFileName(pszSubkey); if (m_fSearchKeyNames) m_fShownThisSubkey = (m_pfnStrCmp(pszSubkeyName, m_pszString) != NULL); else m_fShownThisSubkey = FALSE; if (m_fShownThisSubkey) { m_pb.Print(TEXT("%s\r\n"), pszSubkey); } ProcessUI(); return(WasSearchStopped() ? RWS_FULLSTOP : rws); } /////////////////////////////////////////////////////////////////////////////// CRegWalk::REGWALKSTATUS CRegScan::onValue( HKEY hkey, PCTSTR pszValue, int nDepth) { if (m_fSearchValueNames && (m_pfnStrCmp(pszValue, m_pszString) != NULL)) { if (!m_fShownThisSubkey) { m_pb.Print(TEXT("%s\r\n"), m_szSubkeyPath); m_fShownThisSubkey = TRUE; } m_pb.Print(TEXT("\t%s\r\n"), pszValue); } if (m_fSearchValueData) { // Check the value's data DWORD dwType; RegQueryValueEx(hkey, pszValue, NULL, &dwType, NULL, NULL); if ((dwType == REG_EXPAND_SZ) || (dwType == REG_SZ)) { CAutoBuf<TCHAR, sizeof(TCHAR)> szData; // Give buffer a size > 0 so that RegQueryValueEx returns // ERROR_MORE_DATA instead of ERROR_SUCCESS. szData = 1; while (RegQueryValueEx(hkey, pszValue, NULL, NULL, szData, szData) == ERROR_MORE_DATA) ; // szData is NULL is there is no value data if (((PCTSTR) szData != NULL) && (m_pfnStrCmp(szData, m_pszString) != NULL)) { if (!m_fShownThisSubkey) { m_pb.Print(TEXT("%s\r\n"), m_szSubkeyPath); m_fShownThisSubkey = TRUE; } m_pb.Print(TEXT("\t%s (%s)\r\n"), ((pszValue[0] == 0) ? TEXT("(default)") : pszValue), (PCTSTR) szData); } } } ProcessUI(); return(WasSearchStopped() ? RWS_FULLSTOP : RWS_CONTINUE); } /////////////////////////////////////////////////////////////////////////////// CUILayout g_UILayout; // Repositions controls when dialog box size changes. /////////////////////////////////////////////////////////////////////////////// BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) { chSETDLGICONS(hwnd, IDI_REGSCAN); HWND hwndRootKey = GetDlgItem(hwnd, IDC_ROOTKEY); int n = 0; n = ComboBox_AddString(hwndRootKey, TEXT("HKEY_LOCAL_MACHINE")); ComboBox_SetItemData(hwndRootKey, n, HKEY_LOCAL_MACHINE); ComboBox_SetCurSel(hwndRootKey, n); // HKLM is default n = ComboBox_AddString(hwndRootKey, TEXT("HKEY_CURRENT_CONFIG")); ComboBox_SetItemData(hwndRootKey, n, HKEY_CURRENT_CONFIG); n = ComboBox_AddString(hwndRootKey, TEXT("HKEY_CLASSES_ROOT")); ComboBox_SetItemData(hwndRootKey, n, HKEY_CLASSES_ROOT); n = ComboBox_AddString(hwndRootKey, TEXT("HKEY_USERS")); ComboBox_SetItemData(hwndRootKey, n, HKEY_USERS); n = ComboBox_AddString(hwndRootKey, TEXT("HKEY_CURRENT_USER")); ComboBox_SetItemData(hwndRootKey, n, HKEY_CURRENT_USER); // Set up the resizeing of the controls g_UILayout.Initialize(hwnd); g_UILayout.AnchorControl(CUILayout::AP_TOPLEFT, CUILayout::AP_TOPRIGHT, IDC_MACHINE, FALSE); g_UILayout.AnchorControl(CUILayout::AP_TOPLEFT, CUILayout::AP_TOPRIGHT, IDC_ROOTKEY, FALSE); g_UILayout.AnchorControl(CUILayout::AP_TOPLEFT, CUILayout::AP_TOPRIGHT, IDC_SUBKEY, FALSE); g_UILayout.AnchorControl(CUILayout::AP_TOPLEFT, CUILayout::AP_TOPRIGHT, IDC_STRING, FALSE); g_UILayout.AnchorControl(CUILayout::AP_TOPRIGHT, CUILayout::AP_TOPRIGHT, IDC_SEARCHKEYNAMES, FALSE); g_UILayout.AnchorControl(CUILayout::AP_TOPRIGHT, CUILayout::AP_TOPRIGHT, IDC_SEARCHVALUENAMES, FALSE); g_UILayout.AnchorControl(CUILayout::AP_TOPRIGHT, CUILayout::AP_TOPRIGHT, IDC_SEARCHVALUEDATA, FALSE); g_UILayout.AnchorControl(CUILayout::AP_TOPRIGHT, CUILayout::AP_TOPRIGHT, IDC_CASESENSITIVE, FALSE); g_UILayout.AnchorControl(CUILayout::AP_TOPRIGHT, CUILayout::AP_TOPRIGHT, IDC_SEARCHSTART, FALSE); g_UILayout.AnchorControl(CUILayout::AP_TOPRIGHT, CUILayout::AP_TOPRIGHT, IDC_SEARCHSTOP, FALSE); g_UILayout.AnchorControl(CUILayout::AP_TOPLEFT, CUILayout::AP_BOTTOMRIGHT, IDC_SEARCHRESULTS, FALSE); CheckDlgButton(hwnd, IDC_SEARCHKEYNAMES, TRUE); CheckDlgButton(hwnd, IDC_SEARCHVALUENAMES, TRUE); CheckDlgButton(hwnd, IDC_SEARCHVALUEDATA, TRUE); return(TRUE); } /////////////////////////////////////////////////////////////////////////////// void EnableControls(HWND hwnd, BOOL fEnable) { EnableWindow(GetDlgItem(hwnd, IDC_MACHINE), fEnable); EnableWindow(GetDlgItem(hwnd, IDC_ROOTKEY), fEnable); EnableWindow(GetDlgItem(hwnd, IDC_SUBKEY), fEnable); EnableWindow(GetDlgItem(hwnd, IDC_STRING), fEnable); EnableWindow(GetDlgItem(hwnd, IDC_SEARCHKEYNAMES), fEnable); EnableWindow(GetDlgItem(hwnd, IDC_SEARCHVALUENAMES), fEnable); EnableWindow(GetDlgItem(hwnd, IDC_SEARCHVALUEDATA), fEnable); EnableWindow(GetDlgItem(hwnd, IDC_CASESENSITIVE), fEnable); ShowWindow(GetDlgItem(hwnd, IDC_SEARCHSTART), fEnable ? SW_SHOW : SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_SEARCHSTOP), fEnable ? SW_HIDE : SW_SHOW); } /////////////////////////////////////////////////////////////////////////////// void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { static CRegScan x; switch (id) { case IDCANCEL: EndDialog(hwnd, id); break; case IDC_SEARCHSTOP: x.ForceSearchStop(); break; case IDC_SEARCHSTART: SetDlgItemText(hwnd, IDC_SEARCHRESULTS, TEXT("Scanning Registry...")); EnableControls(hwnd, FALSE); TCHAR szString[1000]; GetDlgItemText(hwnd, IDC_STRING, szString, chDIMOF(szString)); TCHAR szMachine[100], szSubkey[1000]; GetDlgItemText(hwnd, IDC_MACHINE, szMachine, chDIMOF(szMachine)); GetDlgItemText(hwnd, IDC_SUBKEY, szSubkey, chDIMOF(szSubkey)); HWND hwndRootKey = GetDlgItem(hwnd, IDC_ROOTKEY); int nIndex = ComboBox_GetCurSel(hwndRootKey); HKEY hkeyRoot = (HKEY) ComboBox_GetItemData(hwndRootKey, nIndex); if (!x.Go( (szMachine[0] == 0) ? NULL : szMachine, hkeyRoot, szSubkey, szString, IsDlgButtonChecked(hwnd, IDC_SEARCHKEYNAMES), IsDlgButtonChecked(hwnd, IDC_SEARCHVALUENAMES), IsDlgButtonChecked(hwnd, IDC_SEARCHVALUEDATA), IsDlgButtonChecked(hwnd, IDC_CASESENSITIVE))) { chMB("Couldn't access the registry"); } SetDlgItemText(hwnd, IDC_SEARCHRESULTS, x.WasSearchStopped() ? TEXT("Scan Canceled") : ((x.Result()[0] == 0) ? TEXT("No entries found") : x.Result())); EnableControls(hwnd, TRUE); break; } } /////////////////////////////////////////////////////////////////////////////// void Dlg_OnSize(HWND hwnd, UINT state, int cx, int cy) { // Reposition the child controls g_UILayout.AdjustControls(cx, cy); } /////////////////////////////////////////////////////////////////////////////// void Dlg_OnGetMinMaxInfo(HWND hwnd, PMINMAXINFO pMinMaxInfo) { // Return minimum size of dialog box g_UILayout.HandleMinMax(pMinMaxInfo); } /////////////////////////////////////////////////////////////////////////////// INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog); chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand); chHANDLE_DLGMSG(hwnd, WM_SIZE, Dlg_OnSize); chHANDLE_DLGMSG(hwnd, WM_GETMINMAXINFO, Dlg_OnGetMinMaxInfo); } return(FALSE); } /////////////////////////////////////////////////////////////////////////////// int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) { DialogBox(hinstExe, MAKEINTRESOURCE(IDD_REGSCAN), NULL, Dlg_Proc); return(0); } //////////////////////////////// End of File //////////////////////////////////

 

RegWalk.h

/****************************************************************************** Module: RegWalk.h Notices: Copyright (c) 2000 Jeffrey Richter ******************************************************************************/ #pragma once // Include this header file once per compilation unit /////////////////////////////////////////////////////////////////////////////// #include <ShlWapi.h> /////////////////////////////////////////////////////////////////////////////// class CRegWalk { public: CRegWalk() {} virtual ~CRegWalk() {} BOOL Go(PCTSTR pszMachine, HKEY hkeyRoot, PCTSTR pszSubkey, BOOL fRecurse); enum REGWALKSTATUS { RWS_FULLSTOP, RWS_CONTINUE, RWS_RECURSE }; protected: virtual REGWALKSTATUS onSubkey(PCTSTR pszSubkey, int nDepth, BOOL fRecurseRequested); virtual REGWALKSTATUS onValue(HKEY hkey, PCTSTR pszValue, int nDepth); protected: HKEY m_hkeyRootMachine; // Root key on machine BOOL m_fRecurse; // Recurse into subkeys? int m_nDepth; // Recurse depth TCHAR m_szSubkeyPath[MAX_PATH]; // Subkey path private: REGWALKSTATUS RegWalkRecurse(); REGWALKSTATUS EnumValuesInSubkey(); }; /////////////////////////////////////////////////////////////////////////////// #ifdef REGWALK_IMPL /////////////////////////////////////////////////////////////////////////////// #pragma comment(lib, "shlwapi") /////////////////////////////////////////////////////////////////////////////// CRegWalk::REGWALKSTATUS CRegWalk::onSubkey(PCTSTR pszSubkey, int nDepth, BOOL fRecurseRequested) { return(fRecurseRequested ? RWS_RECURSE : RWS_CONTINUE); } CRegWalk::REGWALKSTATUS CRegWalk::onValue(HKEY hkey, PCTSTR pszValue, int nDepth) { return(RWS_CONTINUE); } /////////////////////////////////////////////////////////////////////////////// CRegWalk::REGWALKSTATUS CRegWalk::EnumValuesInSubkey() { HKEY hkey = NULL; REGWALKSTATUS rws = RWS_CONTINUE; if (ERROR_SUCCESS == RegOpenKeyEx(m_hkeyRootMachine, m_szSubkeyPath, 0, KEY_QUERY_VALUE, &hkey)) { for (int nIndex = 0; rws != RWS_FULLSTOP; nIndex++) { TCHAR szValueName[256]; // No value name exceeds 255 characters DWORD cbValueName = chDIMOF(szValueName); if (ERROR_SUCCESS != RegEnumValue(hkey, nIndex, szValueName, &cbValueName, NULL, NULL, NULL, NULL)) break; rws = onValue(hkey, szValueName, m_nDepth); } chVERIFY(RegCloseKey(hkey) == ERROR_SUCCESS); } return(rws); } /////////////////////////////////////////////////////////////////////////////// CRegWalk::REGWALKSTATUS CRegWalk::RegWalkRecurse() { // Report this Subkey REGWALKSTATUS rws = onSubkey(m_szSubkeyPath, ++m_nDepth, m_fRecurse); // Enumerate the values in this subkey? if (rws == RWS_RECURSE) rws = EnumValuesInSubkey(); // Continue enumerating subkeys? if (rws != RWS_FULLSTOP) { HKEY hkey = NULL; if (ERROR_SUCCESS == RegOpenKeyEx(m_hkeyRootMachine, m_szSubkeyPath, 0, KEY_ENUMERATE_SUB_KEYS, &hkey)) { for (int nIndex = 0; rws != RWS_FULLSTOP; nIndex++) { TCHAR szSubkeyName[256]; // No subkey name exceeds 255 characters DWORD cbSubkeyName = chDIMOF(szSubkeyName); if (ERROR_SUCCESS != RegEnumKeyEx(hkey, nIndex, szSubkeyName, &cbSubkeyName, NULL, NULL, NULL, NULL)) break; // Append the subkey to the path if (m_szSubkeyPath[0] != 0) StrCat(m_szSubkeyPath, TEXT("\\")); StrCat(m_szSubkeyPath, szSubkeyName); rws = RegWalkRecurse(); // Truncate the last subkey from the path PTSTR p = StrRChr(m_szSubkeyPath, NULL, TEXT(`\\')); if (p != NULL) *p = 0; else m_szSubkeyPath[0] = 0; } chVERIFY(RegCloseKey(hkey) == ERROR_SUCCESS); } } m_nDepth--; return(rws); } /////////////////////////////////////////////////////////////////////////////// BOOL CRegWalk::Go(PCTSTR pszMachine, HKEY hkeyRoot, PCTSTR pszSubkey, BOOL fRecurse) { // nDepth indicates how many levels from the top we are. m_nDepth = -1; m_fRecurse = fRecurse; m_hkeyRootMachine = NULL; REGWALKSTATUS rws = RWS_FULLSTOP; __try { if (ERROR_SUCCESS != RegConnectRegistry(pszMachine, hkeyRoot, &m_hkeyRootMachine)) __leave; lstrcpy(m_szSubkeyPath, pszSubkey); // Call the recursive function to walk the subkeys rws = RegWalkRecurse(); } __finally { if (m_hkeyRootMachine != NULL) RegCloseKey(m_hkeyRootMachine); } return(rws != RWS_FULLSTOP); } /////////////////////////////////////////////////////////////////////////////// #endif // REGWALK_IMPL //////////////////////////////// End of File //////////////////////////////////



Programming Server-Side Applications for Microsoft Windows 2000
Programming Server-Side Applications for Microsoft Windows 2000 (Microsoft Programming)
ISBN: 0735607532
EAN: 2147483647
Year: 2000
Pages: 126

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