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) 598 return bSuccess; 599 if (pszKeyPath[0] == L'\0') 600 hKey = hRootKey; 601 else if (RegOpenKeyW(hRootKey, pszKeyPath, &hKey) != ERROR_SUCCESS) 602 goto done; 603 604 if (LoadStringW(hInst, IDS_NEW_KEY, szNewKeyFormat, ARRAY_SIZE(szNewKeyFormat)) <= 0) 605 goto done; 606 607 /* Need to create a new key with a unique name */ 608 do 609 { 610 wsprintf(szNewKey, szNewKeyFormat, iIndex++); 611 nResult = RegCreateKeyExW(hKey, szNewKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hNewKey, &dwDisposition); 612 if (hNewKey && dwDisposition == REG_OPENED_EXISTING_KEY) 613 { 614 RegCloseKey(hNewKey); 615 hNewKey = NULL; 616 } 617 else if (!hNewKey) 618 { 619 InfoMessageBox(hFrameWnd, MB_OK | MB_ICONERROR, NULL, L"Cannot create new key!\n\nError Code: %d", nResult); 620 goto done; 621 } 622 } 623 while(!hNewKey); 624 625 /* Insert the new key */ 626 hNewItem = InsertNode(hwndTV, hItem, szNewKey); 627 if (!hNewItem) 628 goto done; 629 630 /* The new key's name is probably not appropriate yet */ 631 (void)TreeView_EditLabel(hwndTV, hNewItem); 632 633 bSuccess = TRUE; 634 635 done: 636 if (hKey != hRootKey && hKey) 637 RegCloseKey(hKey); 638 if (hNewKey) 639 RegCloseKey(hNewKey); 640 return bSuccess; 641 } 642 643 BOOL TreeWndNotifyProc(HWND hWnd, WPARAM wParam, LPARAM lParam, BOOL *Result) 644 { 645 UNREFERENCED_PARAMETER(wParam); 646 *Result = TRUE; 647 648 switch (((LPNMHDR)lParam)->code) 649 { 650 case TVN_ITEMEXPANDING: 651 *Result = !OnTreeExpanding(g_pChildWnd->hTreeWnd, (NMTREEVIEW*)lParam); 652 return TRUE; 653 case TVN_SELCHANGED: 654 { 655 NMTREEVIEW* pnmtv = (NMTREEVIEW*)lParam; 656 /* Get the parent of the current item */ 657 HTREEITEM hParentItem = TreeView_GetParent(g_pChildWnd->hTreeWnd, pnmtv->itemNew.hItem); 658 659 UpdateAddress(pnmtv->itemNew.hItem, NULL, NULL, TRUE); 660 661 /* Disable the Permissions and new key menu items for 'My Computer' */ 662 EnableMenuItem(hMenuFrame, ID_EDIT_PERMISSIONS, MF_BYCOMMAND | (hParentItem ? MF_ENABLED : MF_GRAYED)); 663 EnableMenuItem(hMenuFrame, ID_EDIT_NEW_KEY, MF_BYCOMMAND | (hParentItem ? MF_ENABLED : MF_GRAYED)); 664 665 /* 666 * Disable Delete/Rename menu options for 'My Computer' (first item so doesn't have any parent) 667 * and HKEY_* keys (their parent is 'My Computer' and the previous remark applies). 668 */ 669 if (!hParentItem || !TreeView_GetParent(g_pChildWnd->hTreeWnd, hParentItem)) 670 { 671 EnableMenuItem(hMenuFrame , ID_EDIT_DELETE, MF_BYCOMMAND | MF_GRAYED); 672 EnableMenuItem(hMenuFrame , ID_EDIT_RENAME, MF_BYCOMMAND | MF_GRAYED); 673 EnableMenuItem(hPopupMenus, ID_TREE_DELETE, MF_BYCOMMAND | MF_GRAYED); 674 EnableMenuItem(hPopupMenus, ID_TREE_RENAME, MF_BYCOMMAND | MF_GRAYED); 675 } 676 else 677 { 678 EnableMenuItem(hMenuFrame , ID_EDIT_DELETE, MF_BYCOMMAND | MF_ENABLED); 679 EnableMenuItem(hMenuFrame , ID_EDIT_RENAME, MF_BYCOMMAND | MF_ENABLED); 680 EnableMenuItem(hPopupMenus, ID_TREE_DELETE, MF_BYCOMMAND | MF_ENABLED); 681 EnableMenuItem(hPopupMenus, ID_TREE_RENAME, MF_BYCOMMAND | MF_ENABLED); 682 } 683 684 return TRUE; 685 } 686 case NM_SETFOCUS: 687 g_pChildWnd->nFocusPanel = 0; 688 break; 689 case TVN_BEGINLABELEDIT: 690 { 691 LPNMTVDISPINFO ptvdi = (LPNMTVDISPINFO)lParam; 692 /* cancel label edit for rootkeys */ 693 if (!TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem) || 694 !TreeView_GetParent(g_pChildWnd->hTreeWnd, TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem))) 695 { 696 *Result = TRUE; 697 } 698 else 699 { 700 *Result = FALSE; 701 } 702 return TRUE; 703 } 704 case TVN_ENDLABELEDIT: 705 { 706 LPCWSTR keyPath; 707 HKEY hRootKey; 708 HKEY hKey = NULL; 709 LPNMTVDISPINFO ptvdi = (LPNMTVDISPINFO)lParam; 710 LONG nRenResult; 711 LONG lResult = TRUE; 712 WCHAR szBuffer[MAX_PATH]; 713 WCHAR Caption[128]; 714 715 if (ptvdi->item.pszText) 716 { 717 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem), &hRootKey); 718 if (wcslen(keyPath)) 719 _snwprintf(szBuffer, ARRAY_SIZE(szBuffer), L"%s\\%s", keyPath, ptvdi->item.pszText); 720 else 721 _snwprintf(szBuffer, ARRAY_SIZE(szBuffer), L"%s", ptvdi->item.pszText); 722 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, ptvdi->item.hItem, &hRootKey); 723 if (RegOpenKeyExW(hRootKey, szBuffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS) 724 { 725 lResult = FALSE; 726 RegCloseKey(hKey); 727 TreeView_EditLabel(g_pChildWnd->hTreeWnd, ptvdi->item.hItem); 728 } 729 else 730 { 731 nRenResult = RenameKey(hRootKey, keyPath, ptvdi->item.pszText); 732 if (nRenResult != ERROR_SUCCESS) 733 { 734 LoadStringW(hInst, IDS_ERROR, Caption, ARRAY_SIZE(Caption)); 735 ErrorMessageBox(hWnd, Caption, nRenResult); 736 lResult = FALSE; 737 } 738 else 739 UpdateAddress(ptvdi->item.hItem, hRootKey, szBuffer, FALSE); 740 } 741 *Result = lResult; 742 } 743 return TRUE; 744 } 745 } 746 return FALSE; 747 } 748 749 /* 750 * CreateTreeView - creates a tree view control. 751 * Returns the handle to the new control if successful, or NULL otherwise. 752 * hwndParent - handle to the control's parent window. 753 */ 754 HWND CreateTreeView(HWND hwndParent, LPWSTR pHostName, HMENU id) 755 { 756 RECT rcClient; 757 HWND hwndTV; 758 759 /* Get the dimensions of the parent window's client area, and create the tree view control. */ 760 GetClientRect(hwndParent, &rcClient); 761 hwndTV = CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEW, NULL, 762 WS_VISIBLE | WS_CHILD | WS_TABSTOP | TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_EDITLABELS | TVS_SHOWSELALWAYS, 763 0, 0, rcClient.right, rcClient.bottom, 764 hwndParent, id, hInst, NULL); 765 if (!hwndTV) return NULL; 766 767 /* Initialize the image list, and add items to the control. */ 768 if (!InitTreeViewImageLists(hwndTV) || !InitTreeViewItems(hwndTV, pHostName)) 769 { 770 DestroyWindow(hwndTV); 771 return NULL; 772 } 773 return hwndTV; 774 } 775 776 void DestroyTreeView(HWND hwndTV) 777 { 778 HIMAGELIST himl; 779 780 if (pathBuffer) HeapFree(GetProcessHeap(), 0, pathBuffer); 781 782 /* Destroy the image list associated with the tree view control */ 783 himl = TreeView_GetImageList(hwndTV, TVSIL_NORMAL); 784 if (himl) ImageList_Destroy(himl); 785 } 786 787 BOOL SelectNode(HWND hwndTV, LPCWSTR keyPath) 788 { 789 HTREEITEM hRoot, hItem; 790 HTREEITEM hChildItem; 791 WCHAR szPathPart[128]; 792 WCHAR szBuffer[128]; 793 LPCWSTR s; 794 TVITEMW tvi; 795 796 /* Load "My Computer" string... */ 797 LoadStringW(hInst, IDS_MY_COMPUTER, szBuffer, ARRAY_SIZE(szBuffer)); 798 StringCbCatW(szBuffer, sizeof(szBuffer), L"\\"); 799 800 /* ... and remove it from the key path */ 801 if (!_wcsnicmp(keyPath, szBuffer, wcslen(szBuffer))) 802 keyPath += wcslen(szBuffer); 803 804 /* Reinitialize szBuffer */ 805 szBuffer[0] = L'\0'; 806 807 hRoot = TreeView_GetRoot(hwndTV); 808 hItem = hRoot; 809 810 while(keyPath[0]) 811 { 812 size_t copyLength; 813 s = wcschr(keyPath, L'\\'); 814 if (s != NULL) 815 { 816 copyLength = (s - keyPath) * sizeof(WCHAR); 817 } 818 else 819 { 820 copyLength = sizeof(szPathPart); 821 } 822 StringCbCopyNW(szPathPart, sizeof(szPathPart), keyPath, copyLength); 823 824 /* Special case for root to expand root key abbreviations */ 825 if (hItem == hRoot) 826 { 827 if (!_wcsicmp(szPathPart, L"HKCR")) 828 StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_CLASSES_ROOT"); 829 else if (!_wcsicmp(szPathPart, L"HKCU")) 830 StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_CURRENT_USER"); 831 else if (!_wcsicmp(szPathPart, L"HKLM")) 832 StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_LOCAL_MACHINE"); 833 else if (!_wcsicmp(szPathPart, L"HKU")) 834 StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_USERS"); 835 else if (!_wcsicmp(szPathPart, L"HKCC")) 836 StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_CURRENT_CONFIG"); 837 else if (!_wcsicmp(szPathPart, L"HKDD")) 838 StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_DYN_DATA"); 839 } 840 841 for (hChildItem = TreeView_GetChild(hwndTV, hItem); hChildItem; 842 hChildItem = TreeView_GetNextSibling(hwndTV, hChildItem)) 843 { 844 memset(&tvi, 0, sizeof(tvi)); 845 tvi.hItem = hChildItem; 846 tvi.mask = TVIF_TEXT | TVIF_CHILDREN; 847 tvi.pszText = szBuffer; 848 tvi.cchTextMax = ARRAY_SIZE(szBuffer); 849 850 (void)TreeView_GetItem(hwndTV, &tvi); 851 852 if (!_wcsicmp(szBuffer, szPathPart)) 853 break; 854 } 855 856 if (!hChildItem) 857 return FALSE; 858 859 if (tvi.cChildren > 0) 860 { 861 if (!TreeView_Expand(hwndTV, hChildItem, TVE_EXPAND)) 862 return FALSE; 863 } 864 865 keyPath = s ? s + 1 : L""; 866 hItem = hChildItem; 867 } 868 869 (void)TreeView_SelectItem(hwndTV, hItem); 870 (void)TreeView_EnsureVisible(hwndTV, hItem); 871 872 return TRUE; 873 } 874 875 /* EOF */ 876