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.

787 lines
19 KiB

  1. // Copyright (c) 1995, Microsoft Corporation, all rights reserved
  2. //
  3. // reg.c
  4. // Registry utility routines
  5. // Listed alphabetically
  6. //
  7. // 11/31/95 Steve Cobb
  8. #include <windows.h> // Win32 root
  9. #include <debug.h> // Trace/Assert library
  10. #include <nouiutil.h> // Prototypes and heap macros
  11. //-----------------------------------------------------------------------------
  12. // Local prototypes (alphabetically)
  13. //-----------------------------------------------------------------------------
  14. BOOL
  15. RegDeleteTreeWorker(
  16. IN HKEY ParentKeyHandle,
  17. IN TCHAR* KeyName,
  18. OUT DWORD* ErrorCode );
  19. //-----------------------------------------------------------------------------
  20. // Routines (alphabetically)
  21. //-----------------------------------------------------------------------------
  22. VOID
  23. GetRegBinary(
  24. IN HKEY hkey,
  25. IN TCHAR* pszName,
  26. OUT BYTE** ppbResult,
  27. OUT DWORD* pcbResult )
  28. // Set '*ppbResult' to the BINARY registry value 'pszName' under key
  29. // 'hkey'. If the value does not exist *ppbResult' is set to NULL.
  30. // '*PcbResult' is the number of bytes in the returned '*ppbResult'. It
  31. // is caller's responsibility to Free the returned block.
  32. //
  33. {
  34. DWORD dwErr;
  35. DWORD dwType;
  36. BYTE* pb;
  37. DWORD cb = 0;
  38. *ppbResult = NULL;
  39. *pcbResult = 0;
  40. // Get result buffer size required.
  41. //
  42. dwErr = RegQueryValueEx(
  43. hkey, pszName, NULL, &dwType, NULL, &cb );
  44. if (dwErr != 0)
  45. {
  46. return;
  47. }
  48. // Allocate result buffer.
  49. //
  50. pb = Malloc( cb );
  51. if (!pb)
  52. {
  53. return;
  54. }
  55. // Get the result block.
  56. //
  57. dwErr = RegQueryValueEx(
  58. hkey, pszName, NULL, &dwType, (LPBYTE )pb, &cb );
  59. if (dwErr == 0)
  60. {
  61. *ppbResult = pb;
  62. *pcbResult = cb;
  63. }
  64. }
  65. VOID
  66. GetRegDword(
  67. IN HKEY hkey,
  68. IN TCHAR* pszName,
  69. OUT DWORD* pdwResult )
  70. // Set '*pdwResult' to the DWORD registry value 'pszName' under key
  71. // 'hkey'. If the value does not exist '*pdwResult' is unchanged.
  72. //
  73. {
  74. DWORD dwErr;
  75. DWORD dwType;
  76. DWORD dwResult;
  77. DWORD cb;
  78. cb = sizeof(DWORD);
  79. dwErr = RegQueryValueEx(
  80. hkey, pszName, NULL, &dwType, (LPBYTE )&dwResult, &cb );
  81. if (dwErr == 0 && dwType == REG_DWORD && cb == sizeof(DWORD))
  82. {
  83. *pdwResult = dwResult;
  84. }
  85. }
  86. DWORD
  87. GetRegExpandSz(
  88. IN HKEY hkey,
  89. IN TCHAR* pszName,
  90. OUT TCHAR** ppszResult )
  91. // Set '*ppszResult' to the fully expanded EXPAND_SZ registry value
  92. // 'pszName' under key 'hkey'. If the value does not exist *ppszResult'
  93. // is set to empty string.
  94. //
  95. // Returns 0 if successful or an error code. It is caller's
  96. // responsibility to Free the returned string.
  97. //
  98. {
  99. DWORD dwErr;
  100. DWORD cb;
  101. TCHAR* pszResult;
  102. // Get the unexpanded result string.
  103. //
  104. dwErr = GetRegSz( hkey, pszName, ppszResult );
  105. if (dwErr != 0)
  106. {
  107. return dwErr;
  108. }
  109. // Find out how big the expanded string will be.
  110. //
  111. cb = ExpandEnvironmentStrings( *ppszResult, NULL, 0 );
  112. if (cb == 0)
  113. {
  114. dwErr = GetLastError();
  115. ASSERT( dwErr != 0 );
  116. Free( *ppszResult );
  117. return dwErr;
  118. }
  119. // Allocate a buffer for the expanded string.
  120. //
  121. pszResult = Malloc( (cb + 1) * sizeof(TCHAR) );
  122. if (!pszResult)
  123. {
  124. return ERROR_NOT_ENOUGH_MEMORY;
  125. }
  126. // Expand the environmant variables in the string, storing the result in
  127. // the allocated buffer.
  128. //
  129. cb = ExpandEnvironmentStrings( *ppszResult, pszResult, cb + 1 );
  130. if (cb == 0)
  131. {
  132. dwErr = GetLastError();
  133. ASSERT( dwErr != 0 );
  134. Free( *ppszResult );
  135. Free( pszResult );
  136. return dwErr;
  137. }
  138. Free( *ppszResult );
  139. *ppszResult = pszResult;
  140. return 0;
  141. }
  142. DWORD
  143. GetRegMultiSz(
  144. IN HKEY hkey,
  145. IN TCHAR* pszName,
  146. IN OUT DTLLIST** ppListResult,
  147. IN DWORD dwNodeType )
  148. // Replaces '*ppListResult' with a list containing a node for each string
  149. // in the MULTI_SZ registry value 'pszName' under key 'hkey'. If the
  150. // value does not exist *ppListResult' is replaced with an empty list.
  151. // 'DwNodeType' determines the type of node.
  152. //
  153. // Returns 0 if successful or an error code. It is caller's
  154. // responsibility to destroy the returned list.
  155. //
  156. {
  157. DWORD dwErr;
  158. DWORD dwType;
  159. DWORD cb;
  160. TCHAR* pszzResult;
  161. DTLLIST* pList;
  162. pList = DtlCreateList( 0 );
  163. if (!pList)
  164. {
  165. return ERROR_NOT_ENOUGH_MEMORY;
  166. }
  167. pszzResult = NULL;
  168. // Get result buffer size required.
  169. //
  170. dwErr = RegQueryValueEx(
  171. hkey, pszName, NULL, &dwType, NULL, &cb );
  172. if (dwErr != 0)
  173. {
  174. // If can't find the value, just return an empty list. This not
  175. // considered an error.
  176. //
  177. dwErr = 0;
  178. }
  179. else
  180. {
  181. // Allocate result buffer.
  182. //
  183. pszzResult = Malloc( cb );
  184. if (!pszzResult)
  185. {
  186. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  187. }
  188. else
  189. {
  190. // Get the result string. It's not an error if we can't get it.
  191. //
  192. dwErr = RegQueryValueEx(
  193. hkey, pszName, NULL, &dwType, (LPBYTE )pszzResult, &cb );
  194. if (dwErr != 0)
  195. {
  196. // Not an error if can't read the string, though this should
  197. // have been caught by the query retrieving the buffer size.
  198. //
  199. dwErr = 0;
  200. }
  201. else if (dwType == REG_MULTI_SZ)
  202. {
  203. TCHAR* psz;
  204. TCHAR* pszKey;
  205. // Convert the result to a list of strings.
  206. //
  207. pszKey = NULL;
  208. for (psz = pszzResult;
  209. *psz != TEXT('\0');
  210. psz += lstrlen( psz ) + 1)
  211. {
  212. DTLNODE* pNode;
  213. if (dwNodeType == NT_Psz)
  214. {
  215. pNode = CreatePszNode( psz );
  216. }
  217. else
  218. {
  219. if (pszKey)
  220. {
  221. ASSERT(*psz==TEXT('='));
  222. pNode = CreateKvNode( pszKey, psz + 1 );
  223. pszKey = NULL;
  224. }
  225. else
  226. {
  227. pszKey = psz;
  228. continue;
  229. }
  230. }
  231. if (!pNode)
  232. {
  233. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  234. break;
  235. }
  236. DtlAddNodeLast( pList, pNode );
  237. }
  238. }
  239. }
  240. }
  241. {
  242. PDESTROYNODE pfunc;
  243. if (dwNodeType == NT_Psz)
  244. {
  245. pfunc = DestroyPszNode;
  246. }
  247. else
  248. {
  249. pfunc = DestroyKvNode;
  250. }
  251. if (dwErr == 0)
  252. {
  253. DtlDestroyList( *ppListResult, pfunc );
  254. *ppListResult = pList;
  255. }
  256. else
  257. {
  258. DtlDestroyList( pList, pfunc );
  259. }
  260. }
  261. Free0( pszzResult );
  262. return 0;
  263. }
  264. DWORD
  265. GetRegSz(
  266. IN HKEY hkey,
  267. IN TCHAR* pszName,
  268. OUT TCHAR** ppszResult )
  269. // Set '*ppszResult' to the SZ registry value 'pszName' under key 'hkey'.
  270. // If the value does not exist *ppszResult' is set to empty string.
  271. //
  272. // Returns 0 if successful or an error code. It is caller's
  273. // responsibility to Free the returned string.
  274. //
  275. {
  276. DWORD dwErr;
  277. DWORD dwType;
  278. DWORD cb = 0;
  279. TCHAR* pszResult;
  280. // Get result buffer size required.
  281. //
  282. dwErr = RegQueryValueEx(
  283. hkey, pszName, NULL, &dwType, NULL, &cb );
  284. if (dwErr != 0)
  285. {
  286. cb = sizeof(TCHAR);
  287. }
  288. // Allocate result buffer.
  289. //
  290. pszResult = Malloc( cb );
  291. if (!pszResult)
  292. {
  293. return ERROR_NOT_ENOUGH_MEMORY;
  294. }
  295. *pszResult = TEXT('\0');
  296. *ppszResult = pszResult;
  297. // Get the result string. It's not an error if we can't get it.
  298. //
  299. dwErr = RegQueryValueEx(
  300. hkey, pszName, NULL, &dwType, (LPBYTE )pszResult, &cb );
  301. return 0;
  302. }
  303. DWORD
  304. GetRegSzz(
  305. IN HKEY hkey,
  306. IN TCHAR* pszName,
  307. OUT TCHAR** ppszResult )
  308. // Set '*ppszResult to the MULTI_SZ registry value 'pszName' under key
  309. // 'hkey', returned as a null-terminated list of null-terminated strings.
  310. // If the value does not exist, *ppszResult is set to an empty string
  311. // (single null character).
  312. //
  313. // Returns 0 if successful or an error code. It is caller's
  314. // responsibility to Free the returned string.
  315. //
  316. {
  317. DWORD dwErr;
  318. DWORD dwType;
  319. DWORD cb = 0;
  320. TCHAR* pszResult;
  321. // Get result buffer size required.
  322. //
  323. dwErr = RegQueryValueEx(
  324. hkey, pszName, NULL, &dwType, NULL, &cb );
  325. if (dwErr != 0)
  326. {
  327. cb = sizeof(TCHAR);
  328. }
  329. // Allocate result buffer.
  330. //
  331. pszResult = Malloc( cb );
  332. if (!pszResult)
  333. return ERROR_NOT_ENOUGH_MEMORY;
  334. *pszResult = TEXT('\0');
  335. *ppszResult = pszResult;
  336. // Get the result string list. It's not an error if we can't get it.
  337. //
  338. dwErr = RegQueryValueEx(
  339. hkey, pszName, NULL, &dwType, (LPBYTE )pszResult, &cb );
  340. return 0;
  341. }
  342. DWORD
  343. RegDeleteTree(
  344. IN HKEY RootKey,
  345. IN TCHAR* SubKeyName )
  346. // Delete registry tree 'SubKeyName' under key 'RootKey'.
  347. //
  348. // (taken from Ted Miller's setup API)
  349. //
  350. {
  351. DWORD d,err;
  352. d = RegDeleteTreeWorker(RootKey,SubKeyName,&err) ? NO_ERROR : err;
  353. if((d == ERROR_FILE_NOT_FOUND) || (d == ERROR_PATH_NOT_FOUND)) {
  354. d = NO_ERROR;
  355. }
  356. if(d == NO_ERROR) {
  357. //
  358. // Delete top-level key
  359. //
  360. d = RegDeleteKey(RootKey,SubKeyName);
  361. if((d == ERROR_FILE_NOT_FOUND) || (d == ERROR_PATH_NOT_FOUND)) {
  362. d = NO_ERROR;
  363. }
  364. }
  365. return(d);
  366. }
  367. BOOL
  368. RegDeleteTreeWorker(
  369. IN HKEY ParentKeyHandle,
  370. IN TCHAR* KeyName,
  371. OUT DWORD* ErrorCode )
  372. // Delete all subkeys of a key whose name and parent's handle was passed
  373. // as parameter. The algorithm used in this function guarantees that the
  374. // maximum number of descendent keys will be deleted.
  375. //
  376. // 'ParentKeyHandle' is a handle to the parent of the key that is
  377. // currently being examined.
  378. //
  379. // 'KeyName' is the name of the key that is currently being examined.
  380. // This name can be an empty string (but not a NULL pointer), and in this
  381. // case ParentKeyHandle refers to the key that is being examined.
  382. //
  383. // 'ErrorCode' is the address to receive a Win32 error code if the
  384. // function fails.
  385. //
  386. // Returns true if successful, false otherwise.
  387. //
  388. // (taken from Ted Miller's setup API)
  389. //
  390. {
  391. HKEY CurrentKeyTraverseAccess;
  392. DWORD iSubKey;
  393. TCHAR SubKeyName[MAX_PATH+1];
  394. DWORD SubKeyNameLength;
  395. FILETIME ftLastWriteTime;
  396. LONG Status;
  397. LONG StatusEnum;
  398. LONG SavedStatus;
  399. //
  400. // Do not accept NULL pointer for ErrorCode
  401. //
  402. if(ErrorCode == NULL) {
  403. return(FALSE);
  404. }
  405. //
  406. // Do not accept NULL pointer for KeyName.
  407. //
  408. if(KeyName == NULL) {
  409. *ErrorCode = ERROR_INVALID_PARAMETER;
  410. return(FALSE);
  411. }
  412. //
  413. // Open a handle to the key whose subkeys are to be deleted.
  414. // Since we need to delete its subkeys, the handle must have
  415. // KEY_ENUMERATE_SUB_KEYS access.
  416. //
  417. Status = RegOpenKeyEx(
  418. ParentKeyHandle,
  419. KeyName,
  420. 0,
  421. KEY_ENUMERATE_SUB_KEYS | DELETE,
  422. &CurrentKeyTraverseAccess
  423. );
  424. if(Status != ERROR_SUCCESS) {
  425. //
  426. // If unable to enumerate the subkeys, return error.
  427. //
  428. *ErrorCode = Status;
  429. return(FALSE);
  430. }
  431. //
  432. // Traverse the key
  433. //
  434. iSubKey = 0;
  435. SavedStatus = ERROR_SUCCESS;
  436. do {
  437. //
  438. // Get the name of a subkey
  439. //
  440. SubKeyNameLength = sizeof(SubKeyName) / sizeof(TCHAR);
  441. StatusEnum = RegEnumKeyEx(
  442. CurrentKeyTraverseAccess,
  443. iSubKey,
  444. SubKeyName,
  445. &SubKeyNameLength,
  446. NULL,
  447. NULL,
  448. NULL,
  449. &ftLastWriteTime
  450. );
  451. if(StatusEnum == ERROR_SUCCESS) {
  452. //
  453. // Delete all children of the subkey.
  454. // Just assume that the children will be deleted, and don't check
  455. // for failure.
  456. //
  457. RegDeleteTreeWorker(CurrentKeyTraverseAccess,SubKeyName,&Status);
  458. //
  459. // Now delete the subkey, and check for failure.
  460. //
  461. Status = RegDeleteKey(CurrentKeyTraverseAccess,SubKeyName);
  462. //
  463. // If unable to delete the subkey, then save the error code.
  464. // Note that the subkey index is incremented only if the subkey
  465. // was not deleted.
  466. //
  467. if(Status != ERROR_SUCCESS) {
  468. iSubKey++;
  469. SavedStatus = Status;
  470. }
  471. } else {
  472. //
  473. // If unable to get a subkey name due to ERROR_NO_MORE_ITEMS,
  474. // then the key doesn't have subkeys, or all subkeys were already
  475. // enumerated. Otherwise, an error has occurred, so just save
  476. // the error code.
  477. //
  478. if(StatusEnum != ERROR_NO_MORE_ITEMS) {
  479. SavedStatus = StatusEnum;
  480. }
  481. }
  482. //if((StatusEnum != ERROR_SUCCESS ) && (StatusEnum != ERROR_NO_MORE_ITEMS)) {
  483. // printf( "RegEnumKeyEx() failed, Key Name = %ls, Status = %d, iSubKey = %d \n",KeyName,StatusEnum,iSubKey);
  484. //}
  485. } while(StatusEnum == ERROR_SUCCESS);
  486. //
  487. // Close the handle to the key whose subkeys were deleted, and return
  488. // the result of the operation.
  489. //
  490. RegCloseKey(CurrentKeyTraverseAccess);
  491. if(SavedStatus != ERROR_SUCCESS) {
  492. *ErrorCode = SavedStatus;
  493. return(FALSE);
  494. }
  495. return(TRUE);
  496. }
  497. BOOL
  498. RegValueExists(
  499. IN HKEY hkey,
  500. IN TCHAR* pszValue )
  501. // Returns true if 'pszValue' is an existing value under 'hkey', false if
  502. // not.
  503. //
  504. {
  505. DWORD dwErr;
  506. DWORD dwType;
  507. DWORD cb = 0;
  508. dwErr = RegQueryValueEx( hkey, pszValue, NULL, &dwType, NULL, &cb );
  509. return !!(dwErr == 0);
  510. }
  511. DWORD
  512. SetRegDword(
  513. IN HKEY hkey,
  514. IN TCHAR* pszName,
  515. IN DWORD dwValue )
  516. // Set registry value 'pszName' under key 'hkey' to REG_DWORD value
  517. // 'dwValue'.
  518. //
  519. // Returns 0 is successful or an error code.
  520. //
  521. {
  522. return RegSetValueEx(
  523. hkey, pszName, 0, REG_DWORD, (LPBYTE )&dwValue, sizeof(dwValue) );
  524. }
  525. DWORD
  526. SetRegMultiSz(
  527. IN HKEY hkey,
  528. IN TCHAR* pszName,
  529. IN DTLLIST* pListValues,
  530. IN DWORD dwNodeType )
  531. // Set registry value 'pszName' under key 'hkey' to a REG_MULTI_SZ value
  532. // containing the strings in the Psz list 'pListValues'. 'DwNodeType'
  533. // determines the type of node.
  534. //
  535. // Returns 0 is successful or an error code.
  536. //
  537. {
  538. DWORD dwErr;
  539. DWORD cb;
  540. DTLNODE* pNode;
  541. TCHAR* pszzValues;
  542. TCHAR* pszValue;
  543. // Count up size of MULTI_SZ buffer needed.
  544. //
  545. cb = sizeof(TCHAR);
  546. for (pNode = DtlGetFirstNode( pListValues );
  547. pNode;
  548. pNode = DtlGetNextNode( pNode ))
  549. {
  550. if (dwNodeType == NT_Psz)
  551. {
  552. TCHAR* psz;
  553. psz = (TCHAR* )DtlGetData( pNode );
  554. ASSERT(psz);
  555. cb += (lstrlen( psz ) + 1) * sizeof(TCHAR);
  556. }
  557. else
  558. {
  559. KEYVALUE* pkv;
  560. ASSERT(dwNodeType==NT_Kv);
  561. pkv = (KEYVALUE* )DtlGetData( pNode );
  562. ASSERT(pkv);
  563. ASSERT(pkv->pszKey);
  564. ASSERT(pkv->pszValue);
  565. cb += (lstrlen( pkv->pszKey ) + 1
  566. + 1 + lstrlen( pkv->pszValue ) + 1) * sizeof(TCHAR);
  567. }
  568. }
  569. if (cb == sizeof(TCHAR))
  570. {
  571. cb += sizeof(TCHAR);
  572. }
  573. // Allocate MULTI_SZ buffer.
  574. //
  575. pszzValues = Malloc( cb );
  576. if (!pszzValues)
  577. {
  578. return ERROR_NOT_ENOUGH_MEMORY;
  579. }
  580. // Fill MULTI_SZ buffer from list.
  581. //
  582. if (cb == 2 * sizeof(TCHAR))
  583. {
  584. pszzValues[ 0 ] = pszzValues[ 1 ] = TEXT('\0');
  585. }
  586. else
  587. {
  588. pszValue = pszzValues;
  589. for (pNode = DtlGetFirstNode( pListValues );
  590. pNode;
  591. pNode = DtlGetNextNode( pNode ))
  592. {
  593. if (dwNodeType == NT_Psz)
  594. {
  595. TCHAR* psz;
  596. psz = (TCHAR* )DtlGetData( pNode );
  597. ASSERT(psz);
  598. lstrcpy( pszValue, psz );
  599. pszValue += lstrlen( pszValue ) + 1;
  600. }
  601. else
  602. {
  603. KEYVALUE* pkv;
  604. pkv = (KEYVALUE* )DtlGetData( pNode );
  605. ASSERT(pkv);
  606. ASSERT(pkv->pszKey);
  607. ASSERT(pkv->pszValue);
  608. lstrcpy( pszValue, pkv->pszKey );
  609. pszValue += lstrlen( pszValue ) + 1;
  610. *pszValue = TEXT('=');
  611. ++pszValue;
  612. lstrcpy( pszValue, pkv->pszValue );
  613. pszValue += lstrlen( pszValue ) + 1;
  614. }
  615. }
  616. *pszValue = TEXT('\0');
  617. }
  618. /* Set registry value from MULTI_SZ buffer.
  619. */
  620. dwErr = RegSetValueEx(
  621. hkey, pszName, 0, REG_MULTI_SZ, (LPBYTE )pszzValues, cb );
  622. Free( pszzValues );
  623. return dwErr;
  624. }
  625. DWORD
  626. SetRegSz(
  627. IN HKEY hkey,
  628. IN TCHAR* pszName,
  629. IN TCHAR* pszValue )
  630. // Set registry value 'pszName' under key 'hkey' to a REG_SZ value
  631. // 'pszValue'.
  632. //
  633. // Returns 0 is successful or an error code.
  634. //
  635. {
  636. TCHAR* psz;
  637. if (pszValue)
  638. {
  639. psz = pszValue;
  640. }
  641. else
  642. {
  643. psz = TEXT("");
  644. }
  645. return
  646. RegSetValueEx(
  647. hkey, pszName, 0, REG_SZ,
  648. (LPBYTE )psz, (lstrlen( psz ) + 1) * sizeof(TCHAR) );
  649. }
  650. DWORD
  651. SetRegSzz(
  652. IN HKEY hkey,
  653. IN TCHAR* pszName,
  654. IN TCHAR* pszValue )
  655. // Set registry value 'pszName' under key 'hkey' to a REG_MULTI_SZ value
  656. // 'pszValue'.
  657. //
  658. // Returns 0 is successful or an error code.
  659. //
  660. {
  661. DWORD cb;
  662. TCHAR* psz;
  663. cb = sizeof(TCHAR);
  664. if (!pszValue)
  665. {
  666. psz = TEXT("");
  667. }
  668. else
  669. {
  670. INT nLen;
  671. for (psz = pszValue; *psz; psz += nLen)
  672. {
  673. nLen = lstrlen( psz ) + 1;
  674. cb += nLen * sizeof(TCHAR);
  675. }
  676. psz = pszValue;
  677. }
  678. return RegSetValueEx( hkey, pszName, 0, REG_MULTI_SZ, (LPBYTE )psz, cb );
  679. }