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.

1980 lines
50 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1993-1994
  4. *
  5. * TITLE: REGKEY.C
  6. *
  7. * VERSION: 4.01
  8. *
  9. * AUTHOR: Tracy Sharpe
  10. *
  11. * DATE: 05 Mar 1994
  12. *
  13. * KeyTreeWnd TreeView routines for the Registry Editor.
  14. *
  15. *******************************************************************************/
  16. #include "pch.h"
  17. #include "regedit.h"
  18. #include "regkey.h"
  19. #include "regvalue.h"
  20. #include "regresid.h"
  21. #define MAX_KEYNAME_TEMPLATE_ID 100
  22. #define SELCHANGE_TIMER_ID 1
  23. #define REFRESH_DPA_GROW 16
  24. VOID
  25. PASCAL
  26. RegEdit_OnKeyTreeDelete(
  27. HWND hWnd,
  28. HTREEITEM hTreeItem
  29. );
  30. VOID
  31. PASCAL
  32. RegEdit_OnKeyTreeRename(
  33. HWND hWnd,
  34. HTREEITEM hTreeItem
  35. );
  36. int
  37. WINAPI
  38. DPACompareKeyNames(
  39. LPVOID lpString1,
  40. LPVOID lpString2,
  41. LPARAM lParam
  42. );
  43. HTREEITEM
  44. PASCAL
  45. KeyTree_InsertItem(
  46. HWND hKeyTreeWnd,
  47. HTREEITEM hParent,
  48. HTREEITEM hInsertAfter,
  49. LPCTSTR lpText,
  50. UINT fHasKids,
  51. LPARAM lParam
  52. );
  53. BOOL
  54. PASCAL
  55. DoesKeyHaveKids(
  56. HKEY hKey,
  57. LPTSTR lpKeyName
  58. );
  59. VOID
  60. PASCAL
  61. KeyTree_EditLabel(
  62. HWND hKeyTreeWnd,
  63. HTREEITEM hTreeItem
  64. );
  65. BOOL
  66. PASCAL
  67. KeyTree_CanDeleteOrRenameItem(
  68. HWND hWnd,
  69. HTREEITEM hTreeItem
  70. );
  71. /*******************************************************************************
  72. *
  73. * RegEdit_OnNewKey
  74. *
  75. * DESCRIPTION:
  76. *
  77. * PARAMETERS:
  78. * hWnd, handle of RegEdit window.
  79. *
  80. *******************************************************************************/
  81. VOID
  82. PASCAL
  83. RegEdit_OnNewKey(
  84. HWND hWnd,
  85. HTREEITEM hTreeItem
  86. )
  87. {
  88. TCHAR KeyName[MAXKEYNAME*2];
  89. UINT cchKeyName = 0;
  90. HKEY hRootKey;
  91. HKEY hKey;
  92. UINT ErrorStringID;
  93. BOOL fNewKeyIsOnlyChild;
  94. UINT NewKeyNameID;
  95. HKEY hNewKey;
  96. HTREEITEM hNewTreeItem;
  97. TV_ITEM TVItem;
  98. hRootKey = KeyTree_BuildKeyPath(g_RegEditData.hKeyTreeWnd, hTreeItem,
  99. KeyName, BKP_TOSUBKEY);
  100. cchKeyName = lstrlen(KeyName);
  101. if(RegOpenKeyEx(hRootKey,KeyName,0,KEY_CREATE_SUB_KEY,&hKey) != ERROR_SUCCESS) {
  102. //
  103. // Get the text of the selected tree item so that we can display
  104. // a more meaningful error message.
  105. //
  106. TVItem.mask = TVIF_TEXT;
  107. TVItem.hItem = hTreeItem;
  108. TVItem.pszText = (LPTSTR) KeyName;
  109. TVItem.cchTextMax = sizeof(KeyName)/sizeof(TCHAR);
  110. TreeView_GetItem(g_RegEditData.hKeyTreeWnd, &TVItem);
  111. ErrorStringID = IDS_NEWKEYPARENTOPENFAILED;
  112. goto error_ShowDialog;
  113. }
  114. TVItem.mask = TVIF_STATE | TVIF_CHILDREN;
  115. TVItem.hItem = hTreeItem;
  116. TreeView_GetItem(g_RegEditData.hKeyTreeWnd, &TVItem);
  117. fNewKeyIsOnlyChild = FALSE;
  118. if (TVItem.cChildren == FALSE) {
  119. //
  120. // The selected key doesn't have any subkeys, so we can't do an expand
  121. // on it just yet. We'll just set a flag and later tag it with a
  122. // plus/minus icon and expand it.
  123. //
  124. fNewKeyIsOnlyChild = TRUE;
  125. }
  126. else if (!(TVItem.state & TVIS_EXPANDED)) {
  127. //
  128. // The selected key isn't expanded. Do it now so that we can do an
  129. // in-place edit and don't reenumerate the "New Key #xxx" after we do
  130. // the RegCreateKey.
  131. //
  132. TreeView_Expand(g_RegEditData.hKeyTreeWnd, hTreeItem, TVE_EXPAND);
  133. }
  134. if (RegEdit_GetTemporaryKeyName(hWnd, KeyName, hKey))
  135. {
  136. if((cchKeyName + lstrlen(KeyName) + 1) < MAXKEYNAME)
  137. {
  138. if (RegCreateKey(hKey, KeyName, &hNewKey) != ERROR_SUCCESS)
  139. {
  140. ErrorStringID = IDS_NEWKEYCANNOTCREATE;
  141. goto error_CloseKey;
  142. }
  143. RegCloseKey(hNewKey);
  144. if (fNewKeyIsOnlyChild)
  145. {
  146. TVItem.mask = TVIF_CHILDREN;
  147. TVItem.cChildren = TRUE;
  148. TreeView_SetItem(g_RegEditData.hKeyTreeWnd, &TVItem);
  149. TreeView_Expand(g_RegEditData.hKeyTreeWnd, hTreeItem, TVE_EXPAND);
  150. // WARNING: It is possible for our new item _not_ to be the only child
  151. // if our view is out of date!
  152. hNewTreeItem = TreeView_GetChild(g_RegEditData.hKeyTreeWnd, hTreeItem);
  153. }
  154. else
  155. {
  156. hNewTreeItem = KeyTree_InsertItem(g_RegEditData.hKeyTreeWnd, hTreeItem,
  157. TVI_LAST, KeyName, FALSE, 0);
  158. }
  159. TreeView_SelectItem(g_RegEditData.hKeyTreeWnd, hNewTreeItem);
  160. KeyTree_EditLabel(g_RegEditData.hKeyTreeWnd, hNewTreeItem);
  161. }
  162. else
  163. {
  164. ErrorStringID = IDS_RENAMEKEYTOOLONG;
  165. goto error_CloseKey;
  166. }
  167. }
  168. else
  169. {
  170. ErrorStringID = IDS_NEWKEYNOUNIQUE;
  171. goto error_CloseKey;
  172. }
  173. RegCloseKey(hKey);
  174. return;
  175. error_CloseKey:
  176. RegCloseKey(hKey);
  177. // FEATURE: For any errors that may crop up, we may need to turn off the
  178. // child flag.
  179. error_ShowDialog:
  180. InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
  181. MAKEINTRESOURCE(IDS_NEWKEYERRORTITLE), MB_ICONERROR | MB_OK,
  182. (LPTSTR) KeyName);
  183. }
  184. //------------------------------------------------------------------------------
  185. // RegEdit_GetTemporaryKeyName
  186. //
  187. // DESCRIPTION: Loop through the registry trying to find a valid temporary name
  188. // until the user renames the key.
  189. //
  190. // PARAMETERS: HWND hWnd - handle to window
  191. // PTSTR pszKeyName
  192. //
  193. // RETURN: True, if unique name is found
  194. //------------------------------------------------------------------------------
  195. BOOL RegEdit_GetTemporaryKeyName(HWND hWnd, PTSTR pszKeyName, HKEY hKey)
  196. {
  197. HKEY hNewKey;
  198. UINT uNewKeyNameID = 1;
  199. while (uNewKeyNameID < MAX_KEYNAME_TEMPLATE_ID)
  200. {
  201. wsprintf(pszKeyName, g_RegEditData.pNewKeyTemplate, uNewKeyNameID);
  202. if(RegOpenKeyEx(hKey, pszKeyName, 0, 0, &hNewKey) == ERROR_FILE_NOT_FOUND)
  203. {
  204. break;
  205. }
  206. RegCloseKey(hNewKey);
  207. uNewKeyNameID++;
  208. }
  209. if (uNewKeyNameID == MAX_KEYNAME_TEMPLATE_ID)
  210. {
  211. InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(IDS_NEWKEYNOUNIQUE),
  212. MAKEINTRESOURCE(IDS_NEWKEYERRORTITLE), MB_ICONERROR | MB_OK, pszKeyName);
  213. }
  214. return (uNewKeyNameID != MAX_KEYNAME_TEMPLATE_ID);
  215. }
  216. /*******************************************************************************
  217. *
  218. * RegEdit_OnKeyTreeItemExpanding
  219. *
  220. * DESCRIPTION:
  221. *
  222. * PARAMETERS:
  223. * hWnd, handle of RegEdit window.
  224. * lpNMTreeView, TreeView notification data.
  225. *
  226. *******************************************************************************/
  227. LRESULT
  228. PASCAL
  229. RegEdit_OnKeyTreeItemExpanding(
  230. HWND hWnd,
  231. LPNM_TREEVIEW lpNMTreeView
  232. )
  233. {
  234. HWND hKeyTreeWnd;
  235. HTREEITEM hExpandingTreeItem;
  236. TCHAR KeyName[MAXKEYNAME];
  237. TV_ITEM TVItem;
  238. hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
  239. hExpandingTreeItem = lpNMTreeView-> itemNew.hItem;
  240. //
  241. // Check if we're to expand the given tree item for the first time. If so,
  242. // delve into the registry to get all of the key's subkeys.
  243. //
  244. if (lpNMTreeView-> action & TVE_EXPAND && !(lpNMTreeView-> itemNew.state &
  245. TVIS_EXPANDEDONCE)) {
  246. if (TreeView_GetChild(hKeyTreeWnd, hExpandingTreeItem) != NULL)
  247. return FALSE;
  248. RegEdit_SetWaitCursor(TRUE);
  249. if (!KeyTree_ExpandBranch(hKeyTreeWnd, hExpandingTreeItem)) {
  250. //
  251. // Get the text of the selected tree item so that we can display
  252. // a more meaningful error message.
  253. //
  254. TVItem.mask = TVIF_TEXT;
  255. TVItem.hItem = hExpandingTreeItem;
  256. TVItem.pszText = (LPTSTR) KeyName;
  257. TVItem.cchTextMax = sizeof(KeyName)/sizeof(TCHAR);
  258. TreeView_GetItem(hKeyTreeWnd, &TVItem);
  259. InternalMessageBox(g_hInstance, hWnd,
  260. MAKEINTRESOURCE(IDS_OPENKEYCANNOTOPEN),
  261. MAKEINTRESOURCE(IDS_OPENKEYERRORTITLE), MB_ICONERROR | MB_OK,
  262. (LPTSTR) KeyName);
  263. }
  264. RegEdit_SetWaitCursor(FALSE);
  265. }
  266. return FALSE;
  267. }
  268. /*******************************************************************************
  269. *
  270. * RegEdit_OnKeyTreeSelChanged
  271. *
  272. * DESCRIPTION:
  273. * Depending on how the user has selected the new item in the KeyTreeWnd,
  274. * we call to the real worker routine, RegEdit_KeyTreeSelChanged, or delay
  275. * the call for several milliseconds.
  276. *
  277. * PARAMETERS:
  278. * hWnd, handle of RegEdit window.
  279. * lpNMTreeView, TreeView notification data.
  280. *
  281. *******************************************************************************/
  282. VOID
  283. PASCAL
  284. RegEdit_OnKeyTreeSelChanged(
  285. HWND hWnd,
  286. LPNM_TREEVIEW lpNMTreeView
  287. )
  288. {
  289. UINT TimerDelay;
  290. //
  291. // We delay the actual update of the selection and thus of the
  292. // ValueListWnd for several milliseconds. This avoids unnecessary flashing
  293. // as the user scrolls through the tree. (This behavior is directly taken
  294. // from the Explorer.)
  295. //
  296. switch (g_RegEditData.SelChangeTimerState) {
  297. case SCTS_TIMERSET:
  298. KillTimer(hWnd, SELCHANGE_TIMER_ID);
  299. // FALL THROUGH
  300. case SCTS_TIMERCLEAR:
  301. #ifdef WINNT
  302. //
  303. // This behavior is extremely annoying so I am changing it.
  304. //
  305. TimerDelay = 1;
  306. #else
  307. TimerDelay = (lpNMTreeView != NULL && lpNMTreeView-> action ==
  308. TVC_BYMOUSE) ? (1) : (GetDoubleClickTime() * 3 / 2);
  309. #endif
  310. SetTimer(hWnd, SELCHANGE_TIMER_ID, TimerDelay, NULL);
  311. g_RegEditData.SelChangeTimerState = SCTS_TIMERSET;
  312. break;
  313. //
  314. // We want to punt the first selection change notification that comes
  315. // through.
  316. //
  317. case SCTS_INITIALIZING:
  318. RegEdit_KeyTreeSelChanged(hWnd);
  319. break;
  320. }
  321. }
  322. /*******************************************************************************
  323. *
  324. * RegEdit_OnSelChangedTimer
  325. *
  326. * DESCRIPTION:
  327. * Called several milliseconds after a keyboard operation has selected a new
  328. * item in the KeyTreeWnd. Act as if a new selection has just been made in
  329. * the KeyTreeWnd.
  330. *
  331. * PARAMETERS:
  332. * hWnd, handle of RegEdit window.
  333. *
  334. *******************************************************************************/
  335. VOID
  336. PASCAL
  337. RegEdit_OnSelChangedTimer(
  338. HWND hWnd
  339. )
  340. {
  341. KillTimer(hWnd, SELCHANGE_TIMER_ID);
  342. g_RegEditData.SelChangeTimerState = SCTS_TIMERCLEAR;
  343. RegEdit_KeyTreeSelChanged(hWnd);
  344. }
  345. /*******************************************************************************
  346. *
  347. * RegEdit_KeyTreeSelChanged
  348. *
  349. * DESCRIPTION:
  350. * Called after a new item has been selected in the KeyTreeWnd. Opens a
  351. * registry key to the new branch and notifies the ValueListWnd to update
  352. * itself.
  353. *
  354. * PARAMETERS:
  355. * hWnd, handle of RegEdit window.
  356. *
  357. *******************************************************************************/
  358. VOID
  359. PASCAL
  360. RegEdit_KeyTreeSelChanged(
  361. HWND hWnd
  362. )
  363. {
  364. HWND hKeyTreeWnd;
  365. HTREEITEM hSelectedTreeItem;
  366. RECT ItemRect;
  367. RECT ClientRect;
  368. RECT FromRect;
  369. RECT ToRect;
  370. HKEY hRootKey;
  371. TCHAR KeyName[MAXKEYNAME];
  372. TV_ITEM TVItem;
  373. hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
  374. hSelectedTreeItem = TreeView_GetSelection(hKeyTreeWnd);
  375. if (g_RegEditData.SelChangeTimerState != SCTS_INITIALIZING) {
  376. //
  377. // Draw an animation that shows the "expansion" of the newly selected
  378. // tree item to the ListView.
  379. //
  380. TreeView_GetItemRect(hKeyTreeWnd, hSelectedTreeItem, &ItemRect, TRUE);
  381. GetClientRect(hKeyTreeWnd, &ClientRect);
  382. IntersectRect(&FromRect, &ClientRect, &ItemRect);
  383. MapWindowPoints(hKeyTreeWnd, hWnd, (LPPOINT) &FromRect, 2);
  384. GetWindowRect(g_RegEditData.hValueListWnd, &ToRect);
  385. MapWindowPoints(NULL, hWnd, (LPPOINT) &ToRect, 2);
  386. DrawAnimatedRects(hWnd, IDANI_OPEN, &FromRect, &ToRect);
  387. }
  388. //
  389. // Close the previously selected item's key handle, if appropriate.
  390. //
  391. if (g_RegEditData.hCurrentSelectionKey != NULL) {
  392. RegCloseKey(g_RegEditData.hCurrentSelectionKey);
  393. g_RegEditData.hCurrentSelectionKey = NULL;
  394. }
  395. RegEdit_UpdateStatusBar();
  396. //
  397. // Simple case-- we're changing to one of the top-level labels, such as
  398. // "My Computer" or a network computer name. Right now, nothing is
  399. // displayed in the ListView, so just empty it and return.
  400. //
  401. if (TreeView_GetParent(hKeyTreeWnd, hSelectedTreeItem) != NULL) {
  402. //
  403. // Build a registry path to the selected tree item and open a registry
  404. // key.
  405. //
  406. hRootKey = KeyTree_BuildKeyPath(hKeyTreeWnd, hSelectedTreeItem,
  407. KeyName, BKP_TOSUBKEY);
  408. if(RegOpenKeyEx(hRootKey,KeyName, 0, MAXIMUM_ALLOWED,
  409. &g_RegEditData.hCurrentSelectionKey) != ERROR_SUCCESS) {
  410. //
  411. // Get the text of the selected tree item so that we can display
  412. // a more meaningful error message.
  413. //
  414. TVItem.mask = TVIF_TEXT;
  415. TVItem.hItem = hSelectedTreeItem;
  416. TVItem.pszText = (LPTSTR) KeyName;
  417. TVItem.cchTextMax = sizeof(KeyName)/sizeof(TCHAR);
  418. TreeView_GetItem(hKeyTreeWnd, &TVItem);
  419. InternalMessageBox(g_hInstance, hWnd,
  420. MAKEINTRESOURCE(IDS_OPENKEYCANNOTOPEN),
  421. MAKEINTRESOURCE(IDS_OPENKEYERRORTITLE), MB_ICONERROR | MB_OK,
  422. (LPTSTR) KeyName);
  423. }
  424. }
  425. RegEdit_OnValueListRefresh(hWnd);
  426. }
  427. /*******************************************************************************
  428. *
  429. * RegEdit_OnKeyTreeBeginLabelEdit
  430. *
  431. * DESCRIPTION:
  432. *
  433. * PARAMETERS:
  434. * hWnd, handle of RegEdit window.
  435. * lpTVDispInfo,
  436. *
  437. *******************************************************************************/
  438. BOOL
  439. PASCAL
  440. RegEdit_OnKeyTreeBeginLabelEdit(
  441. HWND hWnd,
  442. TV_DISPINFO FAR* lpTVDispInfo
  443. )
  444. {
  445. //
  446. // B#7933: We don't want the user to hurt themselves by making it too easy
  447. // to rename keys and values. Only allow renames via the menus.
  448. //
  449. //
  450. // We don't get any information on the source of this editing action, so
  451. // we must maintain a flag that tells us whether or not this is "good".
  452. //
  453. if (!g_RegEditData.fAllowLabelEdits)
  454. return TRUE;
  455. //
  456. // All other labels are fair game. We need to disable our keyboard
  457. // accelerators so that the edit control can "see" them.
  458. //
  459. g_fDisableAccelerators = TRUE;
  460. return FALSE;
  461. }
  462. /*******************************************************************************
  463. *
  464. * RegEdit_OnKeyTreeEndLabelEdit
  465. *
  466. * DESCRIPTION:
  467. *
  468. * PARAMETERS:
  469. * hWnd, handle of RegEdit window.
  470. * lpTVDispInfo,
  471. *
  472. *******************************************************************************/
  473. BOOL
  474. PASCAL
  475. RegEdit_OnKeyTreeEndLabelEdit(
  476. HWND hWnd,
  477. TV_DISPINFO FAR* lpTVDispInfo
  478. )
  479. {
  480. HWND hKeyTreeWnd;
  481. HKEY hRootKey;
  482. TCHAR SourceKeyName[MAXKEYNAME*2];
  483. TCHAR DestinationKeyName[MAXKEYNAME];
  484. HKEY hSourceKey;
  485. HKEY hDestinationKey;
  486. LPTSTR lpEndOfParentKey;
  487. UINT ErrorStringID;
  488. TV_ITEM TVItem;
  489. //
  490. // We can reenable our keyboard accelerators now that the edit control no
  491. // longer needs to "see" them.
  492. //
  493. g_fDisableAccelerators = FALSE;
  494. hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
  495. //
  496. // Check to see if the user cancelled the edit. If so, we don't care so
  497. // just return.
  498. //
  499. if (lpTVDispInfo-> item.pszText == NULL)
  500. return FALSE;
  501. //
  502. // Attempt to open the key to be renamed. This may or may not be the same
  503. // key that is already open.
  504. //
  505. hRootKey = KeyTree_BuildKeyPath(hKeyTreeWnd, lpTVDispInfo-> item.hItem,
  506. SourceKeyName, BKP_TOSUBKEY);
  507. if (lstrlen(SourceKeyName) >= MAXKEYNAME) {
  508. ErrorStringID = IDS_RENAMEKEYTOOLONG;
  509. goto error_ShowDialog;
  510. }
  511. if(RegOpenKeyEx(hRootKey,SourceKeyName,0,KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,&hSourceKey) != ERROR_SUCCESS) {
  512. ErrorStringID = IDS_RENAMEKEYOTHERERROR;
  513. goto error_ShowDialog;
  514. }
  515. //
  516. // Take the full path name of the key (relative to a predefined root key)
  517. // and replace the old key name with the new. Make sure that this key
  518. // doesn't exceed our internal buffers.
  519. //
  520. lstrcpy(DestinationKeyName, SourceKeyName);
  521. if ((lpEndOfParentKey = StrRChr(DestinationKeyName, NULL, TEXT('\\'))) != NULL)
  522. lpEndOfParentKey++;
  523. else
  524. lpEndOfParentKey = DestinationKeyName;
  525. *lpEndOfParentKey = 0;
  526. if (lstrlen(DestinationKeyName) + lstrlen(lpTVDispInfo-> item.pszText) >= MAXKEYNAME) {
  527. ErrorStringID = IDS_RENAMEKEYTOOLONG;
  528. goto error_CloseSourceKey;
  529. }
  530. lstrcpy(lpEndOfParentKey, lpTVDispInfo-> item.pszText);
  531. //
  532. // Make sure there are no backslashes in the name.
  533. //
  534. if (StrChr(lpEndOfParentKey, TEXT('\\')) != NULL) {
  535. ErrorStringID = IDS_RENAMEKEYBADCHARS;
  536. goto error_CloseSourceKey;
  537. }
  538. //
  539. // Make sure there the name isn't empty
  540. //
  541. if (DestinationKeyName[0] == 0) {
  542. ErrorStringID = IDS_RENAMEKEYEMPTY;
  543. goto error_CloseSourceKey;
  544. }
  545. //
  546. // Make sure that the destination doesn't already exist.
  547. //
  548. if(RegOpenKeyEx(hRootKey,DestinationKeyName,0,KEY_QUERY_VALUE,&hDestinationKey) ==
  549. ERROR_SUCCESS) {
  550. RegCloseKey(hDestinationKey);
  551. ErrorStringID = IDS_RENAMEKEYEXISTS;
  552. goto error_CloseSourceKey;
  553. }
  554. //
  555. // Create the destination key and do the copy.
  556. //
  557. if (RegCreateKey(hRootKey, DestinationKeyName, &hDestinationKey) !=
  558. ERROR_SUCCESS) {
  559. ErrorStringID = IDS_RENAMEKEYOTHERERROR;
  560. goto error_CloseSourceKey;
  561. }
  562. // FEATURE: Check this return (when it gets one!)
  563. if (!CopyRegistry(hSourceKey, hDestinationKey))
  564. {
  565. RegCloseKey(hDestinationKey);
  566. RegCloseKey(hSourceKey);
  567. ErrorStringID = IDS_RENAMEKEYOTHERERROR;
  568. goto error_ShowDialog;
  569. }
  570. RegCloseKey(hSourceKey);
  571. //
  572. // Check to see if we're renaming the currently selected key. If so, toss
  573. // our cached key handle and change to our source key.
  574. //
  575. if (TreeView_GetSelection(hKeyTreeWnd) == lpTVDispInfo-> item.hItem) {
  576. RegCloseKey(g_RegEditData.hCurrentSelectionKey);
  577. g_RegEditData.hCurrentSelectionKey = hDestinationKey;
  578. //
  579. // We can't just call RegEdit_UpdateStatusBar here... the tree item
  580. // won't be updated until we return TRUE from this message. So we must
  581. // post a message to tell ourselves to do the update later on.
  582. //
  583. PostMessage(hWnd, REM_UPDATESTATUSBAR, 0, 0);
  584. }
  585. else
  586. RegCloseKey(hDestinationKey);
  587. if (RegDeleteKeyRecursive(hRootKey, SourceKeyName) != ERROR_SUCCESS) {
  588. ErrorStringID = IDS_RENAMEKEYOTHERERROR;
  589. goto error_ShowDialog;
  590. }
  591. return TRUE;
  592. error_CloseSourceKey:
  593. RegCloseKey(hSourceKey);
  594. error_ShowDialog:
  595. TVItem.hItem = lpTVDispInfo-> item.hItem;
  596. TVItem.mask = TVIF_TEXT;
  597. TVItem.pszText = SourceKeyName;
  598. TVItem.cchTextMax = sizeof(SourceKeyName)/sizeof(TCHAR);
  599. TreeView_GetItem(hKeyTreeWnd, &TVItem);
  600. InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
  601. MAKEINTRESOURCE(IDS_RENAMEKEYERRORTITLE), MB_ICONERROR | MB_OK,
  602. (LPTSTR) SourceKeyName);
  603. return FALSE;
  604. }
  605. /*******************************************************************************
  606. *
  607. * RegEdit_OnKeyTreeCommand
  608. *
  609. * DESCRIPTION:
  610. * Handles the selection of a menu item by the user intended for the
  611. * KeyTree child window.
  612. *
  613. * PARAMETERS:
  614. * hWnd, handle of RegEdit window.
  615. * MenuCommand, identifier of menu command.
  616. * hTreeItem,
  617. *
  618. *******************************************************************************/
  619. VOID
  620. PASCAL
  621. RegEdit_OnKeyTreeCommand(
  622. HWND hWnd,
  623. int MenuCommand,
  624. HTREEITEM hTreeItem
  625. )
  626. {
  627. HWND hKeyTreeWnd;
  628. hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
  629. //
  630. // Assume that the we mean the current selection if we're to dispatch a
  631. // command that requires a tree item. This is necessary because the tree
  632. // control will let you activate the context menu of one tree item while
  633. // another one is really the selected tree item.
  634. //
  635. if (hTreeItem == NULL)
  636. hTreeItem = TreeView_GetSelection(hKeyTreeWnd);
  637. switch (MenuCommand) {
  638. case ID_CONTEXTMENU:
  639. RegEdit_OnKeyTreeContextMenu(hWnd, TRUE);
  640. break;
  641. case ID_TOGGLE:
  642. TreeView_Expand(hKeyTreeWnd, hTreeItem, TVE_TOGGLE);
  643. break;
  644. case ID_DELETE:
  645. RegEdit_OnKeyTreeDelete(hWnd, hTreeItem);
  646. break;
  647. case ID_RENAME:
  648. RegEdit_OnKeyTreeRename(hWnd, hTreeItem);
  649. break;
  650. case ID_DISCONNECT:
  651. RegEdit_OnKeyTreeDisconnect(hWnd, hTreeItem);
  652. break;
  653. case ID_COPYKEYNAME:
  654. RegEdit_OnCopyKeyName(hWnd, hTreeItem);
  655. break;
  656. case ID_NEWKEY:
  657. RegEdit_OnNewKey(hWnd, hTreeItem);
  658. break;
  659. case ID_NEWSTRINGVALUE:
  660. case ID_NEWBINARYVALUE:
  661. if (hTreeItem != TreeView_GetSelection(hKeyTreeWnd)) {
  662. //
  663. // Force the selection to occur now, so that we're dealing
  664. // with the right open key.
  665. //
  666. TreeView_SelectItem(hKeyTreeWnd, hTreeItem);
  667. RegEdit_OnSelChangedTimer(hWnd);
  668. }
  669. // FALL THROUGH
  670. default:
  671. //
  672. // Check to see if this menu command should be handled by the main
  673. // window's command handler.
  674. //
  675. if (MenuCommand >= ID_FIRSTMAINMENUITEM && MenuCommand <=
  676. ID_LASTMAINMENUITEM)
  677. RegEdit_OnCommand(hWnd, MenuCommand, NULL, 0);
  678. break;
  679. }
  680. }
  681. /*******************************************************************************
  682. *
  683. * RegEdit_OnKeyTreeContextMenu
  684. *
  685. * DESCRIPTION:
  686. *
  687. * PARAMETERS:
  688. *
  689. *******************************************************************************/
  690. VOID
  691. PASCAL
  692. RegEdit_OnKeyTreeContextMenu(
  693. HWND hWnd,
  694. BOOL fByAccelerator
  695. )
  696. {
  697. HWND hKeyTreeWnd;
  698. DWORD MessagePos;
  699. POINT MessagePoint;
  700. TV_HITTESTINFO TVHitTestInfo;
  701. UINT MenuID;
  702. HMENU hContextMenu;
  703. HMENU hContextPopupMenu;
  704. TV_ITEM TVItem;
  705. int MenuCommand;
  706. hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
  707. //
  708. // If fByAcclerator is TRUE, then the user hit Shift-F10 to bring up the
  709. // context menu. Following the Cabinet's convention, this menu is
  710. // placed at (0,0) of the KeyTree client area.
  711. //
  712. if (fByAccelerator) {
  713. MessagePoint.x = 0;
  714. MessagePoint.y = 0;
  715. ClientToScreen(hKeyTreeWnd, &MessagePoint);
  716. TVItem.hItem = TreeView_GetSelection(hKeyTreeWnd);
  717. }
  718. else {
  719. MessagePos = GetMessagePos();
  720. MessagePoint.x = GET_X_LPARAM(MessagePos);
  721. MessagePoint.y = GET_Y_LPARAM(MessagePos);
  722. TVHitTestInfo.pt = MessagePoint;
  723. ScreenToClient(hKeyTreeWnd, &TVHitTestInfo.pt);
  724. TVItem.hItem = TreeView_HitTest(hKeyTreeWnd, &TVHitTestInfo);
  725. }
  726. //
  727. // Determine which context menu to use and load it up.
  728. //
  729. if (TVItem.hItem == NULL)
  730. {
  731. return; // No context menu for now
  732. }
  733. else
  734. {
  735. // Select the item to be dragged
  736. TreeView_Select(g_RegEditData.hKeyTreeWnd, TVItem.hItem, TVGN_CARET);
  737. if (TreeView_GetParent(hKeyTreeWnd, TVItem.hItem) == NULL)
  738. MenuID = IDM_COMPUTER_CONTEXT;
  739. else
  740. MenuID = IDM_KEY_CONTEXT;
  741. }
  742. if ((hContextMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(MenuID))) == NULL)
  743. return;
  744. hContextPopupMenu = GetSubMenu(hContextMenu, 0);
  745. TVItem.mask = TVIF_STATE | TVIF_CHILDREN;
  746. TreeView_GetItem(hKeyTreeWnd, &TVItem);
  747. if (TVItem.state & TVIS_EXPANDED)
  748. ModifyMenu(hContextPopupMenu, ID_TOGGLE, MF_BYCOMMAND | MF_STRING,
  749. ID_TOGGLE, g_RegEditData.pCollapse);
  750. if (MenuID == IDM_COMPUTER_CONTEXT) {
  751. if (g_RegEditData.fHaveNetwork) {
  752. if (TreeView_GetPrevSibling(hKeyTreeWnd, TVItem.hItem) == NULL)
  753. EnableMenuItem(hContextPopupMenu, ID_DISCONNECT, MF_GRAYED |
  754. MF_BYCOMMAND);
  755. }
  756. else {
  757. DeleteMenu(hContextPopupMenu, ID_DISCONNECT, MF_BYCOMMAND);
  758. DeleteMenu(hContextPopupMenu, ID_NETSEPARATOR, MF_BYCOMMAND);
  759. }
  760. }
  761. else {
  762. RegEdit_SetKeyTreeEditMenuItems(hContextPopupMenu, TVItem.hItem);
  763. if (TVItem.cChildren == 0)
  764. EnableMenuItem(hContextPopupMenu, ID_TOGGLE, MF_GRAYED |
  765. MF_BYCOMMAND);
  766. }
  767. SetMenuDefaultItem(hContextPopupMenu, ID_TOGGLE, MF_BYCOMMAND);
  768. MenuCommand = TrackPopupMenuEx(hContextPopupMenu, TPM_RETURNCMD |
  769. TPM_RIGHTBUTTON | TPM_LEFTALIGN | TPM_TOPALIGN, MessagePoint.x,
  770. MessagePoint.y, hWnd, NULL);
  771. DestroyMenu(hContextMenu);
  772. RegEdit_OnKeyTreeCommand(hWnd, MenuCommand, TVItem.hItem);
  773. }
  774. /*******************************************************************************
  775. *
  776. * RegEdit_SetKeyTreeEditMenuItems
  777. *
  778. * DESCRIPTION:
  779. * Shared routine between the main menu and the context menu to setup the
  780. * edit menu items.
  781. *
  782. * PARAMETERS:
  783. * hPopupMenu, handle of popup menu to modify.
  784. * hTreeItem, handle of selected tree item.
  785. *
  786. *******************************************************************************/
  787. VOID
  788. PASCAL
  789. RegEdit_SetKeyTreeEditMenuItems(
  790. HMENU hPopupMenu,
  791. HTREEITEM hSelectedTreeItem
  792. )
  793. {
  794. UINT EnableFlags;
  795. EnableFlags = KeyTree_CanDeleteOrRenameItem(g_RegEditData.hKeyTreeWnd,
  796. hSelectedTreeItem) ? (MF_ENABLED | MF_BYCOMMAND) :
  797. (MF_GRAYED | MF_BYCOMMAND);
  798. EnableMenuItem(hPopupMenu, ID_DELETE, EnableFlags);
  799. EnableMenuItem(hPopupMenu, ID_RENAME, EnableFlags);
  800. }
  801. /*******************************************************************************
  802. *
  803. * RegEdit_OnKeyTreeDelete
  804. *
  805. * DESCRIPTION:
  806. *
  807. * PARAMETERS:
  808. *
  809. *******************************************************************************/
  810. VOID
  811. PASCAL
  812. RegEdit_OnKeyTreeDelete(
  813. HWND hWnd,
  814. HTREEITEM hTreeItem
  815. )
  816. {
  817. HWND hKeyTreeWnd;
  818. HKEY hRootKey;
  819. TCHAR KeyName[MAXKEYNAME];
  820. HTREEITEM hParentTreeItem;
  821. TV_ITEM TVItem;
  822. hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
  823. if (!KeyTree_CanDeleteOrRenameItem(hKeyTreeWnd, hTreeItem))
  824. return;
  825. if (InternalMessageBox(g_hInstance, hWnd,
  826. MAKEINTRESOURCE(IDS_CONFIRMDELKEYTEXT),
  827. MAKEINTRESOURCE(IDS_CONFIRMDELKEYTITLE), MB_ICONWARNING | MB_YESNO) !=
  828. IDYES)
  829. return;
  830. if (hTreeItem == TreeView_GetSelection(hKeyTreeWnd)) {
  831. if (g_RegEditData.hCurrentSelectionKey != NULL) {
  832. RegCloseKey(g_RegEditData.hCurrentSelectionKey);
  833. g_RegEditData.hCurrentSelectionKey = NULL;
  834. }
  835. }
  836. hRootKey = KeyTree_BuildKeyPath(hKeyTreeWnd, hTreeItem, KeyName,
  837. BKP_TOSUBKEY);
  838. if (RegDeleteKeyRecursive(hRootKey, KeyName) == ERROR_SUCCESS) {
  839. SetWindowRedraw(hKeyTreeWnd, FALSE);
  840. hParentTreeItem = TreeView_GetParent(hKeyTreeWnd, hTreeItem);
  841. TreeView_DeleteItem(hKeyTreeWnd, hTreeItem);
  842. //
  843. // See if the key that we just deleted was the last child of its
  844. // parent. If so, remove the expand/collapse button.
  845. //
  846. if (TreeView_GetChild(hKeyTreeWnd, hParentTreeItem) == NULL) {
  847. TVItem.mask = TVIF_CHILDREN | TVIF_STATE;
  848. TVItem.hItem = hParentTreeItem;
  849. TVItem.cChildren = 0;
  850. TVItem.state = 0;
  851. TVItem.stateMask = TVIS_EXPANDED | TVIS_EXPANDEDONCE;
  852. TreeView_SetItem(hKeyTreeWnd, &TVItem);
  853. }
  854. //
  855. // Make sure we can see the selected tree item now since it may be
  856. // currently off-screen.
  857. //
  858. TreeView_EnsureVisible(hKeyTreeWnd, TreeView_GetSelection(hKeyTreeWnd));
  859. SetWindowRedraw(hKeyTreeWnd, TRUE);
  860. UpdateWindow(hKeyTreeWnd);
  861. }
  862. else {
  863. TVItem.hItem = hTreeItem;
  864. TVItem.mask = TVIF_TEXT;
  865. TVItem.pszText = KeyName;
  866. TVItem.cchTextMax = sizeof(KeyName)/sizeof(TCHAR);
  867. TreeView_GetItem(hKeyTreeWnd, &TVItem);
  868. InternalMessageBox(g_hInstance, hWnd,
  869. MAKEINTRESOURCE(IDS_DELETEKEYDELETEFAILED),
  870. MAKEINTRESOURCE(IDS_DELETEKEYERRORTITLE), MB_ICONERROR | MB_OK,
  871. KeyName);
  872. //
  873. // Need to refresh the tree at this point, as some subkeys may have
  874. // been deleted successfully even if we didn't have sufficient
  875. // permissions to delete all of them.
  876. //
  877. RegEdit_OnKeyTreeRefresh(hWnd);
  878. }
  879. }
  880. /*******************************************************************************
  881. *
  882. * RegEdit_OnKeyTreeRename
  883. *
  884. * DESCRIPTION:
  885. *
  886. * PARAMETERS:
  887. *
  888. *******************************************************************************/
  889. VOID
  890. PASCAL
  891. RegEdit_OnKeyTreeRename(
  892. HWND hWnd,
  893. HTREEITEM hTreeItem
  894. )
  895. {
  896. if (KeyTree_CanDeleteOrRenameItem(g_RegEditData.hKeyTreeWnd, hTreeItem))
  897. KeyTree_EditLabel(g_RegEditData.hKeyTreeWnd, hTreeItem);
  898. }
  899. /*******************************************************************************
  900. *
  901. * RegEdit_OnKeyTreeRefresh
  902. *
  903. * DESCRIPTION:
  904. *
  905. * PARAMETERS:
  906. *
  907. *******************************************************************************/
  908. VOID
  909. PASCAL
  910. RegEdit_OnKeyTreeRefresh(
  911. HWND hWnd
  912. )
  913. {
  914. HDPA hDPA;
  915. HWND hKeyTreeWnd;
  916. HTREEITEM hPrevSelectedTreeItem;
  917. TV_ITEM EnumTVItem;
  918. TV_ITEM CurrentTVItem;
  919. HKEY hRootKey;
  920. TCHAR KeyName[MAXKEYNAME];
  921. int MaximumSubKeyLength;
  922. int Index;
  923. HKEY hEnumKey;
  924. int CompareResult;
  925. LPTSTR lpDPAKeyName;
  926. HTREEITEM hTempTreeItem;
  927. if ((hDPA = DPA_CreateEx(REFRESH_DPA_GROW, GetProcessHeap())) == NULL)
  928. return;
  929. hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
  930. RegEdit_SetWaitCursor(TRUE);
  931. SetWindowRedraw(hKeyTreeWnd, FALSE);
  932. hPrevSelectedTreeItem = TreeView_GetSelection(hKeyTreeWnd);
  933. EnumTVItem.mask = TVIF_TEXT;
  934. EnumTVItem.pszText = KeyName;
  935. EnumTVItem.cchTextMax = sizeof(KeyName)/sizeof(TCHAR);
  936. CurrentTVItem.mask = TVIF_STATE | TVIF_CHILDREN;
  937. CurrentTVItem.stateMask = 0;
  938. CurrentTVItem.hItem = TreeView_GetRoot(hKeyTreeWnd);
  939. while (TRUE) {
  940. TreeView_GetItem(hKeyTreeWnd, &CurrentTVItem);
  941. hRootKey = KeyTree_BuildKeyPath(hKeyTreeWnd, CurrentTVItem.hItem,
  942. KeyName, BKP_TOSUBKEY);
  943. if (CurrentTVItem.state & TVIS_EXPANDED) {
  944. //
  945. // If this isn't a top-level label (and it won't be if hRootKey is
  946. // not NULL), then compare the actual contents of the registry
  947. // against what we're showing.
  948. //
  949. if(hRootKey && RegOpenKeyEx(hRootKey,KeyName,0,KEY_ENUMERATE_SUB_KEYS,&hEnumKey) ==
  950. ERROR_SUCCESS) {
  951. //
  952. // As a result of adding new keys and renaming existing ones,
  953. // the children of this item may be out of order. For the
  954. // following algorithm to work correctly, we must now sort
  955. // these keys.
  956. //
  957. TreeView_SortChildren(hKeyTreeWnd, CurrentTVItem.hItem, FALSE);
  958. //
  959. // Build a sorted dynamic array of strings that represent the
  960. // keys actually in the registry at this time.
  961. //
  962. MaximumSubKeyLength = MAXKEYNAME - (lstrlen(KeyName) + 1);
  963. Index = 0;
  964. while (RegEnumKey(hEnumKey, Index, KeyName,
  965. MaximumSubKeyLength) == ERROR_SUCCESS) {
  966. lpDPAKeyName = NULL;
  967. Str_SetPtr(&lpDPAKeyName, KeyName);
  968. DPA_InsertPtr(hDPA, Index++, lpDPAKeyName);
  969. }
  970. RegCloseKey(hEnumKey);
  971. DPA_Sort(hDPA, DPACompareKeyNames, 0);
  972. //
  973. // Does this key have subkeys anymore? If not, then we need
  974. // to reset it's child flag and remove all of it's children.
  975. //
  976. if (Index == 0) {
  977. DPA_DeleteAllPtrs(hDPA);
  978. TreeView_Expand(hKeyTreeWnd, CurrentTVItem.hItem,
  979. TVE_COLLAPSE | TVE_COLLAPSERESET);
  980. CurrentTVItem.cChildren = 0;
  981. goto SetCurrentTreeItem;
  982. }
  983. //
  984. // Merge the keys that we found during our above enumeration
  985. // with the keys that our key tree lists. Add and remove
  986. // elements from the tree as appropriate.
  987. //
  988. lpDPAKeyName = DPA_FastGetPtr(hDPA, --Index);
  989. EnumTVItem.hItem = TreeView_GetChild(hKeyTreeWnd,
  990. CurrentTVItem.hItem);
  991. if (EnumTVItem.hItem)
  992. TreeView_GetItem(hKeyTreeWnd, &EnumTVItem);
  993. while (Index >= 0 && EnumTVItem.hItem != NULL) {
  994. CompareResult = lstrcmpi(KeyName, lpDPAKeyName);
  995. if (CompareResult == 0) {
  996. EnumTVItem.hItem = TreeView_GetNextSibling(hKeyTreeWnd,
  997. EnumTVItem.hItem);
  998. if (EnumTVItem.hItem)
  999. TreeView_GetItem(hKeyTreeWnd, &EnumTVItem);
  1000. goto GetNextDPAPointer;
  1001. }
  1002. else if (CompareResult > 0) {
  1003. KeyTree_InsertItem(hKeyTreeWnd, CurrentTVItem.hItem,
  1004. TVI_SORT, lpDPAKeyName, DoesKeyHaveKids(hEnumKey,
  1005. lpDPAKeyName), 0);
  1006. GetNextDPAPointer:
  1007. Str_SetPtr(&lpDPAKeyName, NULL);
  1008. if (--Index >= 0)
  1009. lpDPAKeyName = DPA_FastGetPtr(hDPA, Index);
  1010. }
  1011. else {
  1012. hTempTreeItem = TreeView_GetNextSibling(hKeyTreeWnd,
  1013. EnumTVItem.hItem);
  1014. TreeView_DeleteItem(hKeyTreeWnd, EnumTVItem.hItem);
  1015. EnumTVItem.hItem = hTempTreeItem;
  1016. if (EnumTVItem.hItem)
  1017. TreeView_GetItem(hKeyTreeWnd, &EnumTVItem);
  1018. }
  1019. }
  1020. //
  1021. // Once we drop to here, we may have extra items in the key
  1022. // tree or in the dynamic array. Process them accordingly.
  1023. //
  1024. if (Index >= 0) {
  1025. while (TRUE) {
  1026. KeyTree_InsertItem(hKeyTreeWnd, CurrentTVItem.hItem,
  1027. TVI_SORT, lpDPAKeyName, DoesKeyHaveKids(hEnumKey,
  1028. lpDPAKeyName), 0);
  1029. Str_SetPtr(&lpDPAKeyName, NULL);
  1030. if (--Index < 0)
  1031. break;
  1032. lpDPAKeyName = DPA_FastGetPtr(hDPA, Index);
  1033. }
  1034. }
  1035. else {
  1036. while (EnumTVItem.hItem != NULL) {
  1037. hTempTreeItem = TreeView_GetNextSibling(hKeyTreeWnd,
  1038. EnumTVItem.hItem);
  1039. TreeView_DeleteItem(hKeyTreeWnd, EnumTVItem.hItem);
  1040. EnumTVItem.hItem = hTempTreeItem;
  1041. }
  1042. }
  1043. DPA_DeleteAllPtrs(hDPA);
  1044. }
  1045. CurrentTVItem.hItem = TreeView_GetChild(hKeyTreeWnd,
  1046. CurrentTVItem.hItem);
  1047. }
  1048. else {
  1049. //
  1050. // If this isn't a top-level label (and it won't be if hRootKey is
  1051. // not NULL), then re-check if this key has any children.
  1052. //
  1053. if (hRootKey != NULL) {
  1054. TreeView_Expand(hKeyTreeWnd, CurrentTVItem.hItem, TVE_COLLAPSE |
  1055. TVE_COLLAPSERESET);
  1056. CurrentTVItem.cChildren = DoesKeyHaveKids(hRootKey, KeyName);
  1057. SetCurrentTreeItem:
  1058. TreeView_SetItem(hKeyTreeWnd, &CurrentTVItem);
  1059. }
  1060. //
  1061. // Because we're at the "bottom" of the TreeView, we now need to
  1062. // walk to the siblings of this tree item. And if no siblings
  1063. // exist, we walk back to the parent and check again for siblings.
  1064. //
  1065. while (TRUE) {
  1066. if ((hTempTreeItem = TreeView_GetNextSibling(hKeyTreeWnd,
  1067. CurrentTVItem.hItem)) != NULL) {
  1068. CurrentTVItem.hItem = hTempTreeItem;
  1069. break;
  1070. }
  1071. if ((CurrentTVItem.hItem = TreeView_GetParent(hKeyTreeWnd,
  1072. CurrentTVItem.hItem)) == NULL) {
  1073. //
  1074. // We've now walked over all of the tree items, so do any
  1075. // cleanup here and exit.
  1076. //
  1077. DPA_Destroy(hDPA);
  1078. SetWindowRedraw(hKeyTreeWnd, TRUE);
  1079. //
  1080. // The selection may have changed as a result of having
  1081. // the focus on an nonexistent key.
  1082. //
  1083. if (TreeView_GetSelection(hKeyTreeWnd) != hPrevSelectedTreeItem) {
  1084. RegEdit_OnKeyTreeSelChanged(hWnd, NULL);
  1085. } else {
  1086. if (RegEdit_OnValueListRefresh(hWnd) != ERROR_SUCCESS) {
  1087. //
  1088. // Its possible that the registry key was deleted and replaced with
  1089. // an identically-named key. We should just trigger a selection
  1090. // change in this case.
  1091. //
  1092. RegEdit_OnKeyTreeSelChanged(hWnd, NULL);
  1093. }
  1094. }
  1095. RegEdit_SetWaitCursor(FALSE);
  1096. return;
  1097. }
  1098. }
  1099. }
  1100. }
  1101. }
  1102. /*******************************************************************************
  1103. *
  1104. * DPACompareKeyNames
  1105. *
  1106. * DESCRIPTION:
  1107. * Callback comparision routine for refresh's DPA_Sort call. Simply returns
  1108. * the result of lstrcmpi.
  1109. *
  1110. * PARAMETERS:
  1111. * lpString1,
  1112. * lpString2,
  1113. * lParam, ignored optional data.
  1114. *
  1115. *******************************************************************************/
  1116. int
  1117. WINAPI
  1118. DPACompareKeyNames(
  1119. LPVOID lpString1,
  1120. LPVOID lpString2,
  1121. LPARAM lParam
  1122. )
  1123. {
  1124. return lstrcmpi((LPTSTR) lpString2, (LPTSTR) lpString1);
  1125. }
  1126. /*******************************************************************************
  1127. *
  1128. * RegEdit_OnKeyTreeDisconnect
  1129. *
  1130. * DESCRIPTION:
  1131. *
  1132. * PARAMETERS:
  1133. *
  1134. *******************************************************************************/
  1135. VOID
  1136. PASCAL
  1137. RegEdit_OnKeyTreeDisconnect(
  1138. HWND hWnd,
  1139. HTREEITEM hTreeItem
  1140. )
  1141. {
  1142. HWND hKeyTreeWnd;
  1143. TV_ITEM TVItem;
  1144. hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
  1145. //
  1146. // Disconnect all of the root registry handles that we've opened.
  1147. //
  1148. TVItem.mask = TVIF_PARAM;
  1149. TVItem.hItem = TreeView_GetChild(hKeyTreeWnd, hTreeItem);
  1150. while (TVItem.hItem != NULL) {
  1151. TreeView_GetItem(hKeyTreeWnd, &TVItem);
  1152. RegCloseKey((HKEY) TVItem.lParam);
  1153. TVItem.hItem = TreeView_GetNextSibling(hKeyTreeWnd, TVItem.hItem);
  1154. }
  1155. TreeView_DeleteItem(hKeyTreeWnd, hTreeItem);
  1156. }
  1157. /*******************************************************************************
  1158. *
  1159. * RegEdit_UpdateStatusBar
  1160. *
  1161. * DESCRIPTION:
  1162. * Show the full registry path in the status bar, for lack of anything
  1163. * better to do with it.
  1164. *
  1165. * PARAMETERS:
  1166. * (none).
  1167. *
  1168. *******************************************************************************/
  1169. VOID
  1170. PASCAL
  1171. RegEdit_UpdateStatusBar(
  1172. VOID
  1173. )
  1174. {
  1175. HWND hKeyTreeWnd;
  1176. TCHAR KeyName[MAXKEYNAME*2];
  1177. hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
  1178. KeyTree_BuildKeyPath(hKeyTreeWnd, TreeView_GetSelection(hKeyTreeWnd),
  1179. KeyName, BKP_TOCOMPUTER);
  1180. SetWindowText(g_RegEditData.hStatusBarWnd, KeyName);
  1181. }
  1182. /*******************************************************************************
  1183. *
  1184. * RegEdit_OnCopyKeyName
  1185. *
  1186. * DESCRIPTION:
  1187. *
  1188. * PARAMETERS:
  1189. *
  1190. *******************************************************************************/
  1191. VOID
  1192. PASCAL
  1193. RegEdit_OnCopyKeyName(
  1194. HWND hWnd,
  1195. HTREEITEM hTreeItem
  1196. )
  1197. {
  1198. TCHAR KeyName[MAXKEYNAME*2];
  1199. UINT KeyNameLength;
  1200. HANDLE hClipboardData;
  1201. LPTSTR lpClipboardData;
  1202. KeyTree_BuildKeyPath(g_RegEditData.hKeyTreeWnd, hTreeItem, KeyName,
  1203. BKP_TOSYMBOLICROOT);
  1204. KeyNameLength = (lstrlen(KeyName) + 1) * sizeof(TCHAR);
  1205. if (OpenClipboard(hWnd)) {
  1206. if ((hClipboardData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
  1207. KeyNameLength)) != NULL) {
  1208. lpClipboardData = (LPTSTR) GlobalLock(hClipboardData);
  1209. CopyMemory(lpClipboardData, KeyName, KeyNameLength);
  1210. GlobalUnlock(hClipboardData);
  1211. EmptyClipboard();
  1212. SetClipboardData(CF_UNICODETEXT, hClipboardData);
  1213. }
  1214. CloseClipboard();
  1215. }
  1216. }
  1217. /*******************************************************************************
  1218. *
  1219. * KeyTree_BuildKeyPath
  1220. *
  1221. * DESCRIPTION:
  1222. *
  1223. * PARAMETERS:
  1224. * hTreeViewWnd, handle of KeyTree window.
  1225. * hTreeItem, handle of tree item to begin building from.
  1226. * lpKeyPath, buffer to store path in.
  1227. * fIncludeSymbolicRootName, TRUE if root key's name should be included
  1228. * (e.g., HKEY_LOCAL_MACHINE), else FALSE.
  1229. *
  1230. *******************************************************************************/
  1231. HKEY
  1232. PASCAL
  1233. KeyTree_BuildKeyPath(
  1234. HWND hTreeViewWnd,
  1235. HTREEITEM hTreeItem,
  1236. LPTSTR lpKeyPath,
  1237. UINT ToFlags
  1238. )
  1239. {
  1240. TV_ITEM TVItem;
  1241. TCHAR SubKeyName[MAXKEYNAME*2];
  1242. *lpKeyPath = '\0';
  1243. TVItem.mask = TVIF_TEXT | TVIF_PARAM;
  1244. TVItem.hItem = hTreeItem;
  1245. TVItem.pszText = (LPTSTR) SubKeyName;
  1246. TVItem.cchTextMax = sizeof(SubKeyName)/sizeof(TCHAR);
  1247. while (TRUE) {
  1248. TreeView_GetItem(hTreeViewWnd, &TVItem);
  1249. if (TVItem.lParam != 0 && !(ToFlags & BKP_TOSYMBOLICROOT))
  1250. break;
  1251. if (*lpKeyPath != '\0') {
  1252. lstrcat(SubKeyName, TEXT("\\"));
  1253. lstrcat(SubKeyName, lpKeyPath);
  1254. }
  1255. lstrcpy(lpKeyPath, SubKeyName);
  1256. if (TVItem.lParam != 0 && (ToFlags & BKP_TOCOMPUTER) != BKP_TOCOMPUTER)
  1257. break;
  1258. TVItem.hItem = TreeView_GetParent(hTreeViewWnd, TVItem.hItem);
  1259. if (TVItem.hItem == NULL) {
  1260. if ((ToFlags & BKP_TOCOMPUTER) != BKP_TOCOMPUTER)
  1261. *lpKeyPath = '\0';
  1262. break;
  1263. }
  1264. }
  1265. return ((HKEY) TVItem.lParam);
  1266. }
  1267. /*******************************************************************************
  1268. *
  1269. * KeyTree_InsertItem
  1270. *
  1271. * DESCRIPTION:
  1272. *
  1273. * PARAMETERS:
  1274. *
  1275. *******************************************************************************/
  1276. HTREEITEM
  1277. PASCAL
  1278. KeyTree_InsertItem(
  1279. HWND hKeyTreeWnd,
  1280. HTREEITEM hParent,
  1281. HTREEITEM hInsertAfter,
  1282. LPCTSTR lpText,
  1283. UINT fHasKids,
  1284. LPARAM lParam
  1285. )
  1286. {
  1287. TV_INSERTSTRUCT TVInsertStruct;
  1288. TVInsertStruct.hParent = hParent;
  1289. TVInsertStruct.hInsertAfter = hInsertAfter;
  1290. TVInsertStruct.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE |
  1291. TVIF_PARAM | TVIF_CHILDREN;
  1292. // TVInsertStruct.item.hItem = NULL;
  1293. // TVInsertStruct.item.state = 0;
  1294. // TVInsertStruct.item.stateMask = 0;
  1295. TVInsertStruct.item.pszText = (LPTSTR) lpText;
  1296. // TVInsertStruct.item.cchTextMax = lstrlen(lpText);
  1297. TVInsertStruct.item.iImage = IMAGEINDEX(IDI_FOLDER);
  1298. TVInsertStruct.item.iSelectedImage = IMAGEINDEX(IDI_FOLDEROPEN);
  1299. TVInsertStruct.item.cChildren = fHasKids;
  1300. TVInsertStruct.item.lParam = lParam;
  1301. return TreeView_InsertItem(hKeyTreeWnd, &TVInsertStruct);
  1302. }
  1303. /*******************************************************************************
  1304. *
  1305. * KeyTree_ExpandBranch
  1306. *
  1307. * DESCRIPTION:
  1308. *
  1309. * PARAMETERS:
  1310. * hTreeViewWnd, handle of KeyTree window.
  1311. * hTreeItem, handle of tree item to edit.
  1312. *
  1313. *******************************************************************************/
  1314. BOOL
  1315. PASCAL
  1316. KeyTree_ExpandBranch(
  1317. HWND hKeyTreeWnd,
  1318. HTREEITEM hExpandingTreeItem
  1319. )
  1320. {
  1321. TCHAR KeyName[MAXKEYNAME];
  1322. HKEY hRootKey;
  1323. HKEY hEnumKey;
  1324. int Index;
  1325. int MaximumSubKeyLength;
  1326. //
  1327. // Nothing special needs to be done with a top-level label such as "My
  1328. // Computer" or a network computer name. It's children are already filled
  1329. // in and are always valid.
  1330. //
  1331. if (TreeView_GetParent(hKeyTreeWnd, hExpandingTreeItem) == NULL)
  1332. return TRUE;
  1333. hRootKey = KeyTree_BuildKeyPath(hKeyTreeWnd, hExpandingTreeItem,
  1334. KeyName, FALSE);
  1335. if(RegOpenKeyEx(hRootKey,KeyName,0,KEY_ENUMERATE_SUB_KEYS,&hEnumKey) != ERROR_SUCCESS)
  1336. return FALSE;
  1337. MaximumSubKeyLength = MAXKEYNAME - (lstrlen(KeyName) + 1);
  1338. Index = 0;
  1339. while (RegEnumKey(hEnumKey, Index++, KeyName, MaximumSubKeyLength) ==
  1340. ERROR_SUCCESS) {
  1341. KeyTree_InsertItem(hKeyTreeWnd, hExpandingTreeItem, TVI_FIRST,
  1342. KeyName, DoesKeyHaveKids(hEnumKey, KeyName), 0);
  1343. }
  1344. RegCloseKey(hEnumKey);
  1345. //
  1346. // Sort the subkeys _after_ inserting all the items. The above insert
  1347. // used to specify TVI_SORT, but on NT, expanding a key with several
  1348. // subkeys (e.g., HKEY_CLASSES_ROOT) would take several seconds!
  1349. //
  1350. TreeView_SortChildren(hKeyTreeWnd, hExpandingTreeItem, FALSE);
  1351. return TRUE;
  1352. }
  1353. /*******************************************************************************
  1354. *
  1355. * DoesKeyHaveKids
  1356. *
  1357. * DESCRIPTION:
  1358. * Checks if the given key path has any subkeys or not.
  1359. *
  1360. * PARAMETERS:
  1361. *
  1362. *******************************************************************************/
  1363. BOOL
  1364. PASCAL
  1365. DoesKeyHaveKids(
  1366. HKEY hKey,
  1367. LPTSTR lpKeyName
  1368. )
  1369. {
  1370. BOOL fHasKids;
  1371. HKEY hCheckChildrenKey;
  1372. DWORD cSubKeys;
  1373. fHasKids = FALSE;
  1374. if(RegOpenKeyEx(hKey,lpKeyName,0,KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
  1375. &hCheckChildrenKey) == ERROR_SUCCESS) {
  1376. if (RegQueryInfoKey(hCheckChildrenKey, NULL, NULL, NULL, &cSubKeys,
  1377. NULL, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS &&
  1378. cSubKeys > 0)
  1379. fHasKids = TRUE;
  1380. RegCloseKey(hCheckChildrenKey);
  1381. }
  1382. return fHasKids;
  1383. }
  1384. /*******************************************************************************
  1385. *
  1386. * KeyTree_EditLabel
  1387. *
  1388. * DESCRIPTION:
  1389. *
  1390. * PARAMETERS:
  1391. * hTreeViewWnd, handle of KeyTree window.
  1392. * hTreeItem, handle of tree item to edit.
  1393. *
  1394. *******************************************************************************/
  1395. VOID
  1396. PASCAL
  1397. KeyTree_EditLabel(
  1398. HWND hKeyTreeWnd,
  1399. HTREEITEM hTreeItem
  1400. )
  1401. {
  1402. g_RegEditData.fAllowLabelEdits = TRUE;
  1403. TreeView_EditLabel(hKeyTreeWnd, hTreeItem);
  1404. g_RegEditData.fAllowLabelEdits = FALSE;
  1405. }
  1406. /*******************************************************************************
  1407. *
  1408. * KeyTree_CanDeleteOrRenameItem
  1409. *
  1410. * DESCRIPTION:
  1411. *
  1412. * PARAMETERS:
  1413. * hTreeViewWnd, handle of KeyTree window.
  1414. * hTreeItem, handle of tree item to check.
  1415. *
  1416. *******************************************************************************/
  1417. BOOL
  1418. PASCAL
  1419. KeyTree_CanDeleteOrRenameItem(
  1420. HWND hWnd,
  1421. HTREEITEM hTreeItem
  1422. )
  1423. {
  1424. TV_ITEM TVItem;
  1425. //
  1426. // Check if the selected tree item is null. This will occur when viewing
  1427. // the Edit popup from the main menu with no selection made.
  1428. //
  1429. if (hTreeItem != NULL) {
  1430. //
  1431. // Check if this tree item has any reference data indicating that it
  1432. // is a predefined root. Predefined roots cannot be renamed or
  1433. // deleted.
  1434. //
  1435. TVItem.hItem = hTreeItem;
  1436. TVItem.mask = TVIF_PARAM;
  1437. TreeView_GetItem(hWnd, &TVItem);
  1438. if ((HKEY) TVItem.lParam == NULL) {
  1439. //
  1440. // Check that this isn't a top-level item such as "My Computer" or
  1441. // a remote registry connection.
  1442. //
  1443. if (TreeView_GetParent(hWnd, hTreeItem) != NULL)
  1444. return TRUE;
  1445. }
  1446. }
  1447. return FALSE;
  1448. }
  1449. //------------------------------------------------------------------------------
  1450. // KeyTree_GetRootKey
  1451. //
  1452. // DESCRIPTION: Returns the root key of the item (HKEY_ ...)
  1453. //
  1454. // PARAMETERS: hTreeItem - treeview item
  1455. //------------------------------------------------------------------------------
  1456. HKEY KeyTree_GetRootKey(HTREEITEM hTreeItem)
  1457. {
  1458. TV_ITEM TVItem;
  1459. TVItem.mask = TVIF_PARAM;
  1460. TVItem.hItem = hTreeItem;
  1461. TreeView_GetItem(g_RegEditData.hKeyTreeWnd, &TVItem);
  1462. while (!TVItem.lParam)
  1463. {
  1464. TVItem.hItem = TreeView_GetParent(g_RegEditData.hKeyTreeWnd, TVItem.hItem);
  1465. TreeView_GetItem(g_RegEditData.hKeyTreeWnd, &TVItem);
  1466. }
  1467. return ((HKEY) TVItem.lParam);
  1468. }
  1469. //------------------------------------------------------------------------------
  1470. // KeyTree_GetKeyName
  1471. //
  1472. // DESCRIPTION: Returns the TEXT of an item
  1473. //
  1474. // PARAMETERS: hTreeItem - treeview item
  1475. // pszText - pointer to an TCHAR array
  1476. // cchMax - number of characters in the array
  1477. //------------------------------------------------------------------------------
  1478. PTSTR KeyTree_GetKeyName(HTREEITEM hTreeItem, PTSTR pszName, int cchNameMax)
  1479. {
  1480. TV_ITEM TVItem;
  1481. pszName[0] = TEXT('\0');
  1482. TVItem.mask = TVIF_TEXT;
  1483. TVItem.hItem = hTreeItem;
  1484. TVItem.pszText = pszName;
  1485. TVItem.cchTextMax = cchNameMax;
  1486. TreeView_GetItem(g_RegEditData.hKeyTreeWnd, &TVItem);
  1487. return TVItem.pszText;
  1488. }