1 /* 2 * Regedit treeview 3 * 4 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org> 5 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 6 */ 7 8 #include "regedit.h" 9 10 /* Global variables and constants */ 11 /* Image_Open, Image_Closed, and Image_Root - integer variables for indexes of the images */ 12 static int Image_Open; 13 static int Image_Closed; 14 static int Image_Root; 15 16 static LPWSTR pathBuffer; 17 18 #define NUM_ICONS 3 /* number of icons to add to the image list */ 19 20 /* External resources in shell32.dll */ 21 #define IDI_SHELL_FOLDER 4 22 #define IDI_SHELL_FOLDER_OPEN 5 23 #define IDI_SHELL_MY_COMPUTER 16 24 25 static BOOL get_item_path(HWND hwndTV, HTREEITEM hItem, HKEY* phKey, LPWSTR* pKeyPath, int* pPathLen, int* pMaxLen) 26 { 27 TVITEMW item; 28 size_t maxLen, len; 29 LPWSTR newStr; 30 31 item.mask = TVIF_PARAM; 32 item.hItem = hItem; 33 if (!TreeView_GetItem(hwndTV, &item)) return FALSE; 34 35 if (item.lParam) 36 { 37 /* found root key with valid key value */ 38 *phKey = (HKEY)item.lParam; 39 return TRUE; 40 } 41 42 if(!get_item_path(hwndTV, TreeView_GetParent(hwndTV, hItem), phKey, pKeyPath, pPathLen, pMaxLen)) return FALSE; 43 if (*pPathLen) 44 { 45 (*pKeyPath)[*pPathLen] = L'\\'; 46 ++(*pPathLen); 47 } 48 49 do 50 { 51 item.mask = TVIF_TEXT; 52 item.hItem = hItem; 53 item.pszText = *pKeyPath + *pPathLen; 54 maxLen = *pMaxLen - *pPathLen; 55 item.cchTextMax = (int) maxLen; 56 if (!TreeView_GetItem(hwndTV, &item)) return FALSE; 57 len = wcslen(item.pszText); 58 if (len < maxLen - 1) 59 { 60 *pPathLen += (int) len; 61 break; 62 } 63 newStr = HeapReAlloc(GetProcessHeap(), 0, *pKeyPath, *pMaxLen * 2); 64 if (!newStr) return FALSE; 65 *pKeyPath = newStr; 66 *pMaxLen *= 2; 67 } 68 while(TRUE); 69 70 return TRUE; 71 } 72 73 LPCWSTR GetItemPath(HWND hwndTV, HTREEITEM hItem, HKEY* phRootKey) 74 { 75 int pathLen = 0, maxLen; 76 77 *phRootKey = NULL; 78 79 if (!pathBuffer) 80 pathBuffer = HeapAlloc(GetProcessHeap(), 0, 1024); 81 if (!pathBuffer) 82 return NULL; 83 84 *pathBuffer = UNICODE_NULL; 85 86 maxLen = (int)HeapSize(GetProcessHeap(), 0, pathBuffer); 87 88 if (!hItem) 89 { 90 hItem = TreeView_GetSelection(hwndTV); 91 } 92 if (maxLen == -1 || !hItem || !get_item_path(hwndTV, hItem, phRootKey, &pathBuffer, &pathLen, &maxLen)) 93 { 94 return NULL; 95 } 96 return pathBuffer; 97 } 98 99 BOOL DeleteNode(HWND hwndTV, HTREEITEM hItem) 100 { 101 if (!hItem) hItem = TreeView_GetSelection(hwndTV); 102 if (!hItem) return FALSE; 103 return TreeView_DeleteItem(hwndTV, hItem); 104 } 105 106 /* Add an entry to the tree. Only give hKey for root nodes (HKEY_ constants) */ 107 static HTREEITEM AddEntryToTree(HWND hwndTV, HTREEITEM hParent, LPWSTR label, HKEY hKey, DWORD dwChildren) 108 { 109 TVITEMW tvi; 110 TVINSERTSTRUCTW tvins; 111 112 if (hKey) 113 { 114 if (RegQueryInfoKeyW(hKey, 0, 0, 0, &dwChildren, 0, 0, 0, 0, 0, 0, 0) != ERROR_SUCCESS) 115 { 116 dwChildren = 0; 117 } 118 } 119 120 tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM; 121 tvi.pszText = label; 122 tvi.cchTextMax = wcslen(tvi.pszText); 123 tvi.iImage = Image_Closed; 124 tvi.iSelectedImage = Image_Open; 125 tvi.cChildren = dwChildren; 126 tvi.lParam = (LPARAM)hKey; 127 tvins.item = tvi; 128 tvins.hInsertAfter = (HTREEITEM)(hKey ? TVI_LAST : TVI_FIRST); 129 tvins.hParent = hParent; 130 return TreeView_InsertItem(hwndTV, &tvins); 131 } 132 133 BOOL RefreshTreeItem(HWND hwndTV, HTREEITEM hItem) 134 { 135 HKEY hRoot, hKey, hSubKey; 136 HTREEITEM childItem; 137 LPCWSTR KeyPath; 138 DWORD dwCount, dwIndex, dwMaxSubKeyLen; 139 LPWSTR Name = NULL; 140 TVITEMW tvItem; 141 LPWSTR pszNodes = NULL; 142 BOOL bSuccess = FALSE; 143 LPWSTR s; 144 BOOL bAddedAny; 145 146 KeyPath = GetItemPath(hwndTV, hItem, &hRoot); 147 148 if (*KeyPath) 149 { 150 if (RegOpenKeyExW(hRoot, KeyPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 151 { 152 goto done; 153 } 154 } 155 else 156 { 157 hKey = hRoot; 158 } 159 160 if (RegQueryInfoKeyW(hKey, 0, 0, 0, &dwCount, &dwMaxSubKeyLen, 0, 0, 0, 0, 0, 0) != ERROR_SUCCESS) 161 { 162 goto done; 163 } 164 165 /* Set the number of children again */ 166 tvItem.mask = TVIF_CHILDREN; 167 tvItem.hItem = hItem; 168 tvItem.cChildren = dwCount; 169 if (!TreeView_SetItem(hwndTV, &tvItem)) 170 { 171 goto done; 172 } 173 174 /* We don't have to bother with the rest if it's not expanded. */ 175 if (TreeView_GetItemState(hwndTV, hItem, TVIS_EXPANDED) == 0) 176 { 177 RegCloseKey(hKey); 178 bSuccess = TRUE; 179 goto done; 180 } 181 182 dwMaxSubKeyLen++; /* account for the \0 terminator */ 183 if (!(Name = HeapAlloc(GetProcessHeap(), 0, dwMaxSubKeyLen * sizeof(WCHAR)))) 184 { 185 goto done; 186 } 187 tvItem.cchTextMax = dwMaxSubKeyLen; 188 /*if (!(tvItem.pszText = HeapAlloc(GetProcessHeap(), 0, dwMaxSubKeyLen * sizeof(WCHAR)))) { 189 goto done; 190 }*/ 191 192 /* Get all of the tree node siblings in one contiguous block of memory */ 193 { 194 DWORD dwPhysicalSize = 0; 195 DWORD dwActualSize = 0; 196 DWORD dwNewPhysicalSize; 197 LPWSTR pszNewNodes; 198 DWORD dwStep = 10000; 199 200 for (childItem = TreeView_GetChild(hwndTV, hItem); childItem; 201 childItem = TreeView_GetNextSibling(hwndTV, childItem)) 202 { 203 204 if (dwActualSize + dwMaxSubKeyLen + 1 > dwPhysicalSize) 205 { 206 dwNewPhysicalSize = dwActualSize + dwMaxSubKeyLen + 1 + dwStep; 207 208 if (pszNodes) 209 pszNewNodes = (LPWSTR) HeapReAlloc(GetProcessHeap(), 0, pszNodes, dwNewPhysicalSize * sizeof(WCHAR)); 210 else 211 pszNewNodes = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, dwNewPhysicalSize * sizeof(WCHAR)); 212 if (!pszNewNodes) 213 goto done; 214 215 dwPhysicalSize = dwNewPhysicalSize; 216 pszNodes = pszNewNodes; 217 } 218 219 tvItem.mask = TVIF_TEXT; 220 tvItem.hItem = childItem; 221 tvItem.pszText = &pszNodes[dwActualSize]; 222 tvItem.cchTextMax = dwPhysicalSize - dwActualSize; 223 if (!TreeView_GetItem(hwndTV, &tvItem)) 224 goto done; 225 226 dwActualSize += (DWORD) wcslen(&pszNodes[dwActualSize]) + 1; 227 } 228 229 if (pszNodes) 230 pszNodes[dwActualSize] = L'\0'; 231 } 232 233 /* Now go through all the children in the tree, and check if any have to be removed. */ 234 childItem = TreeView_GetChild(hwndTV, hItem); 235 while (childItem) 236 { 237 HTREEITEM nextItem = TreeView_GetNextSibling(hwndTV, childItem); 238 if (RefreshTreeItem(hwndTV, childItem) == FALSE) 239 { 240 (void)TreeView_DeleteItem(hwndTV, childItem); 241 } 242 childItem = nextItem; 243 } 244 245 /* Now go through all the children in the registry, and check if any have to be added. */ 246 bAddedAny = FALSE; 247 for (dwIndex = 0; dwIndex < dwCount; dwIndex++) 248 { 249 DWORD cName = dwMaxSubKeyLen, dwSubCount; 250 BOOL found; 251 252 found = FALSE; 253 if (RegEnumKeyExW(hKey, dwIndex, Name, &cName, 0, 0, 0, NULL) != ERROR_SUCCESS) 254 { 255 continue; 256 } 257 258 /* Check if the node is already in there. */ 259 if (pszNodes) 260 { 261 for (s = pszNodes; *s; s += wcslen(s) + 1) 262 { 263 if (!wcscmp(s, Name)) 264 { 265 found = TRUE; 266 break; 267 } 268 } 269 } 270 271 if (found == FALSE) 272 { 273 /* Find the number of children of the node. */ 274 dwSubCount = 0; 275 if (RegOpenKeyExW(hKey, Name, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) 276 { 277 if (RegQueryInfoKeyW(hSubKey, 0, 0, 0, &dwSubCount, 0, 0, 0, 0, 0, 0, 0) != ERROR_SUCCESS) 278 { 279 dwSubCount = 0; 280 } 281 RegCloseKey(hSubKey); 282 } 283 284 AddEntryToTree(hwndTV, hItem, Name, NULL, dwSubCount); 285 bAddedAny = TRUE; 286 } 287 } 288 RegCloseKey(hKey); 289 290 if (bAddedAny) 291 SendMessageW(hwndTV, TVM_SORTCHILDREN, 0, (LPARAM) hItem); 292 293 bSuccess = TRUE; 294 295 done: 296 if (pszNodes) 297 HeapFree(GetProcessHeap(), 0, pszNodes); 298 if (Name) 299 HeapFree(GetProcessHeap(), 0, Name); 300 return bSuccess; 301 } 302 303 BOOL RefreshTreeView(HWND hwndTV) 304 { 305 HTREEITEM hItem; 306 HTREEITEM hSelectedItem; 307 HCURSOR hcursorOld; 308 309 hSelectedItem = TreeView_GetSelection(hwndTV); 310 hcursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT)); 311 SendMessageW(hwndTV, WM_SETREDRAW, FALSE, 0); 312 313 hItem = TreeView_GetChild(hwndTV, TreeView_GetRoot(hwndTV)); 314 while (hItem) 315 { 316 RefreshTreeItem(hwndTV, hItem); 317 hItem = TreeView_GetNextSibling(hwndTV, hItem); 318 } 319 320 SendMessageW(hwndTV, WM_SETREDRAW, TRUE, 0); 321 SetCursor(hcursorOld); 322 323 /* We reselect the currently selected node, this will prompt a refresh of the listview. */ 324 (void)TreeView_SelectItem(hwndTV, hSelectedItem); 325 return TRUE; 326 } 327 328 HTREEITEM InsertNode(HWND hwndTV, HTREEITEM hItem, LPWSTR name) 329 { 330 WCHAR buf[MAX_NEW_KEY_LEN]; 331 HTREEITEM hNewItem = 0; 332 TVITEMEXW item; 333 334 /* Default to the current selection */ 335 if (!hItem) 336 { 337 hItem = TreeView_GetSelection(hwndTV); 338 if (!hItem) 339 return FALSE; 340 } 341 342 memset(&item, 0, sizeof(item)); 343 item.hItem = hItem; 344 item.mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_STATE; 345 if (!TreeView_GetItem(hwndTV, &item)) 346 return FALSE; 347 348 if (item.state & TVIS_EXPANDEDONCE) 349 { 350 hNewItem = AddEntryToTree(hwndTV, hItem, name, 0, 0); 351 SendMessageW(hwndTV, TVM_SORTCHILDREN, 0, (LPARAM) hItem); 352 } 353 else 354 { 355 item.mask = TVIF_CHILDREN | TVIF_HANDLE; 356 item.hItem = hItem; 357 item.cChildren = 1; 358 if (!TreeView_SetItem(hwndTV, &item)) 359 return FALSE; 360 } 361 362 (void)TreeView_Expand(hwndTV, hItem, TVE_EXPAND); 363 if (!hNewItem) 364 { 365 for(hNewItem = TreeView_GetChild(hwndTV, hItem); hNewItem; hNewItem = TreeView_GetNextSibling(hwndTV, hNewItem)) 366 { 367 item.mask = TVIF_HANDLE | TVIF_TEXT; 368 item.hItem = hNewItem; 369 item.pszText = buf; 370 item.cchTextMax = ARRAY_SIZE(buf); 371 if (!TreeView_GetItem(hwndTV, &item)) continue; 372 if (wcscmp(name, item.pszText) == 0) break; 373 } 374 } 375 if (hNewItem) (void)TreeView_SelectItem(hwndTV, hNewItem); 376 377 return hNewItem; 378 } 379 380 HWND StartKeyRename(HWND hwndTV) 381 { 382 HTREEITEM hItem; 383 384 if(!(hItem = TreeView_GetSelection(hwndTV))) return 0; 385 return TreeView_EditLabel(hwndTV, hItem); 386 } 387 388 static BOOL InitTreeViewItems(HWND hwndTV, LPWSTR pHostName) 389 { 390 TVITEMW tvi; 391 TVINSERTSTRUCTW tvins; 392 HTREEITEM hRoot; 393 394 tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM; 395 /* Set the text of the item. */ 396 tvi.pszText = pHostName; 397 tvi.cchTextMax = wcslen(tvi.pszText); 398 /* Assume the item is not a parent item, so give it an image. */ 399 tvi.iImage = Image_Root; 400 tvi.iSelectedImage = Image_Root; 401 tvi.cChildren = 5; 402 /* Save the heading level in the item's application-defined data area. */ 403 tvi.lParam = (LPARAM)NULL; 404 tvins.item = tvi; 405 tvins.hInsertAfter = (HTREEITEM)TVI_FIRST; 406 tvins.hParent = TVI_ROOT; 407 /* Add the item to the tree view control. */ 408 if (!(hRoot = TreeView_InsertItem(hwndTV, &tvins))) return FALSE; 409 410 if (!AddEntryToTree(hwndTV, hRoot, L"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT, 1)) return FALSE; 411 if (!AddEntryToTree(hwndTV, hRoot, L"HKEY_CURRENT_USER", HKEY_CURRENT_USER, 1)) return FALSE; 412 if (!AddEntryToTree(hwndTV, hRoot, L"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE, 1)) return FALSE; 413 if (!AddEntryToTree(hwndTV, hRoot, L"HKEY_USERS", HKEY_USERS, 1)) return FALSE; 414 if (!AddEntryToTree(hwndTV, hRoot, L"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG, 1)) return FALSE; 415 416 if (GetVersion() & 0x80000000) 417 { 418 /* Win9x specific key */ 419 if (!AddEntryToTree(hwndTV, hRoot, L"HKEY_DYN_DATA", HKEY_DYN_DATA, 1)) return FALSE; 420 } 421 422 /* expand and select host name */ 423 (void)TreeView_Expand(hwndTV, hRoot, TVE_EXPAND); 424 (void)TreeView_Select(hwndTV, hRoot, TVGN_CARET); 425 return TRUE; 426 } 427 428 /* 429 * InitTreeViewImageLists - creates an image list, adds three bitmaps 430 * to it, and associates the image list with a tree view control. 431 * Returns TRUE if successful, or FALSE otherwise. 432 * hwndTV - handle to the tree view control. 433 */ 434 static BOOL InitTreeViewImageLists(HWND hwndTV) 435 { 436 HIMAGELIST himl; /* handle to image list */ 437 HICON hico; /* handle to icon */ 438 INT cx = GetSystemMetrics(SM_CXSMICON); 439 INT cy = GetSystemMetrics(SM_CYSMICON); 440 HMODULE hShell32 = GetModuleHandleW(L"shell32.dll"); 441 442 /* Create the image list. */ 443 if ((himl = ImageList_Create(cx, cy, ILC_MASK | ILC_COLOR32, 0, NUM_ICONS)) == NULL) 444 return FALSE; 445 446 /* Add the open file, closed file, and document bitmaps. */ 447 hico = LoadImageW(hShell32, 448 MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPEN), 449 IMAGE_ICON, 450 cx, 451 cy, 452 LR_DEFAULTCOLOR); 453 if (hico) 454 { 455 Image_Open = ImageList_AddIcon(himl, hico); 456 DestroyIcon(hico); 457 } 458 459 hico = LoadImageW(hShell32, 460 MAKEINTRESOURCEW(IDI_SHELL_FOLDER), 461 IMAGE_ICON, 462 cx, 463 cy, 464 LR_DEFAULTCOLOR); 465 if (hico) 466 { 467 Image_Closed = ImageList_AddIcon(himl, hico); 468 DestroyIcon(hico); 469 } 470 471 hico = LoadImageW(hShell32, 472 MAKEINTRESOURCEW(IDI_SHELL_MY_COMPUTER), 473 IMAGE_ICON, 474 cx, 475 cy, 476 LR_DEFAULTCOLOR); 477 if (hico) 478 { 479 Image_Root = ImageList_AddIcon(himl, hico); 480 DestroyIcon(hico); 481 } 482 483 /* Fail if not all of the images were added. */ 484 if (ImageList_GetImageCount(himl) < NUM_ICONS) 485 { 486 ImageList_Destroy(himl); 487 return FALSE; 488 } 489 490 /* Associate the image list with the tree view control. */ 491 (void)TreeView_SetImageList(hwndTV, himl, TVSIL_NORMAL); 492 493 return TRUE; 494 } 495 496 BOOL OnTreeExpanding(HWND hwndTV, NMTREEVIEW* pnmtv) 497 { 498 DWORD dwCount, dwIndex, dwMaxSubKeyLen; 499 HKEY hRoot, hNewKey, hKey; 500 LPCWSTR keyPath; 501 LPWSTR Name; 502 LONG errCode; 503 HCURSOR hcursorOld; 504 505 static int expanding; 506 if (expanding) return FALSE; 507 if (pnmtv->itemNew.state & TVIS_EXPANDEDONCE ) 508 { 509 return TRUE; 510 } 511 expanding = TRUE; 512 hcursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT)); 513 SendMessageW(hwndTV, WM_SETREDRAW, FALSE, 0); 514 515 keyPath = GetItemPath(hwndTV, pnmtv->itemNew.hItem, &hRoot); 516 if (!keyPath) goto done; 517 518 if (*keyPath) 519 { 520 errCode = RegOpenKeyExW(hRoot, keyPath, 0, KEY_READ, &hNewKey); 521 if (errCode != ERROR_SUCCESS) goto done; 522 } 523 else 524 { 525 hNewKey = hRoot; 526 } 527 528 errCode = RegQueryInfoKeyW(hNewKey, 0, 0, 0, &dwCount, &dwMaxSubKeyLen, 0, 0, 0, 0, 0, 0); 529 if (errCode != ERROR_SUCCESS) goto done; 530 dwMaxSubKeyLen++; /* account for the \0 terminator */ 531 Name = HeapAlloc(GetProcessHeap(), 0, dwMaxSubKeyLen * sizeof(WCHAR)); 532 if (!Name) goto done; 533 534 for (dwIndex = 0; dwIndex < dwCount; dwIndex++) 535 { 536 DWORD cName = dwMaxSubKeyLen, dwSubCount; 537 538 errCode = RegEnumKeyExW(hNewKey, dwIndex, Name, &cName, 0, 0, 0, 0); 539 if (errCode != ERROR_SUCCESS) continue; 540 errCode = RegOpenKeyExW(hNewKey, Name, 0, KEY_QUERY_VALUE, &hKey); 541 if (errCode == ERROR_SUCCESS) 542 { 543 errCode = RegQueryInfoKeyW(hKey, 0, 0, 0, &dwSubCount, 0, 0, 0, 0, 0, 0, 0); 544 RegCloseKey(hKey); 545 } 546 if (errCode != ERROR_SUCCESS) dwSubCount = 0; 547 AddEntryToTree(hwndTV, pnmtv->itemNew.hItem, Name, NULL, dwSubCount); 548 } 549 550 SendMessageW(hwndTV, TVM_SORTCHILDREN, 0, (LPARAM)pnmtv->itemNew.hItem); 551 552 RegCloseKey(hNewKey); 553 HeapFree(GetProcessHeap(), 0, Name); 554 555 done: 556 SendMessageW(hwndTV, WM_SETREDRAW, TRUE, 0); 557 SetCursor(hcursorOld); 558 expanding = FALSE; 559 560 return TRUE; 561 } 562 563 BOOL CreateNewKey(HWND hwndTV, HTREEITEM hItem) 564 { 565 WCHAR szNewKeyFormat[128]; 566 WCHAR szNewKey[128]; 567 LPCWSTR pszKeyPath; 568 int iIndex = 1; 569 LONG nResult; 570 HKEY hRootKey = NULL, hKey = NULL, hNewKey = NULL; 571 BOOL bSuccess = FALSE; 572 DWORD dwDisposition; 573 HTREEITEM hNewItem; 574 575 pszKeyPath = GetItemPath(hwndTV, hItem, &hRootKey); 576 if (!pszKeyPath) 577 return bSuccess; 578 if (pszKeyPath[0] == L'\0') 579 hKey = hRootKey; 580 else if (RegOpenKeyW(hRootKey, pszKeyPath, &hKey) != ERROR_SUCCESS) 581 goto done; 582 583 if (LoadStringW(hInst, IDS_NEW_KEY, szNewKeyFormat, ARRAY_SIZE(szNewKeyFormat)) <= 0) 584 goto done; 585 586 /* Need to create a new key with a unique name */ 587 do 588 { 589 wsprintf(szNewKey, szNewKeyFormat, iIndex++); 590 nResult = RegCreateKeyExW(hKey, szNewKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hNewKey, &dwDisposition); 591 if (hNewKey && dwDisposition == REG_OPENED_EXISTING_KEY) 592 { 593 RegCloseKey(hNewKey); 594 hNewKey = NULL; 595 } 596 else if (!hNewKey) 597 { 598 InfoMessageBox(hFrameWnd, MB_OK | MB_ICONERROR, NULL, L"Cannot create new key!\n\nError Code: %d", nResult); 599 goto done; 600 } 601 } 602 while(!hNewKey); 603 604 /* Insert the new key */ 605 hNewItem = InsertNode(hwndTV, hItem, szNewKey); 606 if (!hNewItem) 607 goto done; 608 609 /* The new key's name is probably not appropriate yet */ 610 (void)TreeView_EditLabel(hwndTV, hNewItem); 611 612 bSuccess = TRUE; 613 614 done: 615 if (hKey != hRootKey && hKey) 616 RegCloseKey(hKey); 617 if (hNewKey) 618 RegCloseKey(hNewKey); 619 return bSuccess; 620 } 621 622 BOOL TreeWndNotifyProc(HWND hWnd, WPARAM wParam, LPARAM lParam, BOOL *Result) 623 { 624 UNREFERENCED_PARAMETER(wParam); 625 *Result = TRUE; 626 627 switch (((LPNMHDR)lParam)->code) 628 { 629 case TVN_ITEMEXPANDING: 630 *Result = !OnTreeExpanding(g_pChildWnd->hTreeWnd, (NMTREEVIEW*)lParam); 631 return TRUE; 632 case TVN_SELCHANGED: 633 { 634 NMTREEVIEW* pnmtv = (NMTREEVIEW*)lParam; 635 /* Get the parent of the current item */ 636 HTREEITEM hParentItem = TreeView_GetParent(g_pChildWnd->hTreeWnd, pnmtv->itemNew.hItem); 637 638 UpdateAddress(pnmtv->itemNew.hItem, NULL, NULL, TRUE); 639 640 /* Disable the Permissions and new key menu items for 'My Computer' */ 641 EnableMenuItem(hMenuFrame, ID_EDIT_PERMISSIONS, MF_BYCOMMAND | (hParentItem ? MF_ENABLED : MF_GRAYED)); 642 EnableMenuItem(hMenuFrame, ID_EDIT_NEW_KEY, MF_BYCOMMAND | (hParentItem ? MF_ENABLED : MF_GRAYED)); 643 644 /* 645 * Disable Delete/Rename menu options for 'My Computer' (first item so doesn't have any parent) 646 * and HKEY_* keys (their parent is 'My Computer' and the previous remark applies). 647 */ 648 if (!hParentItem || !TreeView_GetParent(g_pChildWnd->hTreeWnd, hParentItem)) 649 { 650 EnableMenuItem(hMenuFrame , ID_EDIT_DELETE, MF_BYCOMMAND | MF_GRAYED); 651 EnableMenuItem(hMenuFrame , ID_EDIT_RENAME, MF_BYCOMMAND | MF_GRAYED); 652 EnableMenuItem(hPopupMenus, ID_TREE_DELETE, MF_BYCOMMAND | MF_GRAYED); 653 EnableMenuItem(hPopupMenus, ID_TREE_RENAME, MF_BYCOMMAND | MF_GRAYED); 654 } 655 else 656 { 657 EnableMenuItem(hMenuFrame , ID_EDIT_DELETE, MF_BYCOMMAND | MF_ENABLED); 658 EnableMenuItem(hMenuFrame , ID_EDIT_RENAME, MF_BYCOMMAND | MF_ENABLED); 659 EnableMenuItem(hPopupMenus, ID_TREE_DELETE, MF_BYCOMMAND | MF_ENABLED); 660 EnableMenuItem(hPopupMenus, ID_TREE_RENAME, MF_BYCOMMAND | MF_ENABLED); 661 } 662 663 return TRUE; 664 } 665 case NM_SETFOCUS: 666 g_pChildWnd->nFocusPanel = 0; 667 break; 668 case TVN_BEGINLABELEDIT: 669 { 670 LPNMTVDISPINFO ptvdi = (LPNMTVDISPINFO)lParam; 671 /* cancel label edit for rootkeys */ 672 if (!TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem) || 673 !TreeView_GetParent(g_pChildWnd->hTreeWnd, TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem))) 674 { 675 *Result = TRUE; 676 } 677 else 678 { 679 *Result = FALSE; 680 } 681 return TRUE; 682 } 683 case TVN_ENDLABELEDIT: 684 { 685 LPCWSTR keyPath; 686 HKEY hRootKey; 687 HKEY hKey = NULL; 688 LPNMTVDISPINFO ptvdi = (LPNMTVDISPINFO)lParam; 689 LONG nRenResult; 690 LONG lResult = TRUE; 691 WCHAR szBuffer[MAX_PATH]; 692 WCHAR Caption[128]; 693 694 if (ptvdi->item.pszText) 695 { 696 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem), &hRootKey); 697 if (wcslen(keyPath)) 698 _snwprintf(szBuffer, ARRAY_SIZE(szBuffer), L"%s\\%s", keyPath, ptvdi->item.pszText); 699 else 700 _snwprintf(szBuffer, ARRAY_SIZE(szBuffer), L"%s", ptvdi->item.pszText); 701 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, ptvdi->item.hItem, &hRootKey); 702 if (RegOpenKeyExW(hRootKey, szBuffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS) 703 { 704 lResult = FALSE; 705 RegCloseKey(hKey); 706 TreeView_EditLabel(g_pChildWnd->hTreeWnd, ptvdi->item.hItem); 707 } 708 else 709 { 710 nRenResult = RenameKey(hRootKey, keyPath, ptvdi->item.pszText); 711 if (nRenResult != ERROR_SUCCESS) 712 { 713 LoadStringW(hInst, IDS_ERROR, Caption, ARRAY_SIZE(Caption)); 714 ErrorMessageBox(hWnd, Caption, nRenResult); 715 lResult = FALSE; 716 } 717 else 718 UpdateAddress(ptvdi->item.hItem, hRootKey, szBuffer, FALSE); 719 } 720 *Result = lResult; 721 } 722 return TRUE; 723 } 724 } 725 return FALSE; 726 } 727 728 /* 729 * CreateTreeView - creates a tree view control. 730 * Returns the handle to the new control if successful, or NULL otherwise. 731 * hwndParent - handle to the control's parent window. 732 */ 733 HWND CreateTreeView(HWND hwndParent, LPWSTR pHostName, HMENU id) 734 { 735 RECT rcClient; 736 HWND hwndTV; 737 738 /* Get the dimensions of the parent window's client area, and create the tree view control. */ 739 GetClientRect(hwndParent, &rcClient); 740 hwndTV = CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEW, NULL, 741 WS_VISIBLE | WS_CHILD | WS_TABSTOP | TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_EDITLABELS | TVS_SHOWSELALWAYS, 742 0, 0, rcClient.right, rcClient.bottom, 743 hwndParent, id, hInst, NULL); 744 if (!hwndTV) return NULL; 745 746 /* Initialize the image list, and add items to the control. */ 747 if (!InitTreeViewImageLists(hwndTV) || !InitTreeViewItems(hwndTV, pHostName)) 748 { 749 DestroyWindow(hwndTV); 750 return NULL; 751 } 752 return hwndTV; 753 } 754 755 void DestroyTreeView(HWND hwndTV) 756 { 757 HIMAGELIST himl; 758 759 if (pathBuffer) HeapFree(GetProcessHeap(), 0, pathBuffer); 760 761 /* Destroy the image list associated with the tree view control */ 762 himl = TreeView_GetImageList(hwndTV, TVSIL_NORMAL); 763 if (himl) ImageList_Destroy(himl); 764 } 765 766 BOOL SelectNode(HWND hwndTV, LPCWSTR keyPath) 767 { 768 HTREEITEM hRoot, hItem; 769 HTREEITEM hChildItem; 770 WCHAR szPathPart[128]; 771 WCHAR szBuffer[128]; 772 LPCWSTR s; 773 TVITEMW tvi; 774 775 /* Load "My Computer" string... */ 776 LoadStringW(hInst, IDS_MY_COMPUTER, szBuffer, ARRAY_SIZE(szBuffer)); 777 StringCbCatW(szBuffer, sizeof(szBuffer), L"\\"); 778 779 /* ... and remove it from the key path */ 780 if (!_wcsnicmp(keyPath, szBuffer, wcslen(szBuffer))) 781 keyPath += wcslen(szBuffer); 782 783 /* Reinitialize szBuffer */ 784 szBuffer[0] = L'\0'; 785 786 hRoot = TreeView_GetRoot(hwndTV); 787 hItem = hRoot; 788 789 while(keyPath[0]) 790 { 791 size_t copyLength; 792 s = wcschr(keyPath, L'\\'); 793 if (s != NULL) 794 { 795 copyLength = (s - keyPath) * sizeof(WCHAR); 796 } 797 else 798 { 799 copyLength = sizeof(szPathPart); 800 } 801 StringCbCopyNW(szPathPart, sizeof(szPathPart), keyPath, copyLength); 802 803 /* Special case for root to expand root key abbreviations */ 804 if (hItem == hRoot) 805 { 806 if (!_wcsicmp(szPathPart, L"HKCR")) 807 StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_CLASSES_ROOT"); 808 else if (!_wcsicmp(szPathPart, L"HKCU")) 809 StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_CURRENT_USER"); 810 else if (!_wcsicmp(szPathPart, L"HKLM")) 811 StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_LOCAL_MACHINE"); 812 else if (!_wcsicmp(szPathPart, L"HKU")) 813 StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_USERS"); 814 else if (!_wcsicmp(szPathPart, L"HKCC")) 815 StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_CURRENT_CONFIG"); 816 else if (!_wcsicmp(szPathPart, L"HKDD")) 817 StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_DYN_DATA"); 818 } 819 820 for (hChildItem = TreeView_GetChild(hwndTV, hItem); hChildItem; 821 hChildItem = TreeView_GetNextSibling(hwndTV, hChildItem)) 822 { 823 memset(&tvi, 0, sizeof(tvi)); 824 tvi.hItem = hChildItem; 825 tvi.mask = TVIF_TEXT | TVIF_CHILDREN; 826 tvi.pszText = szBuffer; 827 tvi.cchTextMax = ARRAY_SIZE(szBuffer); 828 829 (void)TreeView_GetItem(hwndTV, &tvi); 830 831 if (!_wcsicmp(szBuffer, szPathPart)) 832 break; 833 } 834 835 if (!hChildItem) 836 return FALSE; 837 838 if (tvi.cChildren > 0) 839 { 840 if (!TreeView_Expand(hwndTV, hChildItem, TVE_EXPAND)) 841 return FALSE; 842 } 843 844 keyPath = s ? s + 1 : L""; 845 hItem = hChildItem; 846 } 847 848 (void)TreeView_SelectItem(hwndTV, hItem); 849 (void)TreeView_EnsureVisible(hwndTV, hItem); 850 851 return TRUE; 852 } 853 854 /* EOF */ 855