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