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.

634 lines
15 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1993-2000
  4. *
  5. * TITLE: REGMISC.C
  6. *
  7. * VERSION: 4.0
  8. *
  9. * AUTHOR: Tracy Sharpe
  10. *
  11. * DATE: 21 Nov 1993
  12. *
  13. * Miscellaneous routines for the Registry Editor.
  14. *
  15. ********************************************************************************
  16. *
  17. * CHANGE LOG:
  18. *
  19. * DATE REV DESCRIPTION
  20. * ----------- --- -------------------------------------------------------------
  21. * 21 Nov 1993 TCS Original implementation.
  22. * 06 Apr 1994 TCS Moved EditRegistryKey to REGPORTE.C because it needs to
  23. * be available for the real-mode registry tool, too.
  24. *
  25. *******************************************************************************/
  26. #include "pch.h"
  27. /*******************************************************************************
  28. *
  29. * LoadDynamicString
  30. *
  31. * DESCRIPTION:
  32. * Wrapper for the FormatMessage function that loads a string from our
  33. * resource table into a dynamically allocated buffer, optionally filling
  34. * it with the variable arguments passed.
  35. *
  36. * PARAMETERS:
  37. * StringID, resource identifier of the string to use.
  38. * (optional), parameters to use to format the string message.
  39. * (returns), pointer to dynamically allocated string buffer.
  40. *
  41. *******************************************************************************/
  42. PTSTR
  43. CDECL
  44. LoadDynamicString(
  45. UINT StringID,
  46. ...
  47. )
  48. {
  49. #if 0
  50. PTSTR pStr;
  51. va_list Marker = va_start(Marker, StringID);
  52. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  53. (LPVOID) (DWORD) g_hInstance, StringID, 0, (LPTSTR) (PTSTR FAR *)
  54. &pStr, 0, &Marker);
  55. #else
  56. TCHAR Buffer[256];
  57. PTSTR pStr;
  58. va_list Marker;
  59. va_start(Marker, StringID);
  60. LoadString(g_hInstance, StringID, Buffer, ARRAYSIZE(Buffer));
  61. if (0 == FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  62. (LPVOID) (LPSTR) Buffer, 0, 0, (LPTSTR) (PTSTR FAR *) &pStr, 0, &Marker)) {
  63. pStr = NULL;
  64. }
  65. va_end(Marker);
  66. #endif
  67. return pStr;
  68. }
  69. /*******************************************************************************
  70. *
  71. * CopyRegistry
  72. *
  73. * DESCRIPTION:
  74. *
  75. * PARAMETERS:
  76. * hSourceKey,
  77. * hDestinationKey,
  78. *
  79. *******************************************************************************/
  80. BOOL
  81. PASCAL
  82. CopyRegistry(
  83. HKEY hSourceKey,
  84. HKEY hDestinationKey
  85. )
  86. {
  87. BOOL fSuccess = TRUE;
  88. DWORD EnumIndex;
  89. DWORD cchValueName;
  90. DWORD cbValueData;
  91. DWORD Type;
  92. HKEY hSourceSubKey;
  93. HKEY hDestinationSubKey;
  94. //
  95. // Copy all of the value names and their data.
  96. //
  97. EnumIndex = 0;
  98. while (TRUE)
  99. {
  100. PBYTE pbValueData;
  101. cchValueName = ARRAYSIZE(g_ValueNameBuffer);
  102. // VALUE DATA
  103. // Query for data size
  104. if (RegEnumValue(hSourceKey, EnumIndex++, g_ValueNameBuffer,
  105. &cchValueName, NULL, &Type, NULL, &cbValueData) != ERROR_SUCCESS)
  106. {
  107. break;
  108. }
  109. // allocate memory for data
  110. pbValueData = LocalAlloc(LPTR, cbValueData+ExtraAllocLen(Type));
  111. if (pbValueData)
  112. {
  113. if (RegEdit_QueryValueEx(hSourceKey, g_ValueNameBuffer,
  114. NULL, &Type, pbValueData, &cbValueData) == ERROR_SUCCESS)
  115. {
  116. RegSetValueEx(hDestinationKey, g_ValueNameBuffer, 0, Type,
  117. pbValueData, cbValueData);
  118. }
  119. else
  120. {
  121. fSuccess = FALSE;
  122. }
  123. LocalFree(pbValueData);
  124. }
  125. else
  126. {
  127. fSuccess = FALSE;
  128. }
  129. }
  130. if (fSuccess)
  131. {
  132. //
  133. // Copy all of the subkeys and recurse into them.
  134. //
  135. EnumIndex = 0;
  136. while (TRUE) {
  137. if (RegEnumKey(hSourceKey, EnumIndex++, g_KeyNameBuffer, MAXKEYNAME) !=
  138. ERROR_SUCCESS)
  139. break;
  140. if(RegOpenKeyEx(hSourceKey,g_KeyNameBuffer,0,KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,&hSourceSubKey) ==
  141. ERROR_SUCCESS) {
  142. if (RegCreateKey(hDestinationKey, g_KeyNameBuffer,
  143. &hDestinationSubKey) == ERROR_SUCCESS) {
  144. CopyRegistry(hSourceSubKey, hDestinationSubKey);
  145. RegCloseKey(hDestinationSubKey);
  146. }
  147. RegCloseKey(hSourceSubKey);
  148. }
  149. }
  150. }
  151. return fSuccess;
  152. }
  153. /*******************************************************************************
  154. *
  155. * CreateDitheredBrush
  156. *
  157. * DESCRIPTION:
  158. * Creates a dithered brush which is made up of alternating black and white
  159. * pixels.
  160. *
  161. * PARAMETERS:
  162. * (returns), handle of dithered brush.
  163. *
  164. *******************************************************************************/
  165. HBRUSH
  166. PASCAL
  167. CreateDitheredBrush(
  168. VOID
  169. )
  170. {
  171. WORD graybits[] = {0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555,
  172. 0xAAAA};
  173. HBRUSH hBrush;
  174. HBITMAP hBitmap;
  175. if ((hBitmap = CreateBitmap(8, 8, 1, 1, graybits)) != NULL) {
  176. hBrush = CreatePatternBrush(hBitmap);
  177. DeleteObject(hBitmap);
  178. }
  179. else
  180. hBrush = NULL;
  181. return hBrush;
  182. }
  183. /*******************************************************************************
  184. *
  185. * SendChildrenMessage
  186. *
  187. * DESCRIPTION:
  188. * Sends the given message to all children of the given parent window.
  189. *
  190. * PARAMETERS:
  191. * hWnd, handle of parent window.
  192. * Message, message to send.
  193. * wParam, message dependent data.
  194. * lParam, message dependent data.
  195. *
  196. *******************************************************************************/
  197. VOID
  198. PASCAL
  199. SendChildrenMessage(
  200. HWND hWnd,
  201. UINT Message,
  202. WPARAM wParam,
  203. LPARAM lParam
  204. )
  205. {
  206. HWND hChildWnd;
  207. hChildWnd = GetWindow(hWnd, GW_CHILD);
  208. while (hChildWnd != NULL) {
  209. SendMessage(hChildWnd, Message, wParam, lParam);
  210. hChildWnd = GetWindow(hChildWnd, GW_HWNDNEXT);
  211. }
  212. }
  213. /*******************************************************************************
  214. *
  215. * MessagePump
  216. *
  217. * DESCRIPTION:
  218. * Processes the next queued message, if any.
  219. *
  220. * PARAMETERS:
  221. * hDialogWnd, handle of modeless dialog.
  222. *
  223. *******************************************************************************/
  224. BOOL
  225. PASCAL
  226. MessagePump(
  227. HWND hDialogWnd
  228. )
  229. {
  230. MSG Msg;
  231. BOOL fGotMessage;
  232. if ((fGotMessage = PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))) {
  233. if (!IsDialogMessage(hDialogWnd, &Msg)) {
  234. TranslateMessage(&Msg);
  235. DispatchMessage(&Msg);
  236. }
  237. }
  238. return fGotMessage;
  239. }
  240. /*******************************************************************************
  241. *
  242. * GetNextSubstring
  243. *
  244. * DESCRIPTION:
  245. *
  246. * PARAMETERS:
  247. *
  248. *******************************************************************************/
  249. LPTSTR
  250. PASCAL
  251. GetNextSubstring(
  252. LPTSTR lpString
  253. )
  254. {
  255. static LPTSTR lpLastString;
  256. TCHAR EndChar;
  257. LPTSTR lpReturnString;
  258. if (lpString == NULL)
  259. lpString = lpLastString;
  260. while (*lpString == TEXT(' '))
  261. lpString++;
  262. if (*lpString == 0)
  263. lpReturnString = NULL;
  264. else {
  265. if (*lpString == TEXT('\"')) {
  266. EndChar = TEXT('\"');
  267. lpString++;
  268. }
  269. else
  270. EndChar = TEXT(' ');
  271. lpReturnString = lpString;
  272. while (*lpString != EndChar && *lpString != 0)
  273. lpString = CharNext(lpString);
  274. if (*lpString == EndChar)
  275. *lpString++ = 0;
  276. }
  277. lpLastString = lpString;
  278. return lpReturnString;
  279. }
  280. /*******************************************************************************
  281. *
  282. * InternalMessageBox
  283. *
  284. * DESCRIPTION:
  285. *
  286. * PARAMETERS:
  287. *
  288. *******************************************************************************/
  289. int
  290. PASCAL
  291. InternalMessageBox(
  292. HINSTANCE hInst,
  293. HWND hWnd,
  294. LPCTSTR pszFormat,
  295. LPCTSTR pszTitle,
  296. UINT fuStyle,
  297. ...
  298. )
  299. {
  300. TCHAR szTitle[80];
  301. TCHAR szFormat[512];
  302. LPTSTR pszMessage;
  303. BOOL fOk;
  304. int result;
  305. va_list ArgList;
  306. if (HIWORD(pszTitle))
  307. {
  308. // do nothing
  309. }
  310. else
  311. {
  312. // Allow this to be a resource ID
  313. LoadString(hInst, LOWORD(pszTitle), szTitle, ARRAYSIZE(szTitle));
  314. pszTitle = szTitle;
  315. }
  316. if (HIWORD(pszFormat))
  317. {
  318. // do nothing
  319. }
  320. else
  321. {
  322. // Allow this to be a resource ID
  323. LoadString(hInst, LOWORD(pszFormat), szFormat, ARRAYSIZE(szFormat));
  324. pszFormat = szFormat;
  325. }
  326. va_start(ArgList, fuStyle);
  327. fOk = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  328. | FORMAT_MESSAGE_FROM_STRING,
  329. pszFormat, 0, 0, (LPTSTR)&pszMessage, 0, &ArgList);
  330. va_end(ArgList);
  331. if (fOk && pszMessage)
  332. {
  333. result = MessageBox(hWnd, pszMessage, pszTitle, fuStyle | MB_SETFOREGROUND);
  334. LocalFree(pszMessage);
  335. }
  336. else
  337. {
  338. return -1;
  339. }
  340. return result;
  341. }
  342. #ifdef WINNT
  343. /*******************************************************************************
  344. *
  345. * RegDeleteKeyRecursive
  346. *
  347. * DESCRIPTION:
  348. * Adapted from \\kernel\razzle3,mvdm\wow32\wshell.c,WOWRegDeleteKey().
  349. * The Windows 95 implementation of RegDeleteKey recursively deletes all
  350. * the subkeys of the specified registry branch, but the NT implementation
  351. * only deletes leaf keys.
  352. *
  353. * PARAMETERS:
  354. * (see below)
  355. *
  356. *******************************************************************************/
  357. LONG
  358. RegDeleteKeyRecursive(
  359. IN HKEY hKey,
  360. IN LPCTSTR lpszSubKey
  361. )
  362. /*++
  363. Routine Description:
  364. There is a significant difference between the Win3.1 and Win32
  365. behavior of RegDeleteKey when the key in question has subkeys.
  366. The Win32 API does not allow you to delete a key with subkeys,
  367. while the Win3.1 API deletes a key and all its subkeys.
  368. This routine is a recursive worker that enumerates the subkeys
  369. of a given key, applies itself to each one, then deletes itself.
  370. It specifically does not attempt to deal rationally with the
  371. case where the caller may not have access to some of the subkeys
  372. of the key to be deleted. In this case, all the subkeys which
  373. the caller can delete will be deleted, but the api will still
  374. return ERROR_ACCESS_DENIED.
  375. Arguments:
  376. hKey - Supplies a handle to an open registry key.
  377. lpszSubKey - Supplies the name of a subkey which is to be deleted
  378. along with all of its subkeys.
  379. Return Value:
  380. ERROR_SUCCESS - entire subtree successfully deleted.
  381. ERROR_ACCESS_DENIED - given subkey could not be deleted.
  382. --*/
  383. {
  384. DWORD i;
  385. HKEY Key;
  386. LONG Status;
  387. DWORD ClassLength=0;
  388. DWORD SubKeys;
  389. DWORD MaxSubKey;
  390. DWORD MaxClass;
  391. DWORD Values;
  392. DWORD MaxValueName;
  393. DWORD MaxValueData;
  394. DWORD SecurityLength;
  395. FILETIME LastWriteTime;
  396. LPTSTR NameBuffer;
  397. //
  398. // First open the given key so we can enumerate its subkeys
  399. //
  400. Status = RegOpenKeyEx(hKey,
  401. lpszSubKey,
  402. 0,
  403. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
  404. &Key);
  405. if (Status != ERROR_SUCCESS) {
  406. //
  407. // possibly we have delete access, but not enumerate/query.
  408. // So go ahead and try the delete call, but don't worry about
  409. // any subkeys. If we have any, the delete will fail anyway.
  410. //
  411. return(RegDeleteKey(hKey,lpszSubKey));
  412. }
  413. //
  414. // Use RegQueryInfoKey to determine how big to allocate the buffer
  415. // for the subkey names.
  416. //
  417. Status = RegQueryInfoKey(Key,
  418. NULL,
  419. &ClassLength,
  420. 0,
  421. &SubKeys,
  422. &MaxSubKey,
  423. &MaxClass,
  424. &Values,
  425. &MaxValueName,
  426. &MaxValueData,
  427. &SecurityLength,
  428. &LastWriteTime);
  429. if ((Status != ERROR_SUCCESS) &&
  430. (Status != ERROR_MORE_DATA) &&
  431. (Status != ERROR_INSUFFICIENT_BUFFER)) {
  432. RegCloseKey(Key);
  433. return(Status);
  434. }
  435. NameBuffer = (LPTSTR) LocalAlloc(LPTR, (MaxSubKey + 1)*sizeof(TCHAR));
  436. if (NameBuffer == NULL) {
  437. RegCloseKey(Key);
  438. return(ERROR_NOT_ENOUGH_MEMORY);
  439. }
  440. //
  441. // Enumerate subkeys and apply ourselves to each one.
  442. //
  443. i=0;
  444. do {
  445. Status = RegEnumKey(Key,
  446. i,
  447. NameBuffer,
  448. MaxSubKey+1);
  449. if (Status == ERROR_SUCCESS) {
  450. Status = RegDeleteKeyRecursive(Key,NameBuffer);
  451. }
  452. if (Status != ERROR_SUCCESS) {
  453. //
  454. // Failed to delete the key at the specified index. Increment
  455. // the index and keep going. We could probably bail out here,
  456. // since the api is going to fail, but we might as well keep
  457. // going and delete everything we can.
  458. //
  459. ++i;
  460. }
  461. } while ( (Status != ERROR_NO_MORE_ITEMS) &&
  462. (i < SubKeys) );
  463. LocalFree((HLOCAL) NameBuffer);
  464. RegCloseKey(Key);
  465. return(RegDeleteKey(hKey,lpszSubKey));
  466. }
  467. #endif
  468. //--------------------------------------------------------------------------
  469. //
  470. // RegEdit_QueryValueEx
  471. //
  472. // wraps RegQueryValueEx and ensures that the returned string is NULL-
  473. // terminated
  474. //
  475. //--------------------------------------------------------------------------
  476. LONG RegEdit_QueryValueEx(
  477. HKEY hKey, // handle to key
  478. LPCTSTR lpValueName, // value name
  479. LPDWORD lpReserved, // reserved
  480. LPDWORD lpType, // type buffer
  481. LPBYTE lpData, // data buffer
  482. LPDWORD lpcbData // size of data buffer
  483. )
  484. {
  485. LONG lRes = RegQueryValueEx(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
  486. if (lRes == ERROR_SUCCESS
  487. && lpType
  488. && IsRegStringType(*lpType)
  489. && lpcbData
  490. && lpData
  491. )
  492. {
  493. // All string local allocs have an extra space in them
  494. // for the NULL character
  495. LPTSTR psz = (LPTSTR)lpData;
  496. int cch = (int)(*lpcbData/sizeof(TCHAR));
  497. if (cch > 0)
  498. {
  499. // If the string is not NULL terminated, add the additional NULL
  500. if (psz[cch-1] != 0)
  501. psz[cch] = 0;
  502. }
  503. else if (cch == 0)
  504. {
  505. if (*lpcbData == 1)
  506. {
  507. // We have allocated one extra TCHAR (2 bytes) for the NULL character
  508. *((BYTE *)(lpData+1)) = 0;
  509. *((BYTE *)(lpData+2)) = 0;
  510. *((BYTE *)(lpData+3)) = 0;
  511. }
  512. else
  513. {
  514. // No character was copied, but the string was not NULL terminated
  515. psz[0] = 0;
  516. }
  517. }
  518. }
  519. return lRes;
  520. }