Leaked source code of windows server 2003
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.

1202 lines
32 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. hr = StringCchCopy (szBuffer, ARRAYSIZE(szBuffer), TEMP_LOCATION);
  133. if (SUCCEEDED(hr))
  134. {
  135. hr = StringCchCat (szBuffer, ARRAYSIZE(szBuffer), TEXT("\\"));
  136. }
  137. if (SUCCEEDED(hr))
  138. {
  139. hr = StringCchCat (szBuffer, ARRAYSIZE(szBuffer), lpKeyName);
  140. }
  141. if (FAILED(hr))
  142. {
  143. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Failed to copyt registry name with 0x%x"), hr));
  144. return hr;
  145. }
  146. lResult = RegCreateKeyEx (HKEY_CURRENT_USER, szBuffer, 0, NULL,
  147. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  148. NULL, &m_hKey, &dwDisp);
  149. if (lResult != ERROR_SUCCESS)
  150. {
  151. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Failed to open registry key with %d"), lResult));
  152. return (HRESULT_FROM_WIN32(lResult));
  153. }
  154. //
  155. // Store the keyname
  156. //
  157. ULONG ulNoChars;
  158. ulNoChars = lstrlen(szBuffer) + 1;
  159. m_lpKeyName = (LPTSTR) LocalAlloc (LPTR, ulNoChars * sizeof(TCHAR));
  160. if (!m_lpKeyName)
  161. {
  162. RegCloseKey (m_hKey);
  163. m_hKey = NULL;
  164. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Failed to allocate memory for KeyName")));
  165. return (HRESULT_FROM_WIN32(GetLastError()));
  166. }
  167. hr = StringCchCopy (m_lpKeyName, ulNoChars, szBuffer);
  168. ASSERT(SUCCEEDED(hr));
  169. //
  170. // Store the filename
  171. //
  172. ulNoChars = lstrlen(lpFileName) + 1;
  173. m_lpFileName = (LPTSTR) LocalAlloc (LPTR, ulNoChars * sizeof(TCHAR));
  174. if (!m_lpFileName)
  175. {
  176. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Failed to allocate memory for filename")));
  177. return (HRESULT_FROM_WIN32(GetLastError()));
  178. }
  179. hr = StringCchCopy (m_lpFileName, ulNoChars, lpFileName);
  180. ASSERT(SUCCEEDED(hr));
  181. //
  182. // Store the event name
  183. //
  184. hr = StringCchCopy (szBuffer, ARRAYSIZE(szBuffer), REG_EVENT_NAME);
  185. if (SUCCEEDED(hr))
  186. {
  187. hr = StringCchCat (szBuffer, ARRAYSIZE(szBuffer), lpKeyName);
  188. }
  189. if (FAILED(hr))
  190. {
  191. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Failed to copy event name")));
  192. return hr;
  193. }
  194. ulNoChars = lstrlen(szBuffer) + 1;
  195. m_lpEventName = (LPTSTR) LocalAlloc (LPTR, ulNoChars * sizeof(TCHAR));
  196. if (!m_lpEventName)
  197. {
  198. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Failed to allocate memory for filename")));
  199. return (HRESULT_FROM_WIN32(GetLastError()));
  200. }
  201. hr = StringCchCopy (m_lpEventName, ulNoChars, szBuffer);
  202. ASSERT(SUCCEEDED(hr));
  203. //
  204. // Load the file if it exists
  205. //
  206. hr = Load();
  207. if (FAILED(hr))
  208. {
  209. return hr;
  210. }
  211. //
  212. // Create the registry event
  213. //
  214. m_hEvent = CreateEvent (NULL, FALSE, FALSE, m_lpEventName);
  215. if (!m_hEvent)
  216. {
  217. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Initialize: Failed to create registry event with %d"),
  218. GetLastError()));
  219. return (HRESULT_FROM_WIN32(GetLastError()));
  220. }
  221. return (S_OK);
  222. }
  223. STDMETHODIMP CRegistryHive::GetHKey(HKEY *hKey)
  224. {
  225. HRESULT hr = E_FAIL;
  226. *hKey = NULL;
  227. if (m_hKey)
  228. {
  229. if (DuplicateHandle (GetCurrentProcess(),
  230. (HANDLE)m_hKey,
  231. GetCurrentProcess(),
  232. (LPHANDLE) hKey, 0,
  233. TRUE, DUPLICATE_SAME_ACCESS))
  234. {
  235. hr = S_OK;
  236. }
  237. else
  238. {
  239. hr = HRESULT_FROM_WIN32(GetLastError());
  240. }
  241. }
  242. return hr;
  243. }
  244. STDMETHODIMP CRegistryHive::Save(VOID)
  245. {
  246. HANDLE hFile;
  247. HRESULT hr;
  248. DWORD dwTemp, dwBytesWritten;
  249. LPWSTR lpKeyName;
  250. //
  251. // Check parameters
  252. //
  253. if (!m_hKey || !m_lpFileName || !m_lpKeyName)
  254. {
  255. return E_INVALIDARG;
  256. }
  257. //
  258. // Allocate a buffer to hold the keyname
  259. //
  260. lpKeyName = (LPWSTR) LocalAlloc (LPTR, MAX_KEYNAME_SIZE * sizeof(WCHAR));
  261. if (!lpKeyName)
  262. {
  263. return (HRESULT_FROM_WIN32(GetLastError()));
  264. }
  265. //
  266. // Create the output file
  267. //
  268. DISABLE_32BIT_FILE_REDIRECTION_ON_64BIT(m_lpFileName);
  269. hFile = CreateFile (m_lpFileName, GENERIC_WRITE, 0, NULL,
  270. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
  271. NULL);
  272. ENABLE_32BIT_FILE_REDIRECTION_ON_64BIT;
  273. if (hFile == INVALID_HANDLE_VALUE) {
  274. LocalFree (lpKeyName);
  275. return (HRESULT_FROM_WIN32(GetLastError()));
  276. }
  277. //
  278. // Write the header block
  279. //
  280. // 2 DWORDS, signature (PReg) and version number and 2 newlines
  281. //
  282. dwTemp = REGFILE_SIGNATURE;
  283. if (!WriteFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesWritten, NULL) ||
  284. dwBytesWritten != sizeof(dwTemp))
  285. {
  286. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Save: Failed to write signature with %d"),
  287. GetLastError()));
  288. hr = HRESULT_FROM_WIN32(GetLastError());
  289. goto Exit;
  290. }
  291. dwTemp = REGISTRY_FILE_VERSION;
  292. if (!WriteFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesWritten, NULL) ||
  293. dwBytesWritten != sizeof(dwTemp))
  294. {
  295. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Save: Failed to write version number with %d"),
  296. GetLastError()));
  297. hr = HRESULT_FROM_WIN32(GetLastError());
  298. goto Exit;
  299. }
  300. //
  301. // Exports the values / keys
  302. //
  303. hr = ExportKey (m_hKey, hFile, lpKeyName, MAX_KEYNAME_SIZE);
  304. Exit:
  305. //
  306. // Finished
  307. //
  308. CloseHandle (hFile);
  309. LocalFree (lpKeyName);
  310. return hr;
  311. }
  312. STDMETHODIMP CRegistryHive::ExportKey(HKEY hKey, HANDLE hFile, LPWSTR lpKeyName, ULONG ulKeySize)
  313. {
  314. HRESULT hr = S_OK;
  315. DWORD dwBytesWritten, dwNameSize, dwDataSize, dwKeySize;
  316. DWORD dwIndex, dwTemp1, dwTemp2, dwType, dwKeyCount = 0;
  317. LONG lResult;
  318. HKEY hSubKey;
  319. LPWSTR lpValueName = NULL;
  320. LPWSTR lpSubKeyName = NULL;
  321. LPBYTE lpValueData = NULL;
  322. LPWSTR lpEnd;
  323. //
  324. // Gather information about this key
  325. //
  326. lResult = RegQueryInfoKey (hKey, NULL, NULL, NULL, &dwKeyCount, &dwKeySize, NULL,
  327. NULL, &dwNameSize, &dwDataSize, NULL, NULL);
  328. if (lResult != ERROR_SUCCESS)
  329. {
  330. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: Failed to query registry key information with %d"),
  331. lResult));
  332. return HRESULT_FROM_WIN32(lResult);
  333. }
  334. //
  335. // Allocate buffers to work with
  336. //
  337. lpValueName = (LPWSTR) LocalAlloc (LPTR, (dwNameSize + 1) * sizeof(WCHAR));
  338. if (!lpValueName)
  339. {
  340. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: Failed to alloc memory with %d"),
  341. GetLastError()));
  342. hr = HRESULT_FROM_WIN32(GetLastError());
  343. goto Exit;
  344. }
  345. lpValueData = (LPBYTE) LocalAlloc (LPTR, dwDataSize);
  346. if (!lpValueData)
  347. {
  348. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: Failed to alloc memory with %d"),
  349. GetLastError()));
  350. hr = HRESULT_FROM_WIN32(GetLastError());
  351. goto Exit;
  352. }
  353. //
  354. // Enumerate the values and write them to the file
  355. //
  356. dwIndex = 0;
  357. while (TRUE)
  358. {
  359. dwTemp1 = dwNameSize + 1;
  360. dwTemp2 = dwDataSize;
  361. *lpValueName = L'\0';
  362. lResult = RegEnumValueW (hKey, dwIndex, lpValueName, &dwTemp1, NULL,
  363. &dwType, lpValueData, &dwTemp2);
  364. if (lResult == ERROR_NO_MORE_ITEMS)
  365. break;
  366. if (lResult != ERROR_SUCCESS)
  367. {
  368. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: RegEnumValue failed with %d"),
  369. lResult));
  370. hr = HRESULT_FROM_WIN32(lResult);
  371. goto Exit;
  372. }
  373. hr = WriteValue(hFile, lpKeyName, lpValueName, dwType, dwTemp2, lpValueData);
  374. if (hr != S_OK)
  375. goto Exit;
  376. dwIndex++;
  377. }
  378. //
  379. // If dwIndex is 0, this is an empty key. We need to special case this
  380. // so the empty key is entered into the registry file when there are
  381. // no subkeys under it.
  382. //
  383. if ((dwIndex == 0) && (dwKeyCount == 0) && (*lpKeyName))
  384. {
  385. hr = WriteValue(hFile, lpKeyName, lpValueName, REG_NONE, 0, lpValueData);
  386. if (hr != S_OK)
  387. goto Exit;
  388. }
  389. LocalFree (lpValueName);
  390. lpValueName = NULL;
  391. LocalFree (lpValueData);
  392. lpValueData = NULL;
  393. //
  394. // Now process the sub keys
  395. //
  396. lpSubKeyName = (LPWSTR) LocalAlloc (LPTR, (dwKeySize + 1) * sizeof(WCHAR));
  397. if (!lpSubKeyName)
  398. {
  399. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: Failed to alloc memory with %d"),
  400. GetLastError()));
  401. hr = HRESULT_FROM_WIN32(GetLastError());
  402. goto Exit;
  403. }
  404. dwIndex = 0;
  405. ULONG ulNoChars;
  406. if (*lpKeyName)
  407. {
  408. lpEnd = CheckSlash (lpKeyName);
  409. ulNoChars = ulKeySize - lstrlen(lpKeyName);
  410. }
  411. else
  412. {
  413. lpEnd = lpKeyName;
  414. ulNoChars = ulKeySize;
  415. }
  416. while (TRUE)
  417. {
  418. dwTemp1 = dwKeySize + 1;
  419. lResult = RegEnumKeyEx (hKey, dwIndex, lpSubKeyName, &dwTemp1,
  420. NULL, NULL, NULL, NULL);
  421. if (lResult == ERROR_NO_MORE_ITEMS)
  422. break;
  423. if (lResult != ERROR_SUCCESS)
  424. {
  425. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: RegEnumKeyEx failed with %d"),
  426. lResult));
  427. hr = HRESULT_FROM_WIN32(lResult);
  428. goto Exit;
  429. }
  430. hr = StringCchCopy (lpEnd, ulNoChars, lpSubKeyName);
  431. if (FAILED(hr))
  432. {
  433. break;
  434. }
  435. lResult = RegOpenKeyEx (hKey, lpSubKeyName, 0, KEY_READ, &hSubKey);
  436. if (lResult == ERROR_SUCCESS)
  437. {
  438. hr = ExportKey (hSubKey, hFile, lpKeyName, ulKeySize);
  439. RegCloseKey (hSubKey);
  440. if (hr != S_OK)
  441. break;
  442. }
  443. else
  444. {
  445. DebugMsg((DM_WARNING, TEXT("CRegistryHive::ExportKey: RegOpenKeyEx failed with %d"),
  446. lResult));
  447. }
  448. dwIndex++;
  449. }
  450. Exit:
  451. if (lpValueName)
  452. LocalFree (lpValueName);
  453. if (lpValueData)
  454. LocalFree (lpValueData);
  455. if (lpSubKeyName)
  456. LocalFree (lpSubKeyName);
  457. return hr;
  458. }
  459. STDMETHODIMP CRegistryHive::WriteValue(HANDLE hFile, LPWSTR lpKeyName,
  460. LPWSTR lpValueName, DWORD dwType,
  461. DWORD dwDataLength, LPBYTE lpData)
  462. {
  463. HRESULT hr = S_OK;
  464. DWORD dwBytesWritten;
  465. DWORD dwTemp;
  466. //
  467. // Write the entry to the text file.
  468. //
  469. // Format:
  470. //
  471. // [keyname;valuename;type;datalength;data]
  472. //
  473. // open bracket
  474. if (!WriteFile (hFile, &g_cOpenBracket, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  475. dwBytesWritten != sizeof(WCHAR))
  476. {
  477. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write open bracket with %d"),
  478. GetLastError()));
  479. hr = HRESULT_FROM_WIN32(GetLastError());
  480. goto Exit;
  481. }
  482. // key name
  483. dwTemp = (lstrlen (lpKeyName) + 1) * sizeof (WCHAR);
  484. if (!WriteFile (hFile, lpKeyName, dwTemp, &dwBytesWritten, NULL) ||
  485. dwBytesWritten != dwTemp)
  486. {
  487. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write key name with %d"),
  488. GetLastError()));
  489. hr = HRESULT_FROM_WIN32(GetLastError());
  490. goto Exit;
  491. }
  492. // semicolon
  493. if (!WriteFile (hFile, &g_cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  494. dwBytesWritten != sizeof(WCHAR))
  495. {
  496. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write semicolon with %d"),
  497. GetLastError()));
  498. hr = HRESULT_FROM_WIN32(GetLastError());
  499. goto Exit;
  500. }
  501. // value name
  502. dwTemp = (lstrlen (lpValueName) + 1) * sizeof (WCHAR);
  503. if (!WriteFile (hFile, lpValueName, dwTemp, &dwBytesWritten, NULL) ||
  504. dwBytesWritten != dwTemp)
  505. {
  506. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write value name with %d"),
  507. GetLastError()));
  508. hr = HRESULT_FROM_WIN32(GetLastError());
  509. goto Exit;
  510. }
  511. // semicolon
  512. if (!WriteFile (hFile, &g_cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  513. dwBytesWritten != sizeof(WCHAR))
  514. {
  515. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write semicolon with %d"),
  516. GetLastError()));
  517. hr = HRESULT_FROM_WIN32(GetLastError());
  518. goto Exit;
  519. }
  520. // type
  521. if (!WriteFile (hFile, &dwType, sizeof(DWORD), &dwBytesWritten, NULL) ||
  522. dwBytesWritten != sizeof(DWORD))
  523. {
  524. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write data type with %d"),
  525. GetLastError()));
  526. hr = HRESULT_FROM_WIN32(GetLastError());
  527. goto Exit;
  528. }
  529. // semicolon
  530. if (!WriteFile (hFile, &g_cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  531. dwBytesWritten != sizeof(WCHAR))
  532. {
  533. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write semicolon with %d"),
  534. GetLastError()));
  535. hr = HRESULT_FROM_WIN32(GetLastError());
  536. goto Exit;
  537. }
  538. // data length
  539. if (!WriteFile (hFile, &dwDataLength, sizeof(DWORD), &dwBytesWritten, NULL) ||
  540. dwBytesWritten != sizeof(DWORD))
  541. {
  542. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write data type with %d"),
  543. GetLastError()));
  544. hr = HRESULT_FROM_WIN32(GetLastError());
  545. goto Exit;
  546. }
  547. // semicolon
  548. if (!WriteFile (hFile, &g_cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  549. dwBytesWritten != sizeof(WCHAR))
  550. {
  551. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write semicolon with %d"),
  552. GetLastError()));
  553. hr = HRESULT_FROM_WIN32(GetLastError());
  554. goto Exit;
  555. }
  556. // data
  557. if (!WriteFile (hFile, lpData, dwDataLength, &dwBytesWritten, NULL) ||
  558. dwBytesWritten != dwDataLength)
  559. {
  560. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write data with %d"),
  561. GetLastError()));
  562. hr = HRESULT_FROM_WIN32(GetLastError());
  563. goto Exit;
  564. }
  565. // close bracket
  566. if (!WriteFile (hFile, &g_cCloseBracket, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  567. dwBytesWritten != sizeof(WCHAR))
  568. {
  569. DebugMsg((DM_WARNING, TEXT("CRegistryHive::WriteValue: Failed to write close bracket with %d"),
  570. GetLastError()));
  571. hr = HRESULT_FROM_WIN32(GetLastError());
  572. goto Exit;
  573. }
  574. DebugMsg((DM_VERBOSE, TEXT("CRegistryHive::WriteValue: Successfully wrote: %s\\%s"),
  575. lpKeyName, lpValueName));
  576. Exit:
  577. return hr;
  578. }
  579. STDMETHODIMP CRegistryHive::Load(VOID)
  580. {
  581. HANDLE hFile;
  582. HRESULT hr = S_OK;
  583. DWORD dwTemp, dwBytesRead, dwType, dwDataLength, dwDisp;
  584. LPWSTR lpKeyName, lpValueName, lpTemp;
  585. LPBYTE lpData;
  586. WCHAR chTemp;
  587. HKEY hSubKey;
  588. LONG lResult;
  589. //
  590. // Check parameters
  591. //
  592. if (!m_hKey || !m_lpFileName || !m_lpKeyName)
  593. {
  594. return E_INVALIDARG;
  595. }
  596. //
  597. // Open the registry file
  598. //
  599. DISABLE_32BIT_FILE_REDIRECTION_ON_64BIT(m_lpFileName);
  600. hFile = CreateFile (m_lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
  601. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  602. NULL);
  603. ENABLE_32BIT_FILE_REDIRECTION_ON_64BIT;
  604. if (hFile == INVALID_HANDLE_VALUE) {
  605. if (GetLastError() == ERROR_FILE_NOT_FOUND)
  606. {
  607. return S_OK;
  608. }
  609. else
  610. {
  611. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: CreateFile failed for <%s> with %d"),
  612. m_lpFileName, GetLastError()));
  613. return (HRESULT_FROM_WIN32(GetLastError()));
  614. }
  615. }
  616. //
  617. // Allocate buffers to hold the keyname, valuename, and data
  618. //
  619. lpKeyName = (LPWSTR) LocalAlloc (LPTR, MAX_KEYNAME_SIZE * sizeof(WCHAR));
  620. if (!lpKeyName)
  621. {
  622. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to allocate memory with %d"),
  623. GetLastError()));
  624. CloseHandle (hFile);
  625. return (HRESULT_FROM_WIN32(GetLastError()));
  626. }
  627. lpValueName = (LPWSTR) LocalAlloc (LPTR, MAX_VALUENAME_SIZE * sizeof(WCHAR));
  628. if (!lpValueName)
  629. {
  630. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to allocate memory with %d"),
  631. GetLastError()));
  632. LocalFree (lpKeyName);
  633. CloseHandle (hFile);
  634. return (HRESULT_FROM_WIN32(GetLastError()));
  635. }
  636. //
  637. // Read the header block
  638. //
  639. // 2 DWORDS, signature (PReg) and version number and 2 newlines
  640. //
  641. if (!ReadFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesRead, NULL) ||
  642. dwBytesRead != sizeof(dwTemp))
  643. {
  644. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read signature with %d"),
  645. GetLastError()));
  646. hr = HRESULT_FROM_WIN32(GetLastError());
  647. goto Exit;
  648. }
  649. if (dwTemp != REGFILE_SIGNATURE)
  650. {
  651. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Invalid file signature")));
  652. hr = E_FAIL;
  653. goto Exit;
  654. }
  655. if (!ReadFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesRead, NULL) ||
  656. dwBytesRead != sizeof(dwTemp))
  657. {
  658. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read version number with %d"),
  659. GetLastError()));
  660. hr = HRESULT_FROM_WIN32(GetLastError());
  661. goto Exit;
  662. }
  663. if (dwTemp != REGISTRY_FILE_VERSION)
  664. {
  665. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Invalid file version")));
  666. hr = E_FAIL;
  667. goto Exit;
  668. }
  669. //
  670. // Read the data
  671. //
  672. while (TRUE)
  673. {
  674. //
  675. // Read the first character. It will either be a [ or the end
  676. // of the file.
  677. //
  678. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  679. {
  680. if (GetLastError() != ERROR_HANDLE_EOF)
  681. {
  682. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read first character with %d"),
  683. GetLastError()));
  684. hr = HRESULT_FROM_WIN32(GetLastError());
  685. }
  686. goto Exit;
  687. }
  688. if ((dwBytesRead == 0) || (chTemp != L'['))
  689. {
  690. goto Exit;
  691. }
  692. //
  693. // Read the keyname
  694. //
  695. lpTemp = lpKeyName;
  696. DWORD dwTempLen = 0;
  697. while (TRUE)
  698. {
  699. if ( dwTempLen == MAX_KEYNAME_SIZE )
  700. {
  701. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Keyname is bigger than MAX_KEYNAME_SIZE (%d)"), MAX_KEYNAME_SIZE));
  702. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  703. goto Exit;
  704. }
  705. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  706. {
  707. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read keyname character with %d"),
  708. GetLastError()));
  709. hr = HRESULT_FROM_WIN32(GetLastError());
  710. goto Exit;
  711. }
  712. *lpTemp++ = chTemp;
  713. dwTempLen++;
  714. if (chTemp == TEXT('\0'))
  715. break;
  716. }
  717. //
  718. // Read the semi-colon
  719. //
  720. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  721. {
  722. if (GetLastError() != ERROR_HANDLE_EOF)
  723. {
  724. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read first character with %d"),
  725. GetLastError()));
  726. hr = HRESULT_FROM_WIN32(GetLastError());
  727. }
  728. goto Exit;
  729. }
  730. if ((dwBytesRead == 0) || (chTemp != L';'))
  731. {
  732. goto Exit;
  733. }
  734. //
  735. // Read the valuename
  736. //
  737. lpTemp = lpValueName;
  738. dwTempLen = 0;
  739. while (TRUE)
  740. {
  741. if ( dwTempLen == MAX_VALUENAME_SIZE )
  742. {
  743. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Valuename is bigger than MAX_VALUENAME_SIZE (%d)"), MAX_VALUENAME_SIZE));
  744. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  745. goto Exit;
  746. }
  747. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  748. {
  749. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read valuename character with %d"),
  750. GetLastError()));
  751. hr = HRESULT_FROM_WIN32(GetLastError());
  752. goto Exit;
  753. }
  754. *lpTemp++ = chTemp;
  755. dwTempLen++;
  756. if (chTemp == TEXT('\0'))
  757. break;
  758. }
  759. //
  760. // Read the semi-colon
  761. //
  762. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  763. {
  764. if (GetLastError() != ERROR_HANDLE_EOF)
  765. {
  766. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read first character with %d"),
  767. GetLastError()));
  768. hr = HRESULT_FROM_WIN32(GetLastError());
  769. }
  770. goto Exit;
  771. }
  772. if ((dwBytesRead == 0) || (chTemp != L';'))
  773. {
  774. goto Exit;
  775. }
  776. //
  777. // Read the type
  778. //
  779. if (!ReadFile (hFile, &dwType, sizeof(DWORD), &dwBytesRead, NULL))
  780. {
  781. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read type with %d"),
  782. GetLastError()));
  783. hr = HRESULT_FROM_WIN32(GetLastError());
  784. goto Exit;
  785. }
  786. //
  787. // Skip semicolon
  788. //
  789. if (!ReadFile (hFile, &dwTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  790. {
  791. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to skip semicolon with %d"),
  792. GetLastError()));
  793. hr = HRESULT_FROM_WIN32(GetLastError());
  794. goto Exit;
  795. }
  796. //
  797. // Read the data length
  798. //
  799. if (!ReadFile (hFile, &dwDataLength, sizeof(DWORD), &dwBytesRead, NULL))
  800. {
  801. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to data length with %d"),
  802. GetLastError()));
  803. hr = HRESULT_FROM_WIN32(GetLastError());
  804. goto Exit;
  805. }
  806. //
  807. // Skip semicolon
  808. //
  809. if (!ReadFile (hFile, &dwTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  810. {
  811. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to skip semicolon with %d"),
  812. GetLastError()));
  813. hr = HRESULT_FROM_WIN32(GetLastError());
  814. goto Exit;
  815. }
  816. //
  817. // Allocate memory for data
  818. //
  819. lpData = (LPBYTE) LocalAlloc (LPTR, dwDataLength);
  820. if (!lpData)
  821. {
  822. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to allocate memory for data with %d"),
  823. GetLastError()));
  824. hr = HRESULT_FROM_WIN32(GetLastError());
  825. goto Exit;
  826. }
  827. //
  828. // Read data
  829. //
  830. if (!ReadFile (hFile, lpData, dwDataLength, &dwBytesRead, NULL))
  831. {
  832. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to read data with %d"),
  833. GetLastError()));
  834. hr = HRESULT_FROM_WIN32(GetLastError());
  835. goto Exit;
  836. }
  837. //
  838. // Skip closing bracket
  839. //
  840. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  841. {
  842. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to skip closing bracket with %d"),
  843. GetLastError()));
  844. hr = HRESULT_FROM_WIN32(GetLastError());
  845. goto Exit;
  846. }
  847. if (chTemp != L']')
  848. {
  849. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Expected to find ], but found %c"),
  850. chTemp));
  851. hr = E_FAIL;
  852. goto Exit;
  853. }
  854. //
  855. // Save registry value
  856. //
  857. lResult = RegCreateKeyEx (m_hKey, lpKeyName, 0, NULL, REG_OPTION_NON_VOLATILE,
  858. KEY_WRITE, NULL, &hSubKey, &dwDisp);
  859. if (lResult == ERROR_SUCCESS)
  860. {
  861. if ((dwType == REG_NONE) && (dwDataLength == 0) &&
  862. (*lpValueName == L'\0'))
  863. {
  864. lResult = ERROR_SUCCESS;
  865. }
  866. else
  867. {
  868. lResult = RegSetValueEx (hSubKey, lpValueName, 0, dwType,
  869. lpData, dwDataLength);
  870. }
  871. RegCloseKey (hSubKey);
  872. if (lResult != ERROR_SUCCESS)
  873. {
  874. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to set value <%s> with %d"),
  875. lpValueName, lResult));
  876. hr = HRESULT_FROM_WIN32(lResult);
  877. LocalFree (lpData);
  878. goto Exit;
  879. }
  880. }
  881. else
  882. {
  883. DebugMsg((DM_WARNING, TEXT("CRegistryHive::Load: Failed to open key <%s> with %d"),
  884. lpKeyName, lResult));
  885. hr = HRESULT_FROM_WIN32(lResult);
  886. LocalFree (lpData);
  887. goto Exit;
  888. }
  889. LocalFree (lpData);
  890. }
  891. Exit:
  892. //
  893. // Finished
  894. //
  895. CloseHandle (hFile);
  896. LocalFree (lpKeyName);
  897. LocalFree (lpValueName);
  898. return hr;
  899. }
  900. STDMETHODIMP CRegistryHive::IsRegistryEmpty(BOOL *bEmpty)
  901. {
  902. HRESULT hr = ERROR_SUCCESS;
  903. DWORD dwKeys, dwValues;
  904. LONG lResult;
  905. if (!m_hKey)
  906. {
  907. DebugMsg((DM_WARNING, TEXT("CRegistryHive::IsRegistryEmpty: registry key not open yet")));
  908. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  909. }
  910. lResult = RegQueryInfoKey(m_hKey, NULL, NULL, NULL, &dwKeys, NULL, NULL, &dwValues,
  911. NULL, NULL, NULL, NULL);
  912. if (lResult != ERROR_SUCCESS)
  913. {
  914. DebugMsg((DM_WARNING, TEXT("CRegistryHive::IsRegistryEmpty: RegQueryInfoKey failed with %d"),
  915. lResult));
  916. return HRESULT_FROM_WIN32(lResult);
  917. }
  918. if ((dwKeys == 0) && (dwValues == 0))
  919. {
  920. *bEmpty = TRUE;
  921. DebugMsg((DM_VERBOSE, TEXT("CRegistryHive::IsRegistryEmpty: registry key is empty")));
  922. }
  923. else
  924. {
  925. *bEmpty = FALSE;
  926. DebugMsg((DM_VERBOSE, TEXT("CRegistryHive::IsRegistryEmpty: registry key is not empty. Keys = %d, Values = %d"),
  927. dwKeys, dwValues));
  928. }
  929. return S_OK;
  930. }