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.

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