Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

544 lines
13 KiB

  1. #include "pch.h"
  2. #pragma hdrstop
  3. #include "registry.h"
  4. RegKey::RegKey(
  5. void
  6. ) : m_hkeyRoot(NULL),
  7. m_hkey(NULL),
  8. m_hChangeEvent(NULL),
  9. m_bWatchSubtree(false),
  10. m_dwChangeFilter(0)
  11. {
  12. DBGTRACE((DM_REG, DL_MID, TEXT("RegKey::RegKey [default]")));
  13. }
  14. RegKey::RegKey(
  15. HKEY hkeyRoot,
  16. LPCTSTR pszSubKey
  17. ) : m_hkeyRoot(hkeyRoot),
  18. m_hkey(NULL),
  19. m_strSubKey(pszSubKey),
  20. m_hChangeEvent(NULL),
  21. m_bWatchSubtree(false),
  22. m_dwChangeFilter(0)
  23. {
  24. DBGTRACE((DM_REG, DL_MID, TEXT("RegKey::RegKey")));
  25. //
  26. // Nothing to do.
  27. //
  28. }
  29. RegKey::~RegKey(
  30. void
  31. )
  32. {
  33. DBGTRACE((DM_REG, DL_MID, TEXT("RegKey::~RegKey")));
  34. Close();
  35. if (NULL != m_hChangeEvent)
  36. CloseHandle(m_hChangeEvent);
  37. }
  38. HRESULT
  39. RegKey::Open(
  40. REGSAM samDesired, // Access mask (i.e. KEY_READ, KEY_WRITE etc.)
  41. bool bCreate // Create key if it doesn't exist?
  42. ) const
  43. {
  44. DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::Open")));
  45. DBGPRINT((DM_REG, DL_HIGH, TEXT("\thkeyRoot = 0x%08X, SubKey = \"%s\""),
  46. m_hkeyRoot, m_strSubKey.Cstr()));
  47. DWORD dwResult = ERROR_SUCCESS;
  48. Close();
  49. if (bCreate)
  50. {
  51. DWORD dwDisposition;
  52. dwResult = RegCreateKeyEx(m_hkeyRoot,
  53. (LPCTSTR)m_strSubKey,
  54. 0,
  55. NULL,
  56. 0,
  57. samDesired,
  58. NULL,
  59. &m_hkey,
  60. &dwDisposition);
  61. }
  62. else
  63. {
  64. dwResult = RegOpenKeyEx(m_hkeyRoot,
  65. (LPCTSTR)m_strSubKey,
  66. 0,
  67. samDesired,
  68. &m_hkey);
  69. }
  70. return HRESULT_FROM_WIN32(dwResult);
  71. }
  72. void
  73. RegKey::Attach(
  74. HKEY hkey
  75. )
  76. {
  77. Close();
  78. m_strSubKey.Empty();
  79. m_hkeyRoot = NULL;
  80. m_hkey = hkey;
  81. }
  82. void
  83. RegKey::Detach(
  84. void
  85. )
  86. {
  87. m_hkey = NULL;
  88. }
  89. void
  90. RegKey::Close(
  91. void
  92. ) const
  93. {
  94. DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::Close")));
  95. DBGPRINT((DM_REG, DL_HIGH, TEXT("\thkeyRoot = 0x%08X, SubKey = \"%s\""),
  96. m_hkeyRoot, m_strSubKey.Cstr()));
  97. if (NULL != m_hkey)
  98. {
  99. //
  100. // Do this little swap so that the m_hkey member is NULL
  101. // when the actual key is being closed. This lets the async
  102. // change proc determine if it was signaled because of a true
  103. // change or because the key was being closed.
  104. //
  105. HKEY hkeyTemp = m_hkey;
  106. m_hkey = NULL;
  107. RegCloseKey(hkeyTemp);
  108. }
  109. }
  110. //
  111. // This is the basic form of GetValue. All other forms of
  112. // GetValue() call into this one.
  113. //
  114. HRESULT
  115. RegKey::GetValue(
  116. LPCTSTR pszValueName,
  117. DWORD dwTypeExpected,
  118. LPBYTE pbData,
  119. int cbData
  120. ) const
  121. {
  122. DWORD dwType;
  123. DWORD dwResult = RegQueryValueEx(m_hkey,
  124. pszValueName,
  125. 0,
  126. &dwType,
  127. pbData,
  128. (LPDWORD)&cbData);
  129. if (ERROR_SUCCESS == dwResult && dwType != dwTypeExpected)
  130. dwResult = ERROR_INVALID_DATATYPE;
  131. return HRESULT_FROM_WIN32(dwResult);
  132. }
  133. //
  134. // Get a DWORD value (REG_DWORD).
  135. //
  136. HRESULT
  137. RegKey::GetValue(
  138. LPCTSTR pszValueName,
  139. DWORD *pdwDataOut
  140. ) const
  141. {
  142. return GetValue(pszValueName, REG_DWORD, (LPBYTE)pdwDataOut, sizeof(DWORD));
  143. }
  144. //
  145. // Get a byte buffer value (REG_BINARY).
  146. //
  147. HRESULT
  148. RegKey::GetValue(
  149. LPCTSTR pszValueName,
  150. LPBYTE pbDataOut,
  151. int cbDataOut
  152. ) const
  153. {
  154. return GetValue(pszValueName, REG_BINARY, pbDataOut, cbDataOut);
  155. }
  156. //
  157. // Get a text string value (REG_SZ) and write it to a CString object.
  158. //
  159. HRESULT
  160. RegKey::GetValue(
  161. LPCTSTR pszValueName,
  162. CString *pstrDataOut
  163. ) const
  164. {
  165. HRESULT hr = E_FAIL;
  166. int cch = GetValueBufferSize(pszValueName) / sizeof(TCHAR);
  167. if (NULL != pstrDataOut && 0 < cch)
  168. {
  169. hr = GetValue(pszValueName,
  170. REG_SZ,
  171. (LPBYTE)pstrDataOut->GetBuffer(cch),
  172. pstrDataOut->SizeBytes());
  173. pstrDataOut->ReleaseBuffer();
  174. }
  175. return hr;
  176. }
  177. //
  178. // Get a multi-text string value (REG_MULTI_SZ) and write it to a CArray<CString> object.
  179. //
  180. HRESULT
  181. RegKey::GetValue(
  182. LPCTSTR pszValueName,
  183. CArray<CString> *prgstrOut
  184. ) const
  185. {
  186. HRESULT hr = E_FAIL;
  187. int cb = GetValueBufferSize(pszValueName);
  188. if (NULL != prgstrOut && 0 < cb)
  189. {
  190. array_autoptr<TCHAR> ptrTemp(new TCHAR[cb / sizeof(TCHAR)]);
  191. LPCTSTR psz = ptrTemp.get();
  192. hr = GetValue(pszValueName, REG_MULTI_SZ, (LPBYTE)psz, cb);
  193. if (SUCCEEDED(hr))
  194. {
  195. while(psz && TEXT('\0') != *psz)
  196. {
  197. prgstrOut->Append(CString(psz));
  198. psz += lstrlen(psz) + 1;
  199. }
  200. }
  201. }
  202. return hr;
  203. }
  204. //
  205. // Return the required buffer size for a given registry value.
  206. //
  207. int
  208. RegKey::GetValueBufferSize(
  209. LPCTSTR pszValueName
  210. ) const
  211. {
  212. DWORD dwType;
  213. int cbData = 0;
  214. DWORD dwDummy;
  215. DWORD dwResult = RegQueryValueEx(m_hkey,
  216. pszValueName,
  217. 0,
  218. &dwType,
  219. (LPBYTE)&dwDummy,
  220. (LPDWORD)&cbData);
  221. if (ERROR_MORE_DATA != dwResult)
  222. cbData = 0;
  223. return cbData;
  224. }
  225. //
  226. // This is the basic form of SetValue. All other forms of
  227. // SetValue() call into this one.
  228. //
  229. HRESULT
  230. RegKey::SetValue(
  231. LPCTSTR pszValueName,
  232. DWORD dwValueType,
  233. const LPBYTE pbData,
  234. int cbData
  235. )
  236. {
  237. DWORD dwResult = RegSetValueEx(m_hkey,
  238. pszValueName,
  239. 0,
  240. dwValueType,
  241. pbData,
  242. cbData);
  243. return HRESULT_FROM_WIN32(dwResult);
  244. }
  245. //
  246. // Set a DWORD value (REG_DWORD).
  247. //
  248. HRESULT
  249. RegKey::SetValue(
  250. LPCTSTR pszValueName,
  251. DWORD dwData
  252. )
  253. {
  254. return SetValue(pszValueName, REG_DWORD, (const LPBYTE)&dwData, sizeof(dwData));
  255. }
  256. //
  257. // Set a byte buffer value (REG_BINARY).
  258. //
  259. HRESULT
  260. RegKey::SetValue(
  261. LPCTSTR pszValueName,
  262. const LPBYTE pbData,
  263. int cbData
  264. )
  265. {
  266. return SetValue(pszValueName, REG_BINARY, pbData, cbData);
  267. }
  268. //
  269. // Set a text string value (REG_SZ).
  270. //
  271. HRESULT
  272. RegKey::SetValue(
  273. LPCTSTR pszValueName,
  274. LPCTSTR pszData
  275. )
  276. {
  277. return SetValue(pszValueName, REG_SZ, (const LPBYTE)pszData, (lstrlen(pszData) + 1) * sizeof(TCHAR));
  278. }
  279. //
  280. // Set a text string value (REG_MULTI_SZ).
  281. //
  282. HRESULT
  283. RegKey::SetValue(
  284. LPCTSTR pszValueName,
  285. const CArray<CString>& rgstrSrc
  286. )
  287. {
  288. array_autoptr<TCHAR> ptrValues(CreateDoubleNulTermList(rgstrSrc));
  289. int cch = 1;
  290. int n = rgstrSrc.Count();
  291. for (int i = 0; i < n; i++)
  292. cch += rgstrSrc[i].Length() + 1;
  293. return SetValue(pszValueName, REG_MULTI_SZ, (const LPBYTE)ptrValues.get(), cch * sizeof(TCHAR));
  294. }
  295. LPTSTR
  296. RegKey::CreateDoubleNulTermList(
  297. const CArray<CString>& rgstrSrc
  298. ) const
  299. {
  300. int cEntries = rgstrSrc.Count();
  301. int cch = 1; // Account for 2nd nul term.
  302. int i;
  303. for (i = 0; i < cEntries; i++)
  304. cch += rgstrSrc[i].Length() + 1;
  305. LPTSTR pszBuf = new TCHAR[cch];
  306. LPTSTR pszWrite = pszBuf;
  307. for (i = 0; i < cEntries; i++)
  308. {
  309. CString& s = rgstrSrc[i];
  310. lstrcpy(pszWrite, s);
  311. pszWrite += s.Length() + 1;
  312. }
  313. *pszWrite = TEXT('\0'); // Double nul term.
  314. return pszBuf;
  315. }
  316. void
  317. RegKey::OnChange(
  318. HKEY hkey
  319. )
  320. {
  321. DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::OnChange")));
  322. //
  323. // Default does nothing.
  324. //
  325. }
  326. DWORD
  327. RegKey::NotifyWaitThreadProc(
  328. LPVOID pvParam
  329. )
  330. {
  331. DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::NotifyWaitThreadProc")));
  332. RegKey *pThis = (RegKey *)pvParam;
  333. while(NULL != pThis->m_hkey)
  334. {
  335. DBGPRINT((DM_REG, DL_HIGH, TEXT("RegNotifyChangeKey(0x%08X, %d, 0x%08X, 0x%08X, %d)"),
  336. pThis->m_hkey, pThis->m_bWatchSubtree, pThis->m_dwChangeFilter, pThis->m_hChangeEvent, true));
  337. LONG lResult = RegNotifyChangeKeyValue(pThis->m_hkey,
  338. pThis->m_bWatchSubtree,
  339. pThis->m_dwChangeFilter,
  340. pThis->m_hChangeEvent,
  341. true);
  342. if (ERROR_SUCCESS != lResult)
  343. {
  344. DBGERROR((TEXT("RegNotifyChangeKeyValue failed with error %d"), lResult));
  345. return 0;
  346. }
  347. else
  348. {
  349. DBGPRINT((DM_REG, DL_MID, TEXT("Waiting for reg change notification...")));
  350. switch(WaitForSingleObject(pThis->m_hChangeEvent, INFINITE))
  351. {
  352. case WAIT_OBJECT_0:
  353. if (NULL != pThis->m_hkey)
  354. {
  355. DBGPRINT((DM_REG, DL_MID, TEXT("Rcv'd reg change notification")));
  356. pThis->OnChange(pThis->m_hkey);
  357. }
  358. break;
  359. case WAIT_FAILED:
  360. DBGERROR((TEXT("Registry chg wait failed with error %d"), GetLastError()));
  361. break;
  362. default:
  363. break;
  364. }
  365. }
  366. }
  367. return 0;
  368. }
  369. HRESULT
  370. RegKey::WatchForChange(
  371. DWORD dwChangeFilter,
  372. bool bWatchSubtree
  373. )
  374. {
  375. DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::WatchForChange")));
  376. HRESULT hr = E_FAIL;
  377. if (NULL != m_hChangeEvent || NULL == m_hkey)
  378. return E_FAIL;
  379. m_hChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  380. if (NULL == m_hChangeEvent)
  381. {
  382. DBGERROR((TEXT("CreateEvent failed error %d"), GetLastError()));
  383. return HRESULT_FROM_WIN32(GetLastError());
  384. }
  385. m_dwChangeFilter = dwChangeFilter;
  386. m_bWatchSubtree = bWatchSubtree;
  387. DWORD dwThreadId = 0;
  388. HANDLE hThread = CreateThread(NULL,
  389. 0,
  390. (LPTHREAD_START_ROUTINE)NotifyWaitThreadProc,
  391. this,
  392. 0,
  393. &dwThreadId);
  394. if (INVALID_HANDLE_VALUE != hThread)
  395. {
  396. DBGPRINT((DM_REG, DL_MID, TEXT("Reg key chg watch thread ID = %d"), dwThreadId));
  397. CloseHandle(hThread);
  398. hr = NOERROR;
  399. }
  400. return hr;
  401. }
  402. HRESULT
  403. RegKey::WaitForChange(
  404. DWORD dwChangeFilter,
  405. bool bWatchSubtree
  406. )
  407. {
  408. DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKey::WaitForChange")));
  409. HRESULT hr = NOERROR;
  410. LONG lResult = RegNotifyChangeKeyValue(m_hkey,
  411. bWatchSubtree,
  412. dwChangeFilter,
  413. NULL,
  414. false);
  415. if (ERROR_SUCCESS != lResult)
  416. {
  417. DBGERROR((TEXT("RegNotifyChangeKeyValue failed with error %d"), lResult));
  418. hr = HRESULT_FROM_WIN32(lResult);
  419. }
  420. return hr;
  421. }
  422. #if DBG
  423. //-----------------------------------------------------------------------------
  424. // DEBUG ONLY
  425. //-----------------------------------------------------------------------------
  426. RegKeyChg::RegKeyChg(
  427. HKEY hkeyRoot,
  428. LPCTSTR pszSubKey
  429. ) : RegKey(hkeyRoot, pszSubKey)
  430. {
  431. DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKeyChg::RegKeyChg")));
  432. HRESULT hr = Open(KEY_READ | KEY_NOTIFY);
  433. if (SUCCEEDED(hr))
  434. {
  435. hr = WatchForChange(REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME, true);
  436. if (FAILED(hr))
  437. {
  438. DBGERROR((TEXT("WatchForChange failed with error 0x%08X"), hr));
  439. }
  440. }
  441. else if (ERROR_FILE_NOT_FOUND != HRESULT_CODE(hr))
  442. {
  443. DBGERROR((TEXT("Error 0x%08X opening key 0x%08X \"%s\""), hr, hkeyRoot, pszSubKey));
  444. }
  445. }
  446. RegKeyChg::~RegKeyChg(
  447. void
  448. )
  449. {
  450. DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKeyChg::~RegKeyChg")));
  451. }
  452. void
  453. RegKeyChg::OnChange(
  454. HKEY hkey
  455. )
  456. {
  457. DBGTRACE((DM_REG, DL_HIGH, TEXT("RegKeyChg::OnChange")));
  458. RegKey key;
  459. key.Attach(hkey);
  460. DebugRegParams dp;
  461. HRESULT hr = key.GetValue(REGSTR_VAL_DEBUGPARAMS, (LPBYTE)&dp, sizeof(dp));
  462. if (SUCCEEDED(hr))
  463. {
  464. DBGPRINT((DM_REG, DL_HIGH, TEXT("Setting new debug parameters")));
  465. DBGPRINTMASK(dp.PrintMask);
  466. DBGPRINTLEVEL(dp.PrintLevel);
  467. DBGPRINTVERBOSE(dp.PrintVerbose);
  468. DBGTRACEMASK(dp.TraceMask);
  469. DBGTRACELEVEL(dp.TraceLevel);
  470. DBGTRACEVERBOSE(dp.TraceVerbose);
  471. DBGTRACEONEXIT(dp.TraceOnExit);
  472. }
  473. else
  474. DBGERROR((TEXT("GetValue failed with error 0x%08X"), hr));
  475. key.Detach();
  476. }
  477. #endif // #if DBG