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
get_item_path(HWND hwndTV,HTREEITEM hItem,HKEY * phKey,LPWSTR * pKeyPath,int * pPathLen,int * pMaxLen)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
GetItemPath(HWND hwndTV,HTREEITEM hItem,HKEY * phRootKey)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
DeleteNode(HWND hwndTV,HTREEITEM hItem)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) */
AddEntryToTree(HWND hwndTV,HTREEITEM hParent,LPWSTR label,HKEY hKey,DWORD dwChildren)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
RefreshTreeItem(HWND hwndTV,HTREEITEM hItem)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
RefreshTreeView(HWND hwndTV)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
InsertNode(HWND hwndTV,HTREEITEM hItem,LPWSTR name)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
StartKeyRename(HWND hwndTV)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
InitTreeViewItems(HWND hwndTV,LPWSTR pHostName)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 */
InitTreeViewImageLists(HWND hwndTV)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
OnTreeExpanding(HWND hwndTV,NMTREEVIEW * pnmtv)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
CreateNewKey(HWND hwndTV,HTREEITEM hItem)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
TreeWndNotifyProc(HWND hWnd,WPARAM wParam,LPARAM lParam,BOOL * Result)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 */
CreateTreeView(HWND hwndParent,LPWSTR pHostName,HMENU id)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
DestroyTreeView(HWND hwndTV)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
SelectNode(HWND hwndTV,LPCWSTR keyPath)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