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.

1141 lines
29 KiB

  1. #include "main.h"
  2. const WCHAR g_cOpenBracket = L'[';
  3. const WCHAR g_cCloseBracket = L']';
  4. const WCHAR g_cSemiColon = L';';
  5. #define TEMP_LOCATION TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Group Policy Objects")
  6. #define REG_EVENT_NAME TEXT("Group Policy registry event name for ")
  7. ///////////////////////////////////////////////////////////////////////////////
  8. // //
  9. // CRegistryHive object implementation //
  10. // //
  11. ///////////////////////////////////////////////////////////////////////////////
  12. CRegistryHive::CRegistryHive()
  13. {
  14. m_cRef = 1;
  15. InterlockedIncrement(&g_cRefThisDll);
  16. m_hKey = NULL;
  17. m_hEvent = NULL;
  18. m_lpFileName = m_lpKeyName = m_lpEventName = NULL;
  19. }
  20. CRegistryHive::~CRegistryHive()
  21. {
  22. InterlockedDecrement(&g_cRefThisDll);
  23. }
  24. ///////////////////////////////////////////////////////////////////////////////
  25. // //
  26. // CRegistryHive object implementation (IUnknown) //
  27. // //
  28. ///////////////////////////////////////////////////////////////////////////////
  29. HRESULT CRegistryHive::QueryInterface (REFIID riid, void **ppv)
  30. {
  31. if (IsEqualIID(riid, IID_IUnknown))
  32. {
  33. *ppv = (LPUNKNOWN)this;
  34. m_cRef++;
  35. return S_OK;
  36. }
  37. else
  38. {
  39. *ppv = NULL;
  40. return E_NOINTERFACE;
  41. }
  42. }
  43. ULONG CRegistryHive::AddRef (void)
  44. {
  45. return ++m_cRef;
  46. }
  47. ULONG CRegistryHive::Release (void)
  48. {
  49. if (--m_cRef == 0) {
  50. if (m_hKey)
  51. {
  52. RegCloseKey (m_hKey);
  53. if (m_lpKeyName)
  54. {
  55. BOOL bCleanRegistry = TRUE;
  56. //
  57. // We need to decide if the registry keys can be deleted or if
  58. // they are in use by another copy of GPE. To do this, close
  59. // the event we created during initialization and then try to
  60. // open the event again. If the event is successfully opened,
  61. // then another process is using the same registry key and it
  62. // should not be deleted.
  63. //
  64. if (m_hEvent && m_lpEventName)
  65. {
  66. CloseHandle (m_hEvent);
  67. m_hEvent = OpenEvent (SYNCHRONIZE, FALSE, m_lpEventName);
  68. if (m_hEvent)
  69. {
  70. bCleanRegistry = FALSE;
  71. }
  72. }
  73. if (bCleanRegistry)
  74. {
  75. RegDelnode (HKEY_CURRENT_USER, m_lpKeyName);
  76. RegDeleteKey (HKEY_CURRENT_USER, TEMP_LOCATION);
  77. }
  78. }
  79. }
  80. if (m_lpKeyName)
  81. {
  82. LocalFree (m_lpKeyName);
  83. }
  84. if (m_lpFileName)
  85. {
  86. LocalFree (m_lpFileName);
  87. }
  88. if (m_lpEventName)
  89. {
  90. LocalFree (m_lpEventName);
  91. }
  92. if (m_hEvent)
  93. {
  94. CloseHandle (m_hEvent);
  95. }
  96. delete this;
  97. return 0;
  98. }
  99. return m_cRef;
  100. }
  101. ///////////////////////////////////////////////////////////////////////////////
  102. // //
  103. // CRegistryHive object implementation (Public functions) //
  104. // //
  105. ///////////////////////////////////////////////////////////////////////////////
  106. STDMETHODIMP CRegistryHive::Initialize(LPTSTR lpFileName, LPTSTR lpKeyName)
  107. {
  108. TCHAR szBuffer[300];
  109. INT i;
  110. LONG lResult;
  111. DWORD dwDisp;
  112. HRESULT hr;
  113. //
  114. // Check for null pointer
  115. //
  116. if (!lpFileName || !(*lpFileName))
  117. {
  118. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Null filename")));
  119. return E_INVALIDARG;
  120. }
  121. //
  122. // Make sure this object hasn't been initialized already
  123. //
  124. if (m_hKey || m_lpFileName || m_lpKeyName)
  125. {
  126. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Object already initialized")));
  127. return (E_UNEXPECTED);
  128. }
  129. //
  130. // Find a temporary registry key to work with
  131. //
  132. lstrcpy (szBuffer, TEMP_LOCATION);
  133. lstrcat (szBuffer, TEXT("\\"));
  134. lstrcat (szBuffer, lpKeyName);
  135. lResult = RegCreateKeyEx (HKEY_CURRENT_USER, szBuffer, 0, NULL,
  136. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  137. NULL, &m_hKey, &dwDisp);
  138. if (lResult != ERROR_SUCCESS)
  139. {
  140. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Failed to open registry key with %d"), lResult));
  141. return (HRESULT_FROM_WIN32(lResult));
  142. }
  143. //
  144. // Store the keyname
  145. //
  146. m_lpKeyName = (LPTSTR) LocalAlloc (LPTR, (lstrlen(szBuffer) + 1) * sizeof(TCHAR));
  147. if (!m_lpKeyName)
  148. {
  149. RegCloseKey (m_hKey);
  150. m_hKey = NULL;
  151. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Failed to allocate memory for KeyName")));
  152. return (HRESULT_FROM_WIN32(GetLastError()));
  153. }
  154. lstrcpy (m_lpKeyName, szBuffer);
  155. //
  156. // Store the filename
  157. //
  158. m_lpFileName = (LPTSTR) LocalAlloc (LPTR, (lstrlen(lpFileName) + 1) * sizeof(TCHAR));
  159. if (!m_lpFileName)
  160. {
  161. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Failed to allocate memory for filename")));
  162. return (HRESULT_FROM_WIN32(GetLastError()));
  163. }
  164. lstrcpy (m_lpFileName, lpFileName);
  165. //
  166. // Store the event name
  167. //
  168. lstrcpy (szBuffer, REG_EVENT_NAME);
  169. lstrcat (szBuffer, lpKeyName);
  170. m_lpEventName = (LPTSTR) LocalAlloc (LPTR, (lstrlen(szBuffer) + 1) * sizeof(TCHAR));
  171. if (!m_lpEventName)
  172. {
  173. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Failed to allocate memory for filename")));
  174. return (HRESULT_FROM_WIN32(GetLastError()));
  175. }
  176. lstrcpy (m_lpEventName, szBuffer);
  177. //
  178. // Load the file if it exists
  179. //
  180. hr = Load();
  181. if (FAILED(hr))
  182. {
  183. return hr;
  184. }
  185. //
  186. // Create the registry event
  187. //
  188. m_hEvent = CreateEvent (NULL, FALSE, FALSE, m_lpEventName);
  189. if (!m_hEvent)
  190. {
  191. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Failed to create registry event with %d"),
  192. GetLastError()));
  193. return (HRESULT_FROM_WIN32(GetLastError()));
  194. }
  195. return (S_OK);
  196. }
  197. STDMETHODIMP CRegistryHive::GetHKey(HKEY *hKey)
  198. {
  199. HRESULT hr = E_FAIL;
  200. *hKey = NULL;
  201. if (m_hKey)
  202. {
  203. if (DuplicateHandle (GetCurrentProcess(),
  204. (HANDLE)m_hKey,
  205. GetCurrentProcess(),
  206. (LPHANDLE) hKey, 0,
  207. TRUE, DUPLICATE_SAME_ACCESS))
  208. {
  209. hr = S_OK;
  210. }
  211. else
  212. {
  213. hr = HRESULT_FROM_WIN32(GetLastError());
  214. }
  215. }
  216. return hr;
  217. }
  218. STDMETHODIMP CRegistryHive::Save(VOID)
  219. {
  220. HANDLE hFile;
  221. HRESULT hr;
  222. DWORD dwTemp, dwBytesWritten;
  223. LPWSTR lpKeyName;
  224. //
  225. // Check parameters
  226. //
  227. if (!m_hKey || !m_lpFileName || !m_lpKeyName)
  228. {
  229. return E_INVALIDARG;
  230. }
  231. //
  232. // Allocate a buffer to hold the keyname
  233. //
  234. lpKeyName = (LPWSTR) LocalAlloc (LPTR, MAX_KEYNAME_SIZE * sizeof(WCHAR));
  235. if (!lpKeyName)
  236. {
  237. return (HRESULT_FROM_WIN32(GetLastError()));
  238. }
  239. //
  240. // Create the output file
  241. //
  242. hFile = CreateFile (m_lpFileName, GENERIC_WRITE, 0, NULL,
  243. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
  244. NULL);
  245. if (hFile == INVALID_HANDLE_VALUE) {
  246. LocalFree (lpKeyName);
  247. return (HRESULT_FROM_WIN32(GetLastError()));
  248. }
  249. //
  250. // Write the header block
  251. //
  252. // 2 DWORDS, signature (PReg) and version number and 2 newlines
  253. //
  254. dwTemp = REGFILE_SIGNATURE;
  255. if (!WriteFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesWritten, NULL) ||
  256. dwBytesWritten != sizeof(dwTemp))
  257. {
  258. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Save: Failed to write signature with %d"),
  259. GetLastError()));
  260. hr = HRESULT_FROM_WIN32(GetLastError());
  261. goto Exit;
  262. }
  263. dwTemp = REGISTRY_FILE_VERSION;
  264. if (!WriteFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesWritten, NULL) ||
  265. dwBytesWritten != sizeof(dwTemp))
  266. {
  267. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Save: Failed to write version number with %d"),
  268. GetLastError()));
  269. hr = HRESULT_FROM_WIN32(GetLastError());
  270. goto Exit;
  271. }
  272. //
  273. // Exports the values / keys
  274. //
  275. hr = ExportKey (m_hKey, hFile, lpKeyName);
  276. Exit:
  277. //
  278. // Finished
  279. //
  280. CloseHandle (hFile);
  281. LocalFree (lpKeyName);
  282. return hr;
  283. }
  284. STDMETHODIMP CRegistryHive::ExportKey(HKEY hKey, HANDLE hFile, LPWSTR lpKeyName)
  285. {
  286. HRESULT hr = S_OK;
  287. DWORD dwBytesWritten, dwNameSize, dwDataSize, dwKeySize;
  288. DWORD dwIndex, dwTemp1, dwTemp2, dwType, dwKeyCount = 0;
  289. LONG lResult;
  290. HKEY hSubKey;
  291. LPWSTR lpValueName = NULL;
  292. LPWSTR lpSubKeyName = NULL;
  293. LPBYTE lpValueData = NULL;
  294. LPWSTR lpEnd;
  295. //
  296. // Gather information about this key
  297. //
  298. lResult = RegQueryInfoKey (hKey, NULL, NULL, NULL, &dwKeyCount, &dwKeySize, NULL,
  299. NULL, &dwNameSize, &dwDataSize, NULL, NULL);
  300. if (lResult != ERROR_SUCCESS)
  301. {
  302. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: Failed to query registry key information with %d"),
  303. lResult));
  304. return HRESULT_FROM_WIN32(lResult);
  305. }
  306. //
  307. // Allocate buffers to work with
  308. //
  309. lpValueName = (LPWSTR) LocalAlloc (LPTR, (dwNameSize + 1) * sizeof(WCHAR));
  310. if (!lpValueName)
  311. {
  312. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: Failed to alloc memory with %d"),
  313. GetLastError()));
  314. hr = HRESULT_FROM_WIN32(GetLastError());
  315. goto Exit;
  316. }
  317. lpValueData = (LPBYTE) LocalAlloc (LPTR, dwDataSize);
  318. if (!lpValueData)
  319. {
  320. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: Failed to alloc memory with %d"),
  321. GetLastError()));
  322. hr = HRESULT_FROM_WIN32(GetLastError());
  323. goto Exit;
  324. }
  325. //
  326. // Enumerate the values and write them to the file
  327. //
  328. dwIndex = 0;
  329. while (TRUE)
  330. {
  331. dwTemp1 = dwNameSize + 1;
  332. dwTemp2 = dwDataSize;
  333. *lpValueName = L'\0';
  334. lResult = RegEnumValueW (hKey, dwIndex, lpValueName, &dwTemp1, NULL,
  335. &dwType, lpValueData, &dwTemp2);
  336. if (lResult == ERROR_NO_MORE_ITEMS)
  337. break;
  338. if (lResult != ERROR_SUCCESS)
  339. {
  340. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: RegEnumValue failed with %d"),
  341. lResult));
  342. hr = HRESULT_FROM_WIN32(lResult);
  343. goto Exit;
  344. }
  345. hr = WriteValue(hFile, lpKeyName, lpValueName, dwType, dwTemp2, lpValueData);
  346. if (hr != S_OK)
  347. goto Exit;
  348. dwIndex++;
  349. }
  350. //
  351. // If dwIndex is 0, this is an empty key. We need to special case this
  352. // so the empty key is entered into the registry file when there are
  353. // no subkeys under it.
  354. //
  355. if ((dwIndex == 0) && (dwKeyCount == 0) && (*lpKeyName))
  356. {
  357. hr = WriteValue(hFile, lpKeyName, lpValueName, REG_NONE, 0, lpValueData);
  358. if (hr != S_OK)
  359. goto Exit;
  360. }
  361. LocalFree (lpValueName);
  362. lpValueName = NULL;
  363. LocalFree (lpValueData);
  364. lpValueData = NULL;
  365. //
  366. // Now process the sub keys
  367. //
  368. lpSubKeyName = (LPWSTR) LocalAlloc (LPTR, (dwKeySize + 1) * sizeof(WCHAR));
  369. if (!lpSubKeyName)
  370. {
  371. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: Failed to alloc memory with %d"),
  372. GetLastError()));
  373. hr = HRESULT_FROM_WIN32(GetLastError());
  374. goto Exit;
  375. }
  376. dwIndex = 0;
  377. if (*lpKeyName)
  378. lpEnd = CheckSlash (lpKeyName);
  379. else
  380. lpEnd = lpKeyName;
  381. while (TRUE)
  382. {
  383. dwTemp1 = dwKeySize + 1;
  384. lResult = RegEnumKeyEx (hKey, dwIndex, lpSubKeyName, &dwTemp1,
  385. NULL, NULL, NULL, NULL);
  386. if (lResult == ERROR_NO_MORE_ITEMS)
  387. break;
  388. if (lResult != ERROR_SUCCESS)
  389. {
  390. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: RegEnumKeyEx failed with %d"),
  391. lResult));
  392. hr = HRESULT_FROM_WIN32(lResult);
  393. goto Exit;
  394. }
  395. lstrcpy (lpEnd, lpSubKeyName);
  396. lResult = RegOpenKeyEx (hKey, lpSubKeyName, 0, KEY_READ, &hSubKey);
  397. if (lResult == ERROR_SUCCESS)
  398. {
  399. hr = ExportKey (hSubKey, hFile, lpKeyName);
  400. RegCloseKey (hSubKey);
  401. if (hr != S_OK)
  402. break;
  403. }
  404. else
  405. {
  406. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: RegOpenKeyEx failed with %d"),
  407. lResult));
  408. }
  409. dwIndex++;
  410. }
  411. Exit:
  412. if (lpValueName)
  413. LocalFree (lpValueName);
  414. if (lpValueData)
  415. LocalFree (lpValueData);
  416. if (lpSubKeyName)
  417. LocalFree (lpSubKeyName);
  418. return hr;
  419. }
  420. STDMETHODIMP CRegistryHive::WriteValue(HANDLE hFile, LPWSTR lpKeyName,
  421. LPWSTR lpValueName, DWORD dwType,
  422. DWORD dwDataLength, LPBYTE lpData)
  423. {
  424. HRESULT hr = S_OK;
  425. DWORD dwBytesWritten;
  426. DWORD dwTemp;
  427. //
  428. // Write the entry to the text file.
  429. //
  430. // Format:
  431. //
  432. // [keyname;valuename;type;datalength;data]
  433. //
  434. // open bracket
  435. if (!WriteFile (hFile, &g_cOpenBracket, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  436. dwBytesWritten != sizeof(WCHAR))
  437. {
  438. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write open bracket with %d"),
  439. GetLastError()));
  440. hr = HRESULT_FROM_WIN32(GetLastError());
  441. goto Exit;
  442. }
  443. // key name
  444. dwTemp = (lstrlen (lpKeyName) + 1) * sizeof (WCHAR);
  445. if (!WriteFile (hFile, lpKeyName, dwTemp, &dwBytesWritten, NULL) ||
  446. dwBytesWritten != dwTemp)
  447. {
  448. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write key name with %d"),
  449. GetLastError()));
  450. hr = HRESULT_FROM_WIN32(GetLastError());
  451. goto Exit;
  452. }
  453. // semicolon
  454. if (!WriteFile (hFile, &g_cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  455. dwBytesWritten != sizeof(WCHAR))
  456. {
  457. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write semicolon with %d"),
  458. GetLastError()));
  459. hr = HRESULT_FROM_WIN32(GetLastError());
  460. goto Exit;
  461. }
  462. // value name
  463. dwTemp = (lstrlen (lpValueName) + 1) * sizeof (WCHAR);
  464. if (!WriteFile (hFile, lpValueName, dwTemp, &dwBytesWritten, NULL) ||
  465. dwBytesWritten != dwTemp)
  466. {
  467. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write value name with %d"),
  468. GetLastError()));
  469. hr = HRESULT_FROM_WIN32(GetLastError());
  470. goto Exit;
  471. }
  472. // semicolon
  473. if (!WriteFile (hFile, &g_cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  474. dwBytesWritten != sizeof(WCHAR))
  475. {
  476. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write semicolon with %d"),
  477. GetLastError()));
  478. hr = HRESULT_FROM_WIN32(GetLastError());
  479. goto Exit;
  480. }
  481. // type
  482. if (!WriteFile (hFile, &dwType, sizeof(DWORD), &dwBytesWritten, NULL) ||
  483. dwBytesWritten != sizeof(DWORD))
  484. {
  485. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write data type with %d"),
  486. GetLastError()));
  487. hr = HRESULT_FROM_WIN32(GetLastError());
  488. goto Exit;
  489. }
  490. // semicolon
  491. if (!WriteFile (hFile, &g_cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  492. dwBytesWritten != sizeof(WCHAR))
  493. {
  494. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write semicolon with %d"),
  495. GetLastError()));
  496. hr = HRESULT_FROM_WIN32(GetLastError());
  497. goto Exit;
  498. }
  499. // data length
  500. if (!WriteFile (hFile, &dwDataLength, sizeof(DWORD), &dwBytesWritten, NULL) ||
  501. dwBytesWritten != sizeof(DWORD))
  502. {
  503. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write data type with %d"),
  504. GetLastError()));
  505. hr = HRESULT_FROM_WIN32(GetLastError());
  506. goto Exit;
  507. }
  508. // semicolon
  509. if (!WriteFile (hFile, &g_cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  510. dwBytesWritten != sizeof(WCHAR))
  511. {
  512. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write semicolon with %d"),
  513. GetLastError()));
  514. hr = HRESULT_FROM_WIN32(GetLastError());
  515. goto Exit;
  516. }
  517. // data
  518. if (!WriteFile (hFile, lpData, dwDataLength, &dwBytesWritten, NULL) ||
  519. dwBytesWritten != dwDataLength)
  520. {
  521. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write data with %d"),
  522. GetLastError()));
  523. hr = HRESULT_FROM_WIN32(GetLastError());
  524. goto Exit;
  525. }
  526. // close bracket
  527. if (!WriteFile (hFile, &g_cCloseBracket, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  528. dwBytesWritten != sizeof(WCHAR))
  529. {
  530. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write close bracket with %d"),
  531. GetLastError()));
  532. hr = HRESULT_FROM_WIN32(GetLastError());
  533. goto Exit;
  534. }
  535. DebugMsg((DM_VERBOSE, TEXT("CRegistryHive::WriteValue: Successfully wrote: %s\\%s"),
  536. lpKeyName, lpValueName));
  537. Exit:
  538. return hr;
  539. }
  540. STDMETHODIMP CRegistryHive::Load(VOID)
  541. {
  542. HANDLE hFile;
  543. HRESULT hr = S_OK;
  544. DWORD dwTemp, dwBytesRead, dwType, dwDataLength, dwDisp;
  545. LPWSTR lpKeyName, lpValueName, lpTemp;
  546. LPBYTE lpData;
  547. WCHAR chTemp;
  548. HKEY hSubKey;
  549. LONG lResult;
  550. //
  551. // Check parameters
  552. //
  553. if (!m_hKey || !m_lpFileName || !m_lpKeyName)
  554. {
  555. return E_INVALIDARG;
  556. }
  557. //
  558. // Open the registry file
  559. //
  560. hFile = CreateFile (m_lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
  561. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  562. NULL);
  563. if (hFile == INVALID_HANDLE_VALUE) {
  564. if (GetLastError() == ERROR_FILE_NOT_FOUND)
  565. {
  566. return S_OK;
  567. }
  568. else
  569. {
  570. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: CreateFile failed for <%s> with %d"),
  571. m_lpFileName, GetLastError()));
  572. return (HRESULT_FROM_WIN32(GetLastError()));
  573. }
  574. }
  575. //
  576. // Allocate buffers to hold the keyname, valuename, and data
  577. //
  578. lpKeyName = (LPWSTR) LocalAlloc (LPTR, MAX_KEYNAME_SIZE * sizeof(WCHAR));
  579. if (!lpKeyName)
  580. {
  581. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to allocate memory with %d"),
  582. GetLastError()));
  583. CloseHandle (hFile);
  584. return (HRESULT_FROM_WIN32(GetLastError()));
  585. }
  586. lpValueName = (LPWSTR) LocalAlloc (LPTR, MAX_VALUENAME_SIZE * sizeof(WCHAR));
  587. if (!lpValueName)
  588. {
  589. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to allocate memory with %d"),
  590. GetLastError()));
  591. LocalFree (lpKeyName);
  592. CloseHandle (hFile);
  593. return (HRESULT_FROM_WIN32(GetLastError()));
  594. }
  595. //
  596. // Read the header block
  597. //
  598. // 2 DWORDS, signature (PReg) and version number and 2 newlines
  599. //
  600. if (!ReadFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesRead, NULL) ||
  601. dwBytesRead != sizeof(dwTemp))
  602. {
  603. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read signature with %d"),
  604. GetLastError()));
  605. hr = HRESULT_FROM_WIN32(GetLastError());
  606. goto Exit;
  607. }
  608. if (dwTemp != REGFILE_SIGNATURE)
  609. {
  610. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Invalid file signature")));
  611. hr = E_FAIL;
  612. goto Exit;
  613. }
  614. if (!ReadFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesRead, NULL) ||
  615. dwBytesRead != sizeof(dwTemp))
  616. {
  617. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read version number with %d"),
  618. GetLastError()));
  619. hr = HRESULT_FROM_WIN32(GetLastError());
  620. goto Exit;
  621. }
  622. if (dwTemp != REGISTRY_FILE_VERSION)
  623. {
  624. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Invalid file version")));
  625. hr = E_FAIL;
  626. goto Exit;
  627. }
  628. //
  629. // Read the data
  630. //
  631. while (TRUE)
  632. {
  633. //
  634. // Read the first character. It will either be a [ or the end
  635. // of the file.
  636. //
  637. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  638. {
  639. if (GetLastError() != ERROR_HANDLE_EOF)
  640. {
  641. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read first character with %d"),
  642. GetLastError()));
  643. hr = HRESULT_FROM_WIN32(GetLastError());
  644. }
  645. goto Exit;
  646. }
  647. if ((dwBytesRead == 0) || (chTemp != L'['))
  648. {
  649. goto Exit;
  650. }
  651. //
  652. // Read the keyname
  653. //
  654. lpTemp = lpKeyName;
  655. while (TRUE)
  656. {
  657. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  658. {
  659. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read keyname character with %d"),
  660. GetLastError()));
  661. hr = HRESULT_FROM_WIN32(GetLastError());
  662. goto Exit;
  663. }
  664. *lpTemp++ = chTemp;
  665. if (chTemp == TEXT('\0'))
  666. break;
  667. }
  668. //
  669. // Read the semi-colon
  670. //
  671. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  672. {
  673. if (GetLastError() != ERROR_HANDLE_EOF)
  674. {
  675. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read first character with %d"),
  676. GetLastError()));
  677. hr = HRESULT_FROM_WIN32(GetLastError());
  678. }
  679. goto Exit;
  680. }
  681. if ((dwBytesRead == 0) || (chTemp != L';'))
  682. {
  683. goto Exit;
  684. }
  685. //
  686. // Read the valuename
  687. //
  688. lpTemp = lpValueName;
  689. while (TRUE)
  690. {
  691. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  692. {
  693. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read valuename character with %d"),
  694. GetLastError()));
  695. hr = HRESULT_FROM_WIN32(GetLastError());
  696. goto Exit;
  697. }
  698. *lpTemp++ = chTemp;
  699. if (chTemp == TEXT('\0'))
  700. break;
  701. }
  702. //
  703. // Read the semi-colon
  704. //
  705. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  706. {
  707. if (GetLastError() != ERROR_HANDLE_EOF)
  708. {
  709. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read first character with %d"),
  710. GetLastError()));
  711. hr = HRESULT_FROM_WIN32(GetLastError());
  712. }
  713. goto Exit;
  714. }
  715. if ((dwBytesRead == 0) || (chTemp != L';'))
  716. {
  717. goto Exit;
  718. }
  719. //
  720. // Read the type
  721. //
  722. if (!ReadFile (hFile, &dwType, sizeof(DWORD), &dwBytesRead, NULL))
  723. {
  724. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read type with %d"),
  725. GetLastError()));
  726. hr = HRESULT_FROM_WIN32(GetLastError());
  727. goto Exit;
  728. }
  729. //
  730. // Skip semicolon
  731. //
  732. if (!ReadFile (hFile, &dwTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  733. {
  734. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to skip semicolon with %d"),
  735. GetLastError()));
  736. hr = HRESULT_FROM_WIN32(GetLastError());
  737. goto Exit;
  738. }
  739. //
  740. // Read the data length
  741. //
  742. if (!ReadFile (hFile, &dwDataLength, sizeof(DWORD), &dwBytesRead, NULL))
  743. {
  744. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to data length with %d"),
  745. GetLastError()));
  746. hr = HRESULT_FROM_WIN32(GetLastError());
  747. goto Exit;
  748. }
  749. //
  750. // Skip semicolon
  751. //
  752. if (!ReadFile (hFile, &dwTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  753. {
  754. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to skip semicolon with %d"),
  755. GetLastError()));
  756. hr = HRESULT_FROM_WIN32(GetLastError());
  757. goto Exit;
  758. }
  759. //
  760. // Allocate memory for data
  761. //
  762. lpData = (LPBYTE) LocalAlloc (LPTR, dwDataLength);
  763. if (!lpData)
  764. {
  765. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to allocate memory for data with %d"),
  766. GetLastError()));
  767. hr = HRESULT_FROM_WIN32(GetLastError());
  768. goto Exit;
  769. }
  770. //
  771. // Read data
  772. //
  773. if (!ReadFile (hFile, lpData, dwDataLength, &dwBytesRead, NULL))
  774. {
  775. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read data with %d"),
  776. GetLastError()));
  777. hr = HRESULT_FROM_WIN32(GetLastError());
  778. goto Exit;
  779. }
  780. //
  781. // Skip closing bracket
  782. //
  783. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  784. {
  785. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to skip closing bracket with %d"),
  786. GetLastError()));
  787. hr = HRESULT_FROM_WIN32(GetLastError());
  788. goto Exit;
  789. }
  790. if (chTemp != L']')
  791. {
  792. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Expected to find ], but found %c"),
  793. chTemp));
  794. hr = E_FAIL;
  795. goto Exit;
  796. }
  797. //
  798. // Save registry value
  799. //
  800. lResult = RegCreateKeyEx (m_hKey, lpKeyName, 0, NULL, REG_OPTION_NON_VOLATILE,
  801. KEY_WRITE, NULL, &hSubKey, &dwDisp);
  802. if (lResult == ERROR_SUCCESS)
  803. {
  804. if ((dwType == REG_NONE) && (dwDataLength == 0) &&
  805. (*lpValueName == L'\0'))
  806. {
  807. lResult = ERROR_SUCCESS;
  808. }
  809. else
  810. {
  811. lResult = RegSetValueEx (hSubKey, lpValueName, 0, dwType,
  812. lpData, dwDataLength);
  813. }
  814. RegCloseKey (hSubKey);
  815. if (lResult != ERROR_SUCCESS)
  816. {
  817. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to set value <%s> with %d"),
  818. lpValueName, lResult));
  819. hr = HRESULT_FROM_WIN32(lResult);
  820. LocalFree (lpData);
  821. goto Exit;
  822. }
  823. }
  824. else
  825. {
  826. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to open key <%s> with %d"),
  827. lpKeyName, lResult));
  828. hr = HRESULT_FROM_WIN32(lResult);
  829. LocalFree (lpData);
  830. goto Exit;
  831. }
  832. LocalFree (lpData);
  833. }
  834. Exit:
  835. //
  836. // Finished
  837. //
  838. CloseHandle (hFile);
  839. LocalFree (lpKeyName);
  840. LocalFree (lpValueName);
  841. return hr;
  842. }
  843. STDMETHODIMP CRegistryHive::IsRegistryEmpty(BOOL *bEmpty)
  844. {
  845. HRESULT hr = ERROR_SUCCESS;
  846. DWORD dwKeys, dwValues;
  847. LONG lResult;
  848. if (!m_hKey)
  849. {
  850. DebugMsg((DM_WARNING, TEXT("CRegistryHive::IsRegistryEmpty: registry key not open yet")));
  851. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  852. }
  853. lResult = RegQueryInfoKey(m_hKey, NULL, NULL, NULL, &dwKeys, NULL, NULL, &dwValues,
  854. NULL, NULL, NULL, NULL);
  855. if (lResult != ERROR_SUCCESS)
  856. {
  857. DebugMsg((DM_WARNING, TEXT("CRegistryHive::IsRegistryEmpty: RegQueryInfoKey failed with %d"),
  858. lResult));
  859. return HRESULT_FROM_WIN32(lResult);
  860. }
  861. if ((dwKeys == 0) && (dwValues == 0))
  862. {
  863. *bEmpty = TRUE;
  864. DebugMsg((DM_VERBOSE, TEXT("CRegistryHive::IsRegistryEmpty: registry key is empty")));
  865. }
  866. else
  867. {
  868. *bEmpty = FALSE;
  869. DebugMsg((DM_VERBOSE, TEXT("CRegistryHive::IsRegistryEmpty: registry key is not empty. Keys = %d, Values = %d"),
  870. dwKeys, dwValues));
  871. }
  872. return S_OK;
  873. }