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.

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