836145dd0c7d54b01c2e99789a2fec039d74d613
[reactos.git] / base / applications / regedit / childwnd.c
1 /*
2 * Regedit child window
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 ChildWnd* g_pChildWnd;
24 static int last_split;
25 HBITMAP SizingPattern = 0;
26 HBRUSH SizingBrush = 0;
27 static WCHAR Suggestions[256];
28
29 extern LPCWSTR get_root_key_name(HKEY hRootKey)
30 {
31 if (hRootKey == HKEY_CLASSES_ROOT) return L"HKEY_CLASSES_ROOT";
32 if (hRootKey == HKEY_CURRENT_USER) return L"HKEY_CURRENT_USER";
33 if (hRootKey == HKEY_LOCAL_MACHINE) return L"HKEY_LOCAL_MACHINE";
34 if (hRootKey == HKEY_USERS) return L"HKEY_USERS";
35 if (hRootKey == HKEY_CURRENT_CONFIG) return L"HKEY_CURRENT_CONFIG";
36 if (hRootKey == HKEY_DYN_DATA) return L"HKEY_DYN_DATA";
37
38 return L"UNKNOWN HKEY, PLEASE REPORT";
39 }
40
41 extern void ResizeWnd(int cx, int cy)
42 {
43 HDWP hdwp = BeginDeferWindowPos(4);
44 RECT rt, rs, rb;
45 const int nButtonWidth = 44;
46 const int nButtonHeight = 22;
47 int cyEdge = GetSystemMetrics(SM_CYEDGE);
48 const UINT uFlags = SWP_NOZORDER | SWP_NOACTIVATE;
49 SetRect(&rt, 0, 0, cx, cy);
50 cy = 0;
51 if (hStatusBar != NULL)
52 {
53 GetWindowRect(hStatusBar, &rs);
54 cy = rs.bottom - rs.top;
55 }
56 GetWindowRect(g_pChildWnd->hAddressBtnWnd, &rb);
57 cx = g_pChildWnd->nSplitPos + SPLIT_WIDTH / 2;
58 if (hdwp)
59 hdwp = DeferWindowPos(hdwp, g_pChildWnd->hAddressBarWnd, NULL,
60 rt.left, rt.top,
61 rt.right - rt.left - nButtonWidth, nButtonHeight,
62 uFlags);
63 if (hdwp)
64 hdwp = DeferWindowPos(hdwp, g_pChildWnd->hAddressBtnWnd, NULL,
65 rt.right - nButtonWidth, rt.top,
66 nButtonWidth, nButtonHeight,
67 uFlags);
68 if (hdwp)
69 hdwp = DeferWindowPos(hdwp, g_pChildWnd->hTreeWnd, NULL,
70 rt.left,
71 rt.top + nButtonHeight + cyEdge,
72 g_pChildWnd->nSplitPos - SPLIT_WIDTH/2 - rt.left,
73 rt.bottom - rt.top - cy - 2 * cyEdge,
74 uFlags);
75 if (hdwp)
76 hdwp = DeferWindowPos(hdwp, g_pChildWnd->hListWnd, NULL,
77 rt.left + cx,
78 rt.top + nButtonHeight + cyEdge,
79 rt.right - cx,
80 rt.bottom - rt.top - cy - 2 * cyEdge,
81 uFlags);
82 if (hdwp)
83 EndDeferWindowPos(hdwp);
84 }
85
86 /*******************************************************************************
87 * Local module support methods
88 */
89
90 static void draw_splitbar(HWND hWnd, int x)
91 {
92 RECT rt;
93 HGDIOBJ OldObj;
94 HDC hdc = GetDC(hWnd);
95
96 if(!SizingPattern)
97 {
98 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
99 SizingPattern = CreateBitmap(8, 8, 1, 1, Pattern);
100 }
101 if(!SizingBrush)
102 {
103 SizingBrush = CreatePatternBrush(SizingPattern);
104 }
105 GetClientRect(hWnd, &rt);
106 rt.left = x - SPLIT_WIDTH/2;
107 rt.right = x + SPLIT_WIDTH/2+1;
108 OldObj = SelectObject(hdc, SizingBrush);
109 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
110 SelectObject(hdc, OldObj);
111 ReleaseDC(hWnd, hdc);
112 }
113
114 /*******************************************************************************
115 * finish_splitbar [internal]
116 *
117 * make the splitbar invisible and resize the windows
118 * (helper for ChildWndProc)
119 */
120 static void finish_splitbar(HWND hWnd, int x)
121 {
122 RECT rt;
123
124 draw_splitbar(hWnd, last_split);
125 last_split = -1;
126 GetClientRect(hWnd, &rt);
127 g_pChildWnd->nSplitPos = x;
128 ResizeWnd(rt.right, rt.bottom);
129 ReleaseCapture();
130 }
131
132 /*******************************************************************************
133 *
134 * FUNCTION: ChildWnd_CmdWndProc(HWND, unsigned, WORD, LONG)
135 *
136 * PURPOSE: Processes WM_COMMAND messages for the main frame window.
137 *
138 */
139
140 static BOOL ChildWnd_CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
141 {
142 HTREEITEM hSelection;
143 HKEY hRootKey;
144 LPCWSTR keyPath, s;
145 WORD wID = LOWORD(wParam);
146
147 UNREFERENCED_PARAMETER(message);
148
149 switch (wID)
150 {
151 /* Parse the menu selections: */
152 case ID_REGISTRY_EXIT:
153 DestroyWindow(hWnd);
154 break;
155 case ID_VIEW_REFRESH:
156 /* TODO */
157 break;
158 case ID_TREE_EXPANDBRANCH:
159 TreeView_Expand(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), TVE_EXPAND);
160 break;
161 case ID_TREE_COLLAPSEBRANCH:
162 TreeView_Expand(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), TVE_COLLAPSE);
163 break;
164 case ID_TREE_RENAME:
165 SetFocus(g_pChildWnd->hTreeWnd);
166 TreeView_EditLabel(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd));
167 break;
168 case ID_TREE_DELETE:
169 hSelection = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
170 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, hSelection, &hRootKey);
171
172 if (keyPath == 0 || *keyPath == 0)
173 {
174 MessageBeep(MB_ICONHAND);
175 }
176 else if (DeleteKey(hWnd, hRootKey, keyPath))
177 DeleteNode(g_pChildWnd->hTreeWnd, 0);
178 break;
179 case ID_TREE_EXPORT:
180 ExportRegistryFile(g_pChildWnd->hTreeWnd);
181 break;
182 case ID_EDIT_FIND:
183 FindDialog(hWnd);
184 break;
185 case ID_EDIT_COPYKEYNAME:
186 hSelection = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
187 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, hSelection, &hRootKey);
188 CopyKeyName(hWnd, hRootKey, keyPath);
189 break;
190 case ID_EDIT_NEW_KEY:
191 CreateNewKey(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd));
192 break;
193 case ID_EDIT_NEW_STRINGVALUE:
194 case ID_EDIT_NEW_BINARYVALUE:
195 case ID_EDIT_NEW_DWORDVALUE:
196 SendMessageW(hFrameWnd, WM_COMMAND, wParam, lParam);
197 break;
198 case ID_SWITCH_PANELS:
199 g_pChildWnd->nFocusPanel = !g_pChildWnd->nFocusPanel;
200 SetFocus(g_pChildWnd->nFocusPanel? g_pChildWnd->hListWnd: g_pChildWnd->hTreeWnd);
201 break;
202 default:
203 if ((wID >= ID_TREE_SUGGESTION_MIN) && (wID <= ID_TREE_SUGGESTION_MAX))
204 {
205 s = Suggestions;
206 while(wID > ID_TREE_SUGGESTION_MIN)
207 {
208 if (*s)
209 s += wcslen(s) + 1;
210 wID--;
211 }
212 SelectNode(g_pChildWnd->hTreeWnd, s);
213 break;
214 }
215 return FALSE;
216 }
217 return TRUE;
218 }
219
220 /*******************************************************************************
221 *
222 * Key suggestion
223 */
224
225 #define MIN(a,b) ((a < b) ? (a) : (b))
226
227 static void SuggestKeys(HKEY hRootKey, LPCWSTR pszKeyPath, LPWSTR pszSuggestions,
228 size_t iSuggestionsLength)
229 {
230 WCHAR szBuffer[256];
231 WCHAR szLastFound[256];
232 size_t i;
233 HKEY hOtherKey, hSubKey;
234 BOOL bFound;
235
236 memset(pszSuggestions, 0, iSuggestionsLength * sizeof(*pszSuggestions));
237 iSuggestionsLength--;
238
239 /* Are we a root key in HKEY_CLASSES_ROOT? */
240 if ((hRootKey == HKEY_CLASSES_ROOT) && pszKeyPath[0] && !wcschr(pszKeyPath, L'\\'))
241 {
242 do
243 {
244 bFound = FALSE;
245
246 /* Check default key */
247 if (QueryStringValue(hRootKey, pszKeyPath, NULL,
248 szBuffer, COUNT_OF(szBuffer)) == ERROR_SUCCESS)
249 {
250 /* Sanity check this key; it cannot be empty, nor can it be a
251 * loop back */
252 if ((szBuffer[0] != L'\0') && _wcsicmp(szBuffer, pszKeyPath))
253 {
254 if (RegOpenKeyW(hRootKey, szBuffer, &hOtherKey) == ERROR_SUCCESS)
255 {
256 lstrcpynW(pszSuggestions, L"HKCR\\", (int) iSuggestionsLength);
257 i = wcslen(pszSuggestions);
258 pszSuggestions += i;
259 iSuggestionsLength -= i;
260
261 lstrcpynW(pszSuggestions, szBuffer, (int) iSuggestionsLength);
262 i = MIN(wcslen(pszSuggestions) + 1, iSuggestionsLength);
263 pszSuggestions += i;
264 iSuggestionsLength -= i;
265 RegCloseKey(hOtherKey);
266
267 bFound = TRUE;
268 wcscpy(szLastFound, szBuffer);
269 pszKeyPath = szLastFound;
270 }
271 }
272 }
273 }
274 while(bFound && (iSuggestionsLength > 0));
275
276 /* Check CLSID key */
277 if (RegOpenKeyW(hRootKey, pszKeyPath, &hSubKey) == ERROR_SUCCESS)
278 {
279 if (QueryStringValue(hSubKey, L"CLSID", NULL, szBuffer,
280 COUNT_OF(szBuffer)) == ERROR_SUCCESS)
281 {
282 lstrcpynW(pszSuggestions, L"HKCR\\CLSID\\", (int)iSuggestionsLength);
283 i = wcslen(pszSuggestions);
284 pszSuggestions += i;
285 iSuggestionsLength -= i;
286
287 lstrcpynW(pszSuggestions, szBuffer, (int)iSuggestionsLength);
288 i = MIN(wcslen(pszSuggestions) + 1, iSuggestionsLength);
289 pszSuggestions += i;
290 iSuggestionsLength -= i;
291 }
292 RegCloseKey(hSubKey);
293 }
294 }
295 }
296
297
298 LRESULT CALLBACK AddressBarProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
299 {
300 WNDPROC oldwndproc;
301 static WCHAR s_szNode[256];
302 oldwndproc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA);
303
304 switch (uMsg)
305 {
306 case WM_KEYUP:
307 if (wParam == VK_RETURN)
308 {
309 GetWindowTextW(hwnd, s_szNode, COUNT_OF(s_szNode));
310 SelectNode(g_pChildWnd->hTreeWnd, s_szNode);
311 }
312 break;
313 default:
314 break;
315 }
316 return CallWindowProcW(oldwndproc, hwnd, uMsg, wParam, lParam);
317 }
318
319 static VOID
320 UpdateAddress(HTREEITEM hItem, HKEY hRootKey, LPCWSTR pszPath)
321 {
322 LPCWSTR keyPath, rootName;
323 LPWSTR fullPath;
324
325 /* Wipe the listview, the status bar and the address bar if the root key was selected */
326 if (TreeView_GetParent(g_pChildWnd->hTreeWnd, hItem) == NULL)
327 {
328 ListView_DeleteAllItems(g_pChildWnd->hListWnd);
329 SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)NULL);
330 SendMessageW(g_pChildWnd->hAddressBarWnd, WM_SETTEXT, 0, (LPARAM)NULL);
331 return;
332 }
333
334 if (pszPath == NULL)
335 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, hItem, &hRootKey);
336 else
337 keyPath = pszPath;
338
339 if (keyPath)
340 {
341 RefreshListView(g_pChildWnd->hListWnd, hRootKey, keyPath);
342 rootName = get_root_key_name(hRootKey);
343 fullPath = HeapAlloc(GetProcessHeap(), 0, (wcslen(rootName) + 1 + wcslen(keyPath) + 1) * sizeof(WCHAR));
344 if (fullPath)
345 {
346 /* set (correct) the address bar text */
347 if (keyPath[0] != L'\0')
348 swprintf(fullPath, L"%s\\%s", rootName, keyPath);
349 else
350 fullPath = wcscpy(fullPath, rootName);
351 SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)fullPath);
352 SendMessageW(g_pChildWnd->hAddressBarWnd, WM_SETTEXT, 0, (LPARAM)fullPath);
353 HeapFree(GetProcessHeap(), 0, fullPath);
354 /* disable hive manipulation items temporarily (enable only if necessary) */
355 EnableMenuItem(GetSubMenu(hMenuFrame,0), ID_REGISTRY_LOADHIVE, MF_BYCOMMAND | MF_GRAYED);
356 EnableMenuItem(GetSubMenu(hMenuFrame,0), ID_REGISTRY_UNLOADHIVE, MF_BYCOMMAND | MF_GRAYED);
357 /* compare the strings to see if we should enable/disable the "Load Hive" menus accordingly */
358 if (!(_wcsicmp(rootName, L"HKEY_LOCAL_MACHINE") &&
359 _wcsicmp(rootName, L"HKEY_USERS")))
360 {
361 /*
362 * enable the unload menu item if at the root, otherwise
363 * enable the load menu item if there is no slash in
364 * keyPath (ie. immediate child selected)
365 */
366 if(keyPath[0] == L'\0')
367 EnableMenuItem(GetSubMenu(hMenuFrame,0), ID_REGISTRY_LOADHIVE, MF_BYCOMMAND | MF_ENABLED);
368 else if(!wcschr(keyPath, L'\\'))
369 EnableMenuItem(GetSubMenu(hMenuFrame,0), ID_REGISTRY_UNLOADHIVE, MF_BYCOMMAND | MF_ENABLED);
370 }
371 }
372 }
373 }
374
375 /*******************************************************************************
376 *
377 * FUNCTION: ChildWndProc(HWND, unsigned, WORD, LONG)
378 *
379 * PURPOSE: Processes messages for the child windows.
380 *
381 * WM_COMMAND - process the application menu
382 * WM_DESTROY - post a quit message and return
383 *
384 */
385 LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
386 {
387 BOOL Result;
388 RECT rc;
389
390 switch (message)
391 {
392 case WM_CREATE:
393 {
394 WNDPROC oldproc;
395 HFONT hFont;
396 WCHAR buffer[MAX_PATH];
397
398 /* Load "My Computer" string */
399 LoadStringW(hInst, IDS_MY_COMPUTER, buffer, COUNT_OF(buffer));
400
401 g_pChildWnd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ChildWnd));
402 if (!g_pChildWnd) return 0;
403
404 wcsncpy(g_pChildWnd->szPath, buffer, MAX_PATH);
405 g_pChildWnd->nSplitPos = 190;
406 g_pChildWnd->hWnd = hWnd;
407 g_pChildWnd->hAddressBarWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL, WS_CHILD | WS_VISIBLE | WS_CHILDWINDOW | WS_TABSTOP,
408 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
409 hWnd, (HMENU)0, hInst, 0);
410 g_pChildWnd->hAddressBtnWnd = CreateWindowExW(0, L"Button", L"\x00BB", WS_CHILD | WS_VISIBLE | WS_CHILDWINDOW | WS_TABSTOP | BS_TEXT | BS_CENTER | BS_VCENTER | BS_FLAT | BS_DEFPUSHBUTTON,
411 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
412 hWnd, (HMENU)0, hInst, 0);
413 GetClientRect(hWnd, &rc);
414 g_pChildWnd->hTreeWnd = CreateTreeView(hWnd, g_pChildWnd->szPath, (HMENU) TREE_WINDOW);
415 g_pChildWnd->hListWnd = CreateListView(hWnd, (HMENU) LIST_WINDOW, rc.right - g_pChildWnd->nSplitPos);
416 SetFocus(g_pChildWnd->hTreeWnd);
417
418 /* set the address bar and button font */
419 if ((g_pChildWnd->hAddressBarWnd) && (g_pChildWnd->hAddressBtnWnd))
420 {
421 hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
422 SendMessageW(g_pChildWnd->hAddressBarWnd,
423 WM_SETFONT,
424 (WPARAM)hFont,
425 0);
426 SendMessageW(g_pChildWnd->hAddressBtnWnd,
427 WM_SETFONT,
428 (WPARAM)hFont,
429 0);
430 }
431 /* Subclass the AddressBar */
432 oldproc = (WNDPROC)GetWindowLongPtr(g_pChildWnd->hAddressBarWnd, GWLP_WNDPROC);
433 SetWindowLongPtr(g_pChildWnd->hAddressBarWnd, GWLP_USERDATA, (DWORD_PTR)oldproc);
434 SetWindowLongPtr(g_pChildWnd->hAddressBarWnd, GWLP_WNDPROC, (DWORD_PTR)AddressBarProc);
435 break;
436 }
437 case WM_COMMAND:
438 if(HIWORD(wParam) == BN_CLICKED)
439 {
440 PostMessageW(g_pChildWnd->hAddressBarWnd, WM_KEYUP, VK_RETURN, 0);
441 }
442
443 if (!ChildWnd_CmdWndProc(hWnd, message, wParam, lParam))
444 {
445 goto def;
446 }
447 break;
448 case WM_SETCURSOR:
449 if (LOWORD(lParam) == HTCLIENT)
450 {
451 POINT pt;
452 GetCursorPos(&pt);
453 ScreenToClient(hWnd, &pt);
454 if (pt.x>=g_pChildWnd->nSplitPos-SPLIT_WIDTH/2 && pt.x<g_pChildWnd->nSplitPos+SPLIT_WIDTH/2+1)
455 {
456 SetCursor(LoadCursorW(0, IDC_SIZEWE));
457 return TRUE;
458 }
459 }
460 goto def;
461 case WM_DESTROY:
462 DestroyListView(g_pChildWnd->hListWnd);
463 DestroyTreeView(g_pChildWnd->hTreeWnd);
464 DestroyMainMenu();
465 HeapFree(GetProcessHeap(), 0, g_pChildWnd);
466 g_pChildWnd = NULL;
467 PostQuitMessage(0);
468 break;
469 case WM_LBUTTONDOWN:
470 {
471 RECT rt;
472 int x = (short)LOWORD(lParam);
473 GetClientRect(hWnd, &rt);
474 if (x>=g_pChildWnd->nSplitPos-SPLIT_WIDTH/2 && x<g_pChildWnd->nSplitPos+SPLIT_WIDTH/2+1)
475 {
476 last_split = g_pChildWnd->nSplitPos;
477 draw_splitbar(hWnd, last_split);
478 SetCapture(hWnd);
479 }
480 break;
481 }
482
483 case WM_LBUTTONUP:
484 case WM_RBUTTONDOWN:
485 if (GetCapture() == hWnd)
486 {
487 finish_splitbar(hWnd, LOWORD(lParam));
488 }
489 break;
490
491 case WM_CAPTURECHANGED:
492 if (GetCapture()==hWnd && last_split>=0)
493 draw_splitbar(hWnd, last_split);
494 break;
495
496 case WM_KEYDOWN:
497 if (wParam == VK_ESCAPE)
498 if (GetCapture() == hWnd)
499 {
500 RECT rt;
501 draw_splitbar(hWnd, last_split);
502 GetClientRect(hWnd, &rt);
503 ResizeWnd(rt.right, rt.bottom);
504 last_split = -1;
505 ReleaseCapture();
506 SetCursor(LoadCursorW(0, IDC_ARROW));
507 }
508 break;
509
510 case WM_MOUSEMOVE:
511 if (GetCapture() == hWnd)
512 {
513 HDC hdc;
514 RECT rt;
515 HGDIOBJ OldObj;
516 int x = LOWORD(lParam);
517 if(!SizingPattern)
518 {
519 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
520 SizingPattern = CreateBitmap(8, 8, 1, 1, Pattern);
521 }
522 if(!SizingBrush)
523 {
524 SizingBrush = CreatePatternBrush(SizingPattern);
525 }
526
527 GetClientRect(hWnd, &rt);
528 x = (SHORT) min(max(x, SPLIT_MIN), rt.right - SPLIT_MIN);
529 if(last_split != x)
530 {
531 rt.left = last_split-SPLIT_WIDTH/2;
532 rt.right = last_split+SPLIT_WIDTH/2+1;
533 hdc = GetDC(hWnd);
534 OldObj = SelectObject(hdc, SizingBrush);
535 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
536 last_split = x;
537 rt.left = x-SPLIT_WIDTH/2;
538 rt.right = x+SPLIT_WIDTH/2+1;
539 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
540 SelectObject(hdc, OldObj);
541 ReleaseDC(hWnd, hdc);
542 }
543 }
544 break;
545
546 case WM_SETFOCUS:
547 if (g_pChildWnd != NULL)
548 {
549 SetFocus(g_pChildWnd->nFocusPanel? g_pChildWnd->hListWnd: g_pChildWnd->hTreeWnd);
550 }
551 break;
552
553 case WM_TIMER:
554 break;
555
556 case WM_NOTIFY:
557 if ((int)wParam == TREE_WINDOW && g_pChildWnd != NULL)
558 {
559 switch (((LPNMHDR)lParam)->code)
560 {
561 case TVN_ITEMEXPANDING:
562 return !OnTreeExpanding(g_pChildWnd->hTreeWnd, (NMTREEVIEW*)lParam);
563 case TVN_SELCHANGED:
564 {
565 NMTREEVIEW* pnmtv = (NMTREEVIEW*)lParam;
566 /* Get the parent of the current item */
567 HTREEITEM hParentItem = TreeView_GetParent(g_pChildWnd->hTreeWnd, pnmtv->itemNew.hItem);
568
569 UpdateAddress(pnmtv->itemNew.hItem, NULL, NULL);
570
571 /*
572 * Disable Delete/Rename menu options for 'My Computer' (first item so doesn't have any parent)
573 * and HKEY_* keys (their parent is 'My Computer' and the previous remark applies).
574 */
575 if (!hParentItem || !TreeView_GetParent(g_pChildWnd->hTreeWnd, hParentItem))
576 {
577 EnableMenuItem(hMenuFrame , ID_EDIT_DELETE, MF_BYCOMMAND | MF_GRAYED);
578 EnableMenuItem(hMenuFrame , ID_EDIT_RENAME, MF_BYCOMMAND | MF_GRAYED);
579 EnableMenuItem(hPopupMenus, ID_TREE_DELETE, MF_BYCOMMAND | MF_GRAYED);
580 EnableMenuItem(hPopupMenus, ID_TREE_RENAME, MF_BYCOMMAND | MF_GRAYED);
581 }
582 else
583 {
584 EnableMenuItem(hMenuFrame , ID_EDIT_DELETE, MF_BYCOMMAND | MF_ENABLED);
585 EnableMenuItem(hMenuFrame , ID_EDIT_RENAME, MF_BYCOMMAND | MF_ENABLED);
586 EnableMenuItem(hPopupMenus, ID_TREE_DELETE, MF_BYCOMMAND | MF_ENABLED);
587 EnableMenuItem(hPopupMenus, ID_TREE_RENAME, MF_BYCOMMAND | MF_ENABLED);
588 }
589
590 break;
591 }
592 case NM_SETFOCUS:
593 g_pChildWnd->nFocusPanel = 0;
594 break;
595 case TVN_BEGINLABELEDIT:
596 {
597 LPNMTVDISPINFO ptvdi;
598 /* cancel label edit for rootkeys */
599 ptvdi = (LPNMTVDISPINFO) lParam;
600 if (!TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem) ||
601 !TreeView_GetParent(g_pChildWnd->hTreeWnd, TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem)))
602 return TRUE;
603 break;
604 }
605 case TVN_ENDLABELEDIT:
606 {
607 LPCWSTR keyPath;
608 HKEY hRootKey;
609 HKEY hKey = NULL;
610 LPNMTVDISPINFO ptvdi;
611 LONG lResult = TRUE;
612 WCHAR szBuffer[MAX_PATH];
613
614 ptvdi = (LPNMTVDISPINFO) lParam;
615 if (ptvdi->item.pszText)
616 {
617 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem), &hRootKey);
618 _snwprintf(szBuffer, COUNT_OF(szBuffer), L"%s\\%s", keyPath, ptvdi->item.pszText);
619 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, ptvdi->item.hItem, &hRootKey);
620 if (RegOpenKeyExW(hRootKey, szBuffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
621 {
622 lResult = FALSE;
623 RegCloseKey(hKey);
624 TreeView_EditLabel(g_pChildWnd->hTreeWnd, ptvdi->item.hItem);
625 }
626 else
627 {
628 if (RenameKey(hRootKey, keyPath, ptvdi->item.pszText) != ERROR_SUCCESS)
629 lResult = FALSE;
630 else
631 UpdateAddress(ptvdi->item.hItem, hRootKey, szBuffer);
632 }
633 return lResult;
634 }
635 }
636 default:
637 return 0;
638 }
639 }
640 else
641 {
642 if ((int)wParam == LIST_WINDOW && g_pChildWnd != NULL)
643 {
644 switch (((LPNMHDR)lParam)->code)
645 {
646 case NM_SETFOCUS:
647 g_pChildWnd->nFocusPanel = 1;
648 break;
649 default:
650 if(!ListWndNotifyProc(g_pChildWnd->hListWnd, wParam, lParam, &Result))
651 {
652 goto def;
653 }
654 return Result;
655 break;
656 }
657 }
658 }
659 break;
660
661 case WM_CONTEXTMENU:
662 {
663 POINT pt;
664 if((HWND)wParam == g_pChildWnd->hListWnd)
665 {
666 int i, cnt;
667 BOOL IsDefault;
668 pt.x = (short) LOWORD(lParam);
669 pt.y = (short) HIWORD(lParam);
670 cnt = ListView_GetSelectedCount(g_pChildWnd->hListWnd);
671 i = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_FOCUSED | LVNI_SELECTED);
672 if (pt.x == -1 && pt.y == -1)
673 {
674 RECT rc;
675 if (i != -1)
676 {
677 rc.left = LVIR_BOUNDS;
678 SendMessageW(g_pChildWnd->hListWnd, LVM_GETITEMRECT, i, (LPARAM) &rc);
679 pt.x = rc.left + 8;
680 pt.y = rc.top + 8;
681 }
682 else
683 pt.x = pt.y = 0;
684 ClientToScreen(g_pChildWnd->hListWnd, &pt);
685 }
686 if(i == -1)
687 {
688 TrackPopupMenu(GetSubMenu(hPopupMenus, PM_NEW), TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL);
689 }
690 else
691 {
692 HMENU mnu = GetSubMenu(hPopupMenus, PM_MODIFYVALUE);
693 SetMenuDefaultItem(mnu, ID_EDIT_MODIFY, MF_BYCOMMAND);
694 IsDefault = IsDefaultValue(g_pChildWnd->hListWnd, i);
695 if(cnt == 1)
696 EnableMenuItem(mnu, ID_EDIT_RENAME, MF_BYCOMMAND | (IsDefault ? MF_DISABLED | MF_GRAYED : MF_ENABLED));
697 else
698 EnableMenuItem(mnu, ID_EDIT_RENAME, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
699 EnableMenuItem(mnu, ID_EDIT_MODIFY, MF_BYCOMMAND | (cnt == 1 ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
700 EnableMenuItem(mnu, ID_EDIT_MODIFY_BIN, MF_BYCOMMAND | (cnt == 1 ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
701
702 TrackPopupMenu(mnu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL);
703 }
704 }
705 else if ((HWND)wParam == g_pChildWnd->hTreeWnd)
706 {
707 TVHITTESTINFO hti;
708 HMENU hContextMenu;
709 TVITEMW item;
710 MENUITEMINFOW mii;
711 WCHAR resource[256];
712 WCHAR buffer[256];
713 LPWSTR s;
714 LPCWSTR keyPath;
715 HKEY hRootKey;
716 int iLastPos;
717 WORD wID;
718
719 pt.x = (short) LOWORD(lParam);
720 pt.y = (short) HIWORD(lParam);
721
722 if (pt.x == -1 && pt.y == -1)
723 {
724 RECT rc;
725 hti.hItem = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
726 if (hti.hItem != NULL)
727 {
728 TreeView_GetItemRect(g_pChildWnd->hTreeWnd, hti.hItem, &rc, TRUE);
729 pt.x = rc.left + 8;
730 pt.y = rc.top + 8;
731 ClientToScreen(g_pChildWnd->hTreeWnd, &pt);
732 hti.flags = TVHT_ONITEM;
733 }
734 else
735 hti.flags = 0;
736 }
737 else
738 {
739 hti.pt.x = pt.x;
740 hti.pt.y = pt.y;
741 ScreenToClient(g_pChildWnd->hTreeWnd, &hti.pt);
742 TreeView_HitTest(g_pChildWnd->hTreeWnd, &hti);
743 }
744
745 if (hti.flags & TVHT_ONITEM)
746 {
747 hContextMenu = GetSubMenu(hPopupMenus, PM_TREECONTEXT);
748 TreeView_SelectItem(g_pChildWnd->hTreeWnd, hti.hItem);
749
750 memset(&item, 0, sizeof(item));
751 item.mask = TVIF_STATE | TVIF_CHILDREN;
752 item.hItem = hti.hItem;
753 TreeView_GetItem(g_pChildWnd->hTreeWnd, &item);
754
755 /* Set the Expand/Collapse menu item appropriately */
756 LoadStringW(hInst, (item.state & TVIS_EXPANDED) ? IDS_COLLAPSE : IDS_EXPAND, buffer, COUNT_OF(buffer));
757 memset(&mii, 0, sizeof(mii));
758 mii.cbSize = sizeof(mii);
759 mii.fMask = MIIM_STRING | MIIM_STATE | MIIM_ID;
760 mii.fState = (item.cChildren > 0) ? MFS_DEFAULT : MFS_GRAYED;
761 mii.wID = (item.state & TVIS_EXPANDED) ? ID_TREE_COLLAPSEBRANCH : ID_TREE_EXPANDBRANCH;
762 mii.dwTypeData = (LPWSTR) buffer;
763 SetMenuItemInfo(hContextMenu, 0, TRUE, &mii);
764
765 /* Remove any existing suggestions */
766 memset(&mii, 0, sizeof(mii));
767 mii.cbSize = sizeof(mii);
768 mii.fMask = MIIM_ID;
769 GetMenuItemInfo(hContextMenu, GetMenuItemCount(hContextMenu) - 1, TRUE, &mii);
770 if ((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX))
771 {
772 do
773 {
774 iLastPos = GetMenuItemCount(hContextMenu) - 1;
775 GetMenuItemInfo(hContextMenu, iLastPos, TRUE, &mii);
776 RemoveMenu(hContextMenu, iLastPos, MF_BYPOSITION);
777 }
778 while((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX));
779 }
780
781 /* Come up with suggestions */
782 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, NULL, &hRootKey);
783 SuggestKeys(hRootKey, keyPath, Suggestions, COUNT_OF(Suggestions));
784 if (Suggestions[0])
785 {
786 AppendMenu(hContextMenu, MF_SEPARATOR, 0, NULL);
787
788 LoadStringW(hInst, IDS_GOTO_SUGGESTED_KEY, resource, COUNT_OF(resource));
789
790 s = Suggestions;
791 wID = ID_TREE_SUGGESTION_MIN;
792 while(*s && (wID <= ID_TREE_SUGGESTION_MAX))
793 {
794 _snwprintf(buffer, COUNT_OF(buffer), resource, s);
795
796 memset(&mii, 0, sizeof(mii));
797 mii.cbSize = sizeof(mii);
798 mii.fMask = MIIM_STRING | MIIM_ID;
799 mii.wID = wID++;
800 mii.dwTypeData = buffer;
801 InsertMenuItem(hContextMenu, GetMenuItemCount(hContextMenu), TRUE, &mii);
802
803 s += wcslen(s) + 1;
804 }
805 }
806 TrackPopupMenu(hContextMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, g_pChildWnd->hWnd, NULL);
807 }
808 }
809 break;
810 }
811
812 case WM_SIZE:
813 if (wParam != SIZE_MINIMIZED && g_pChildWnd != NULL)
814 {
815 ResizeWnd(LOWORD(lParam), HIWORD(lParam));
816 }
817 /* fall through */
818 default:
819 def:
820 return DefWindowProcW(hWnd, message, wParam, lParam);
821 }
822 return 0;
823 }