registry.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 16k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //+-------------------------------------------------------------------------
  2. //
  3. //  Microsoft Windows
  4. //
  5. //  Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. //  File:       registry.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #pragma hdrstop
  12. #include "registry.h"
  13. RegKey::RegKey(
  14.     void
  15.     ) : m_hkeyRoot(NULL),
  16.         m_hkey(NULL),
  17.         m_hChangeEvent(NULL)
  18. {
  19.     DBGTRACE((DM_REG, DL_MID, TEXT("RegKey::RegKey [default]")));
  20. }
  21. RegKey::RegKey(
  22.     HKEY hkeyRoot,
  23.     LPCTSTR pszSubKey
  24.     ) : m_hkeyRoot(hkeyRoot),
  25.         m_hkey(NULL),
  26.         m_strSubKey(pszSubKey),
  27.         m_hChangeEvent(NULL)
  28. {
  29.     DBGTRACE((DM_REG, DL_MID, TEXT("RegKey::RegKey")));
  30.     //
  31.     // Nothing to do.
  32.     //
  33. }
  34. RegKey::~RegKey(
  35.     void
  36.     )
  37. {
  38.     DBGTRACE((DM_REG, DL_MID, TEXT("RegKey::~RegKey")));
  39.     Close();
  40. }
  41. HRESULT
  42. RegKey::Open(
  43.     REGSAM samDesired,  // Access mask (i.e. KEY_READ, KEY_WRITE etc.)
  44.     bool bCreate        // Create key if it doesn't exist?
  45.     ) const
  46. {
  47.     DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::Open")));
  48.     DBGPRINT((DM_REG, DL_HIGH, TEXT("thkeyRoot = 0x%08X, SubKey = "%s""),
  49.                       m_hkeyRoot, m_strSubKey.Cstr()));
  50.     DWORD dwResult     = ERROR_SUCCESS;
  51.     HKEY hkeyRoot      = m_hkeyRoot; // Assume we'll use m_hkeyRoot;
  52.     bool bCloseRootKey = false;
  53.     
  54.     Close();
  55.     if (HKEY_CURRENT_USER == hkeyRoot)
  56.     {
  57.         //
  58.         // Special-case HKEY_CURRENT_USER.
  59.         // Since we're running from winlogon and need to open
  60.         // the user hive during tricky times we need to
  61.         // call RegOpenCurrentUser().  If it's successful all
  62.         // we do is replace the hkeyRoot member with the
  63.         // returned key.  From here on out things remain
  64.         // unchanged.
  65.         //
  66.         if (ERROR_SUCCESS == RegOpenCurrentUser(samDesired, &hkeyRoot))
  67.         {
  68.             bCloseRootKey = true;
  69.         }
  70.     }
  71.     dwResult = RegOpenKeyEx(hkeyRoot,
  72.                             (LPCTSTR)m_strSubKey,
  73.                             0,
  74.                             samDesired,
  75.                             &m_hkey);
  76.                             
  77.     if ((ERROR_FILE_NOT_FOUND == dwResult) && bCreate)
  78.     {
  79.         DWORD dwDisposition;
  80.         dwResult = RegCreateKeyEx(hkeyRoot,
  81.                                  (LPCTSTR)m_strSubKey,
  82.                                  0,
  83.                                  NULL,
  84.                                  0,
  85.                                  samDesired,
  86.                                  NULL,
  87.                                  &m_hkey,
  88.                                  &dwDisposition);
  89.     }
  90.     if (bCloseRootKey)
  91.     {
  92.         RegCloseKey(hkeyRoot);
  93.     }
  94.     return HRESULT_FROM_WIN32(dwResult);
  95. }
  96. void 
  97. RegKey::Attach(
  98.     HKEY hkey
  99.     )
  100. {
  101.     Close();
  102.     m_strSubKey.Empty();
  103.     m_hkeyRoot = NULL;
  104.     m_hkey     = hkey;
  105. }
  106. void 
  107. RegKey::Detach(
  108.     void
  109.     )
  110. {
  111.     m_hkey = NULL;
  112. }
  113. void
  114. RegKey::Close(
  115.     void
  116.     ) const
  117. {
  118.     DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::Close")));
  119.     DBGPRINT((DM_REG, DL_HIGH, TEXT("thkeyRoot = 0x%08X, SubKey = "%s""),
  120.                       m_hkeyRoot, m_strSubKey.Cstr()));
  121.     if (NULL != m_hChangeEvent)
  122.     {
  123.         //
  124.         // Once key is closed, the change-notification mechanism is 
  125.         // disabled.  No need for the change event object.
  126.         //
  127.         CloseHandle(m_hChangeEvent);
  128.         m_hChangeEvent = NULL;
  129.     }
  130.     if (NULL != m_hkey)
  131.     {
  132.         //
  133.         // Do this little swap so that the m_hkey member is NULL
  134.         // when the actual key is being closed.  This lets the async
  135.         // change proc determine if it was signaled because of a true
  136.         // change or because the key was being closed.
  137.         //
  138.         HKEY hkeyTemp = m_hkey;
  139.         m_hkey = NULL;
  140.         RegCloseKey(hkeyTemp);
  141.     }
  142. }
  143. //
  144. // Determine if a particular registry value exists.
  145. //
  146. HRESULT
  147. RegKey::ValueExists(
  148.     LPCTSTR pszValueName
  149.     ) const
  150. {
  151.     DWORD dwResult = ERROR_SUCCESS;
  152.     int iValue = 0;
  153.     TCHAR szValue[MAX_PATH];
  154.     DWORD cchValue;
  155.     while(ERROR_SUCCESS == dwResult)
  156.     {
  157.         cchValue = ARRAYSIZE(szValue);
  158.         dwResult = RegEnumValue(m_hkey, 
  159.                                 iValue++, 
  160.                                 szValue, 
  161.                                 &cchValue,
  162.                                 NULL,
  163.                                 NULL,
  164.                                 NULL,
  165.                                 NULL);
  166.         if (ERROR_SUCCESS == dwResult && (0 == lstrcmpi(pszValueName, szValue)))
  167.         {
  168.             DBGPRINT((DM_REG, DL_LOW, TEXT("Reg value "%s" exists."), pszValueName));
  169.             return S_OK;
  170.         }
  171.     }
  172.     if (ERROR_NO_MORE_ITEMS == dwResult)
  173.     {
  174.         DBGPRINT((DM_REG, DL_LOW, TEXT("Reg value "%s" doesn't exist."), pszValueName));
  175.         return S_FALSE;
  176.     }
  177.     return HRESULT_FROM_WIN32(dwResult);
  178. }
  179.                                 
  180.                      
  181. //
  182. // This is the basic form of GetValue.  All other forms of 
  183. // GetValue() call into this one.
  184. //
  185. HRESULT
  186. RegKey::GetValue(
  187.     LPCTSTR pszValueName,
  188.     DWORD dwTypeExpected,
  189.     LPBYTE pbData,
  190.     int cbData
  191.     ) const
  192. {
  193.     DWORD dwType;
  194.     DWORD dwResult = RegQueryValueEx(m_hkey,
  195.                                      pszValueName,
  196.                                      0,
  197.                                      &dwType,
  198.                                      pbData,
  199.                                      (LPDWORD)&cbData);
  200.     if (ERROR_SUCCESS == dwResult && dwType != dwTypeExpected)
  201.         dwResult = ERROR_INVALID_DATATYPE;
  202.     return HRESULT_FROM_WIN32(dwResult);
  203. }
  204. //
  205. // Get a DWORD value (REG_DWORD).
  206. //
  207. HRESULT
  208. RegKey::GetValue(
  209.     LPCTSTR pszValueName,
  210.     DWORD *pdwDataOut
  211.     ) const
  212. {
  213.     return GetValue(pszValueName, REG_DWORD, (LPBYTE)pdwDataOut, sizeof(DWORD));
  214. }
  215. //
  216. // Get a byte buffer value (REG_BINARY).
  217. //
  218. HRESULT
  219. RegKey::GetValue(
  220.     LPCTSTR pszValueName,
  221.     LPBYTE pbDataOut,
  222.     int cbDataOut
  223.     ) const
  224. {
  225.     return GetValue(pszValueName, REG_BINARY, pbDataOut, cbDataOut);
  226. }
  227. //
  228. // Get a text string value (REG_SZ) and write it to a CString object.
  229. //
  230. HRESULT
  231. RegKey::GetValue(
  232.     LPCTSTR pszValueName,
  233.     CString *pstrDataOut
  234.     ) const
  235. {
  236.     HRESULT hr = E_FAIL;
  237.     int cch = GetValueBufferSize(pszValueName) / sizeof(TCHAR);
  238.     if (NULL != pstrDataOut && 0 < cch)
  239.     {
  240.         LPTSTR psz = pstrDataOut->GetBuffer(cch);
  241.         hr = GetValue(pszValueName, 
  242.                       REG_SZ, 
  243.                       (LPBYTE)psz, 
  244.                       pstrDataOut->SizeBytes());
  245.         pstrDataOut->ReleaseBuffer();
  246.     }
  247.     return hr;
  248. }
  249. //
  250. // Get a multi-text string value (REG_MULTI_SZ) and write it to a CArray<CString> object.
  251. //
  252. HRESULT
  253. RegKey::GetValue(
  254.     LPCTSTR pszValueName,
  255.     CArray<CString> *prgstrOut
  256.     ) const
  257. {
  258.     HRESULT hr = E_FAIL;
  259.     int cb = GetValueBufferSize(pszValueName);
  260.     if (NULL != prgstrOut && 0 < cb)
  261.     {
  262.         array_autoptr<TCHAR> ptrTemp(new TCHAR[cb / sizeof(TCHAR)]);
  263.         LPCTSTR psz = ptrTemp.get();
  264.         hr = GetValue(pszValueName, REG_MULTI_SZ, (LPBYTE)psz, cb);
  265.         if (SUCCEEDED(hr))
  266.         {
  267.             while(psz && TEXT('') != *psz)
  268.             {
  269.                 prgstrOut->Append(CString(psz));
  270.                 psz += lstrlen(psz) + 1;
  271.             }
  272.         }
  273.     }
  274.     return hr;
  275. }
  276. //
  277. // Return the required buffer size for a given registry value.
  278. //
  279. int
  280. RegKey::GetValueBufferSize(
  281.     LPCTSTR pszValueName
  282.     ) const
  283. {
  284.     DWORD dwType;
  285.     int cbData = 0;
  286.     DWORD dwDummy;
  287.     DWORD dwResult = RegQueryValueEx(m_hkey,
  288.                                      pszValueName,
  289.                                      0,
  290.                                      &dwType,
  291.                                      (LPBYTE)&dwDummy,
  292.                                      (LPDWORD)&cbData);
  293.     if (ERROR_MORE_DATA != dwResult)
  294.         cbData = 0;
  295.     return cbData;
  296. }
  297. //
  298. // This is the basic form of SetValue.  All other forms of 
  299. // SetValue() call into this one.
  300. //
  301. HRESULT
  302. RegKey::SetValue(
  303.     LPCTSTR pszValueName,
  304.     DWORD dwValueType,
  305.     const LPBYTE pbData, 
  306.     int cbData
  307.     )
  308. {
  309.     DWORD dwResult = RegSetValueEx(m_hkey,
  310.                                    pszValueName,
  311.                                    0,
  312.                                    dwValueType,
  313.                                    pbData,
  314.                                    cbData);
  315.     return HRESULT_FROM_WIN32(dwResult);
  316. }
  317.       
  318. //
  319. // Set a DWORD value (REG_DWORD).
  320. //
  321. HRESULT
  322. RegKey::SetValue(
  323.     LPCTSTR pszValueName,
  324.     DWORD dwData
  325.     )
  326. {
  327.     return SetValue(pszValueName, REG_DWORD, (const LPBYTE)&dwData, sizeof(dwData));
  328. }
  329. //
  330. // Set a byte buffer value (REG_BINARY).
  331. //
  332. HRESULT
  333. RegKey::SetValue(
  334.     LPCTSTR pszValueName,
  335.     const LPBYTE pbData,
  336.     int cbData
  337.     )
  338. {
  339.     return SetValue(pszValueName, REG_BINARY, pbData, cbData);
  340. }
  341. //
  342. // Set a text string value (REG_SZ).
  343. //
  344. HRESULT
  345. RegKey::SetValue(
  346.     LPCTSTR pszValueName,
  347.     LPCTSTR pszData
  348.     )
  349. {
  350.     return SetValue(pszValueName, REG_SZ, (const LPBYTE)pszData, (lstrlen(pszData) + 1) * sizeof(TCHAR));
  351. }
  352. //
  353. // Set a text string value (REG_MULTI_SZ).
  354. //
  355. HRESULT
  356. RegKey::SetValue(
  357.     LPCTSTR pszValueName,
  358.     const CArray<CString>& rgstrSrc
  359.     )
  360. {
  361.     array_autoptr<TCHAR> ptrValues(CreateDoubleNulTermList(rgstrSrc));
  362.     int cch = 1;
  363.     int n = rgstrSrc.Count();
  364.     for (int i = 0; i < n; i++)
  365.         cch += rgstrSrc[i].Length() + 1;
  366.     return SetValue(pszValueName, REG_MULTI_SZ, (const LPBYTE)ptrValues.get(), cch * sizeof(TCHAR));
  367. }
  368. LPTSTR
  369. RegKey::CreateDoubleNulTermList(
  370.     const CArray<CString>& rgstrSrc
  371.     ) const
  372. {
  373.     int cEntries = rgstrSrc.Count();
  374.     int cch = 1; // Account for 2nd nul term.
  375.     int i;
  376.     for (i = 0; i < cEntries; i++)
  377.         cch += rgstrSrc[i].Length() + 1;
  378.     LPTSTR pszBuf = new TCHAR[cch];
  379.     LPTSTR pszWrite = pszBuf;
  380.     for (i = 0; i < cEntries; i++)
  381.     {
  382.         CString& s = rgstrSrc[i];
  383.         lstrcpy(pszWrite, s);
  384.         pszWrite += s.Length() + 1;
  385.     }
  386.     *pszWrite = TEXT(''); // Double nul term.
  387.     return pszBuf;
  388. }
  389. HRESULT 
  390. RegKey::MonitorChanges(
  391.     DWORD dwChangeFilter, 
  392.     bool bWatchSubtree
  393.     )
  394. {
  395.     DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::MonitorChanges")));
  396.     DWORD dwResult = 0;
  397.     if (NULL == m_hChangeEvent)
  398.     {
  399.         //
  400.         // Need a NULL DACL on this object because this code is run
  401.         // from within winlogon.exe.
  402.         //
  403.         SECURITY_ATTRIBUTES sa;
  404.         SECURITY_DESCRIPTOR sd;
  405.         InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  406.         SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
  407.         sa.lpSecurityDescriptor = &sd;
  408.         sa.bInheritHandle       = FALSE;
  409.         sa.nLength              = sizeof(sa);
  410.         m_hChangeEvent = ::CreateEvent(&sa,
  411.                                        FALSE,  // auto reset
  412.                                        FALSE,  // initially reset
  413.                                        NULL);  // unnamed
  414.         if (NULL == m_hChangeEvent)
  415.         {
  416.             dwResult = GetLastError();
  417.             DBGERROR((TEXT("CreateEvent failed with error %d"), dwResult));
  418.         }
  419.     }
  420.     if (NULL != m_hChangeEvent)
  421.     {
  422.         dwResult = (DWORD)::RegNotifyChangeKeyValue(m_hkey,
  423.                                                     bWatchSubtree,
  424.                                                     dwChangeFilter,
  425.                                                     m_hChangeEvent,
  426.                                                     true);
  427.         if (ERROR_SUCCESS != dwResult)
  428.         {
  429.             DBGERROR((TEXT("RegNotifyChangeKeyValue failed with error %d"), dwResult));
  430.         }
  431.     }
  432.     return HRESULT_FROM_WIN32(dwResult);
  433. }
  434. bool
  435. RegKey::HasChanged(
  436.     void
  437.     )
  438. {
  439.     return NULL != m_hChangeEvent && WAIT_OBJECT_0 == ::WaitForSingleObject(m_hChangeEvent, 0);
  440. }
  441. HRESULT
  442. RegKey::DeleteAllValues(
  443.     int *pcNotDeleted
  444.     )
  445. {
  446.     HRESULT hr;
  447.     KEYINFO ki;
  448.     if (NULL != pcNotDeleted)
  449.         *pcNotDeleted = 0;
  450.     hr = QueryInfo(&ki, QIM_VALUENAMEMAXCHARCNT);
  451.     if (FAILED(hr))
  452.         return hr;
  453.     CString strName;
  454.     DWORD cchValueName;
  455.     DWORD dwError = ERROR_SUCCESS;
  456.     int cNotDeleted = 0;
  457.     int iValue = 0;
  458.     while(ERROR_SUCCESS == dwError)
  459.     {
  460.         cchValueName = ki.cchValueNameMax + 1;
  461.         dwError = RegEnumValue(m_hkey,
  462.                                iValue,
  463.                                strName.GetBuffer(cchValueName),
  464.                                &cchValueName,
  465.                                NULL,
  466.                                NULL,
  467.                                NULL,
  468.                                NULL);
  469.         strName.ReleaseBuffer();
  470.         if (ERROR_SUCCESS == dwError)
  471.         {
  472.             if (FAILED(hr = DeleteValue(strName)))
  473.             {
  474.                 cNotDeleted++;
  475.                 iValue++;       // Skip to next value to avoid infinite loop.
  476.                 DBGERROR((TEXT("Error %d deleting reg value "%s""),
  477.                          HRESULT_CODE(hr), strName.Cstr()));
  478.             }
  479.         }
  480.     }
  481.     if (ERROR_NO_MORE_ITEMS == dwError)
  482.         dwError = ERROR_SUCCESS;
  483.     if (pcNotDeleted)
  484.         *pcNotDeleted = cNotDeleted;
  485.     return HRESULT_FROM_WIN32(dwError);
  486. }
  487. HRESULT 
  488. RegKey::DeleteValue(
  489.     LPCTSTR pszValue
  490.     )
  491. {
  492.     return HRESULT_FROM_WIN32(RegDeleteValue(m_hkey, pszValue));
  493. }
  494. HRESULT 
  495. RegKey::QueryInfo(
  496.     RegKey::KEYINFO *pInfo,
  497.     DWORD fMask
  498.     ) const
  499. {
  500.     LONG lResult = RegQueryInfoKey(m_hkey,
  501.                                    NULL,
  502.                                    NULL,
  503.                                    NULL,
  504.                                    (QIM_SUBKEYCNT & fMask) ? &pInfo->cSubKeys : NULL,
  505.                                    (QIM_SUBKEYMAXCHARCNT & fMask) ? &pInfo->cchSubKeyMax : NULL,
  506.                                    (QIM_CLASSMAXCHARCNT & fMask) ? &pInfo->cchClassMax : NULL,
  507.                                    (QIM_VALUECNT & fMask) ? &pInfo->cValues : NULL,
  508.                                    (QIM_VALUENAMEMAXCHARCNT & fMask) ? &pInfo->cchValueNameMax : NULL,
  509.                                    (QIM_VALUEMAXBYTECNT & fMask) ? &pInfo->cbValueMax : NULL,
  510.                                    (QIM_SECURITYBYTECNT & fMask) ? &pInfo->cbSecurityDesc : NULL,
  511.                                    (QIM_LASTWRITETIME & fMask) ? &pInfo->LastWriteTime : NULL);
  512.     return HRESULT_FROM_WIN32(lResult);
  513. }
  514. RegKey::ValueIterator::ValueIterator(
  515.     RegKey& key
  516.     ) : m_key(key),
  517.         m_iValue(0),
  518.         m_cchValueName(0)
  519.     KEYINFO ki;
  520.     if (SUCCEEDED(key.QueryInfo(&ki, QIM_VALUENAMEMAXCHARCNT)))
  521.     {
  522.         m_cchValueName = ki.cchValueNameMax + 1;
  523.     }
  524. }
  525. //
  526. // Returns:  S_OK    = More items.
  527. //           S_FALSE = No more items.
  528. HRESULT
  529. RegKey::ValueIterator::Next(
  530.     CString *pstrName, 
  531.     LPDWORD pdwType, 
  532.     LPBYTE pbData, 
  533.     LPDWORD pcbData
  534.     )
  535. {
  536.     HRESULT hr = S_OK;
  537.     DWORD cchValueName = m_cchValueName;
  538.     LONG lResult = RegEnumValue(m_key,
  539.                                 m_iValue,
  540.                                 pstrName->GetBuffer(m_cchValueName),
  541.                                 &cchValueName,
  542.                                 NULL,
  543.                                 pdwType,
  544.                                 pbData,
  545.                                 pcbData);
  546.     pstrName->ReleaseBuffer();
  547.     switch(lResult)
  548.     {
  549.         case ERROR_SUCCESS:
  550.             m_iValue++;
  551.             break;
  552.         case ERROR_NO_MORE_ITEMS:
  553.             hr = S_FALSE;
  554.             break;
  555.         default:
  556.             DBGERROR((TEXT("Error %d enumerating reg value "%s""), 
  557.                      lResult, m_key.SubKeyName().Cstr()));
  558.             hr = HRESULT_FROM_WIN32(lResult);
  559.             break;
  560.     }
  561.     return hr;
  562. };
  563. RegKeyCU::RegKeyCU(
  564.     REGSAM samDesired
  565.     ) : m_hkey(NULL)
  566. {
  567.     RegOpenCurrentUser(samDesired, &m_hkey);
  568. }
  569. RegKeyCU::~RegKeyCU(
  570.     void
  571.     )
  572. {
  573.     if (NULL != m_hkey)
  574.         RegCloseKey(m_hkey);
  575. }