[BROWSEUI] Fix infinite recursion in autocomplete control
[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 DWORD style;
398
399 /* Load "My Computer" string */
400 LoadStringW(hInst, IDS_MY_COMPUTER, buffer, COUNT_OF(buffer));
401
402 g_pChildWnd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ChildWnd));
403 if (!g_pChildWnd) return 0;
404
405 wcsncpy(g_pChildWnd->szPath, buffer, MAX_PATH);
406 g_pChildWnd->nSplitPos = 190;
407 g_pChildWnd->hWnd = hWnd;
408
409 style = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
410 g_pChildWnd->hAddressBarWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL, style,
411 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
412 hWnd, (HMENU)0, hInst, 0);
413
414 style = WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_ICON | BS_CENTER |
415 BS_VCENTER | BS_FLAT | BS_DEFPUSHBUTTON;
416 g_pChildWnd->hAddressBtnWnd = CreateWindowExW(0, L"Button", L"\x00BB", style,
417 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
418 hWnd, (HMENU)0, hInst, 0);
419 g_pChildWnd->hArrowIcon = (HICON)LoadImageW(hInst, MAKEINTRESOURCEW(IDI_ARROW),
420 IMAGE_ICON, 12, 12, 0);
421 SendMessageW(g_pChildWnd->hAddressBtnWnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_pChildWnd->hArrowIcon);
422
423 GetClientRect(hWnd, &rc);
424 g_pChildWnd->hTreeWnd = CreateTreeView(hWnd, g_pChildWnd->szPath, (HMENU) TREE_WINDOW);
425 g_pChildWnd->hListWnd = CreateListView(hWnd, (HMENU) LIST_WINDOW, rc.right - g_pChildWnd->nSplitPos);
426 SetFocus(g_pChildWnd->hTreeWnd);
427
428 /* set the address bar and button font */
429 if ((g_pChildWnd->hAddressBarWnd) && (g_pChildWnd->hAddressBtnWnd))
430 {
431 hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
432 SendMessageW(g_pChildWnd->hAddressBarWnd,
433 WM_SETFONT,
434 (WPARAM)hFont,
435 0);
436 SendMessageW(g_pChildWnd->hAddressBtnWnd,
437 WM_SETFONT,
438 (WPARAM)hFont,
439 0);
440 }
441 /* Subclass the AddressBar */
442 oldproc = (WNDPROC)GetWindowLongPtr(g_pChildWnd->hAddressBarWnd, GWLP_WNDPROC);
443 SetWindowLongPtr(g_pChildWnd->hAddressBarWnd, GWLP_USERDATA, (DWORD_PTR)oldproc);
444 SetWindowLongPtr(g_pChildWnd->hAddressBarWnd, GWLP_WNDPROC, (DWORD_PTR)AddressBarProc);
445 break;
446 }
447 case WM_COMMAND:
448 if(HIWORD(wParam) == BN_CLICKED)
449 {
450 PostMessageW(g_pChildWnd->hAddressBarWnd, WM_KEYUP, VK_RETURN, 0);
451 }
452
453 if (!ChildWnd_CmdWndProc(hWnd, message, wParam, lParam))
454 {
455 goto def;
456 }
457 break;
458 case WM_SETCURSOR:
459 if (LOWORD(lParam) == HTCLIENT)
460 {
461 POINT pt;
462 GetCursorPos(&pt);
463 ScreenToClient(hWnd, &pt);
464 if (pt.x>=g_pChildWnd->nSplitPos-SPLIT_WIDTH/2 && pt.x<g_pChildWnd->nSplitPos+SPLIT_WIDTH/2+1)
465 {
466 SetCursor(LoadCursorW(0, IDC_SIZEWE));
467 return TRUE;
468 }
469 }
470 goto def;
471 case WM_DESTROY:
472 DestroyListView(g_pChildWnd->hListWnd);
473 DestroyTreeView(g_pChildWnd->hTreeWnd);
474 DestroyMainMenu();
475 DestroyIcon(g_pChildWnd->hArrowIcon);
476 HeapFree(GetProcessHeap(), 0, g_pChildWnd);
477 g_pChildWnd = NULL;
478 PostQuitMessage(0);
479 break;
480 case WM_LBUTTONDOWN:
481 {
482 RECT rt;
483 int x = (short)LOWORD(lParam);
484 GetClientRect(hWnd, &rt);
485 if (x>=g_pChildWnd->nSplitPos-SPLIT_WIDTH/2 && x<g_pChildWnd->nSplitPos+SPLIT_WIDTH/2+1)
486 {
487 last_split = g_pChildWnd->nSplitPos;
488 draw_splitbar(hWnd, last_split);
489 SetCapture(hWnd);
490 }
491 break;
492 }
493
494 case WM_LBUTTONUP:
495 case WM_RBUTTONDOWN:
496 if (GetCapture() == hWnd)
497 {
498 finish_splitbar(hWnd, LOWORD(lParam));
499 }
500 break;
501
502 case WM_CAPTURECHANGED:
503 if (GetCapture()==hWnd && last_split>=0)
504 draw_splitbar(hWnd, last_split);
505 break;
506
507 case WM_KEYDOWN:
508 if (wParam == VK_ESCAPE)
509 if (GetCapture() == hWnd)
510 {
511 RECT rt;
512 draw_splitbar(hWnd, last_split);
513 GetClientRect(hWnd, &rt);
514 ResizeWnd(rt.right, rt.bottom);
515 last_split = -1;
516 ReleaseCapture();
517 SetCursor(LoadCursorW(0, IDC_ARROW));
518 }
519 break;
520
521 case WM_MOUSEMOVE:
522 if (GetCapture() == hWnd)
523 {
524 HDC hdc;
525 RECT rt;
526 HGDIOBJ OldObj;
527 int x = LOWORD(lParam);
528 if(!SizingPattern)
529 {
530 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
531 SizingPattern = CreateBitmap(8, 8, 1, 1, Pattern);
532 }
533 if(!SizingBrush)
534 {
535 SizingBrush = CreatePatternBrush(SizingPattern);
536 }
537
538 GetClientRect(hWnd, &rt);
539 x = (SHORT) min(max(x, SPLIT_MIN), rt.right - SPLIT_MIN);
540 if(last_split != x)
541 {
542 rt.left = last_split-SPLIT_WIDTH/2;
543 rt.right = last_split+SPLIT_WIDTH/2+1;
544 hdc = GetDC(hWnd);
545 OldObj = SelectObject(hdc, SizingBrush);
546 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
547 last_split = x;
548 rt.left = x-SPLIT_WIDTH/2;
549 rt.right = x+SPLIT_WIDTH/2+1;
550 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
551 SelectObject(hdc, OldObj);
552 ReleaseDC(hWnd, hdc);
553 }
554 }
555 break;
556
557 case WM_SETFOCUS:
558 if (g_pChildWnd != NULL)
559 {
560 SetFocus(g_pChildWnd->nFocusPanel? g_pChildWnd->hListWnd: g_pChildWnd->hTreeWnd);
561 }
562 break;
563
564 case WM_TIMER:
565 break;
566
567 case WM_NOTIFY:
568 if ((int)wParam == TREE_WINDOW && g_pChildWnd != NULL)
569 {
570 switch (((LPNMHDR)lParam)->code)
571 {
572 case TVN_ITEMEXPANDING:
573 return !OnTreeExpanding(g_pChildWnd->hTreeWnd, (NMTREEVIEW*)lParam);
574 case TVN_SELCHANGED:
575 {
576 NMTREEVIEW* pnmtv = (NMTREEVIEW*)lParam;
577 /* Get the parent of the current item */
578 HTREEITEM hParentItem = TreeView_GetParent(g_pChildWnd->hTreeWnd, pnmtv->itemNew.hItem);
579
580 UpdateAddress(pnmtv->itemNew.hItem, NULL, NULL);
581
582 /*
583 * Disable Delete/Rename menu options for 'My Computer' (first item so doesn't have any parent)
584 * and HKEY_* keys (their parent is 'My Computer' and the previous remark applies).
585 */
586 if (!hParentItem || !TreeView_GetParent(g_pChildWnd->hTreeWnd, hParentItem))
587 {
588 EnableMenuItem(hMenuFrame , ID_EDIT_DELETE, MF_BYCOMMAND | MF_GRAYED);
589 EnableMenuItem(hMenuFrame , ID_EDIT_RENAME, MF_BYCOMMAND | MF_GRAYED);
590 EnableMenuItem(hPopupMenus, ID_TREE_DELETE, MF_BYCOMMAND | MF_GRAYED);
591 EnableMenuItem(hPopupMenus, ID_TREE_RENAME, MF_BYCOMMAND | MF_GRAYED);
592 }
593 else
594 {
595 EnableMenuItem(hMenuFrame , ID_EDIT_DELETE, MF_BYCOMMAND | MF_ENABLED);
596 EnableMenuItem(hMenuFrame , ID_EDIT_RENAME, MF_BYCOMMAND | MF_ENABLED);
597 EnableMenuItem(hPopupMenus, ID_TREE_DELETE, MF_BYCOMMAND | MF_ENABLED);
598 EnableMenuItem(hPopupMenus, ID_TREE_RENAME, MF_BYCOMMAND | MF_ENABLED);
599 }
600
601 break;
602 }
603 case NM_SETFOCUS:
604 g_pChildWnd->nFocusPanel = 0;
605 break;
606 case TVN_BEGINLABELEDIT:
607 {
608 LPNMTVDISPINFO ptvdi;
609 /* cancel label edit for rootkeys */
610 ptvdi = (LPNMTVDISPINFO) lParam;
611 if (!TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem) ||
612 !TreeView_GetParent(g_pChildWnd->hTreeWnd, TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem)))
613 return TRUE;
614 break;
615 }
616 case TVN_ENDLABELEDIT:
617 {
618 LPCWSTR keyPath;
619 HKEY hRootKey;
620 HKEY hKey = NULL;
621 LPNMTVDISPINFO ptvdi;
622 LONG lResult = TRUE;
623 WCHAR szBuffer[MAX_PATH];
624
625 ptvdi = (LPNMTVDISPINFO) lParam;
626 if (ptvdi->item.pszText)
627 {
628 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem), &hRootKey);
629 _snwprintf(szBuffer, COUNT_OF(szBuffer), L"%s\\%s", keyPath, ptvdi->item.pszText);
630 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, ptvdi->item.hItem, &hRootKey);
631 if (RegOpenKeyExW(hRootKey, szBuffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
632 {
633 lResult = FALSE;
634 RegCloseKey(hKey);
635 TreeView_EditLabel(g_pChildWnd->hTreeWnd, ptvdi->item.hItem);
636 }
637 else
638 {
639 if (RenameKey(hRootKey, keyPath, ptvdi->item.pszText) != ERROR_SUCCESS)
640 lResult = FALSE;
641 else
642 UpdateAddress(ptvdi->item.hItem, hRootKey, szBuffer);
643 }
644 return lResult;
645 }
646 }
647 default:
648 return 0;
649 }
650 }
651 else
652 {
653 if ((int)wParam == LIST_WINDOW && g_pChildWnd != NULL)
654 {
655 switch (((LPNMHDR)lParam)->code)
656 {
657 case NM_SETFOCUS:
658 g_pChildWnd->nFocusPanel = 1;
659 break;
660 default:
661 if(!ListWndNotifyProc(g_pChildWnd->hListWnd, wParam, lParam, &Result))
662 {
663 goto def;
664 }
665 return Result;
666 break;
667 }
668 }
669 }
670 break;
671
672 case WM_CONTEXTMENU:
673 {
674 POINT pt;
675 if((HWND)wParam == g_pChildWnd->hListWnd)
676 {
677 int i, cnt;
678 BOOL IsDefault;
679 pt.x = (short) LOWORD(lParam);
680 pt.y = (short) HIWORD(lParam);
681 cnt = ListView_GetSelectedCount(g_pChildWnd->hListWnd);
682 i = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_FOCUSED | LVNI_SELECTED);
683 if (pt.x == -1 && pt.y == -1)
684 {
685 RECT rc;
686 if (i != -1)
687 {
688 rc.left = LVIR_BOUNDS;
689 SendMessageW(g_pChildWnd->hListWnd, LVM_GETITEMRECT, i, (LPARAM) &rc);
690 pt.x = rc.left + 8;
691 pt.y = rc.top + 8;
692 }
693 else
694 pt.x = pt.y = 0;
695 ClientToScreen(g_pChildWnd->hListWnd, &pt);
696 }
697 if(i == -1)
698 {
699 TrackPopupMenu(GetSubMenu(hPopupMenus, PM_NEW), TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL);
700 }
701 else
702 {
703 HMENU mnu = GetSubMenu(hPopupMenus, PM_MODIFYVALUE);
704 SetMenuDefaultItem(mnu, ID_EDIT_MODIFY, MF_BYCOMMAND);
705 IsDefault = IsDefaultValue(g_pChildWnd->hListWnd, i);
706 if(cnt == 1)
707 EnableMenuItem(mnu, ID_EDIT_RENAME, MF_BYCOMMAND | (IsDefault ? MF_DISABLED | MF_GRAYED : MF_ENABLED));
708 else
709 EnableMenuItem(mnu, ID_EDIT_RENAME, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
710 EnableMenuItem(mnu, ID_EDIT_MODIFY, MF_BYCOMMAND | (cnt == 1 ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
711 EnableMenuItem(mnu, ID_EDIT_MODIFY_BIN, MF_BYCOMMAND | (cnt == 1 ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
712
713 TrackPopupMenu(mnu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL);
714 }
715 }
716 else if ((HWND)wParam == g_pChildWnd->hTreeWnd)
717 {
718 TVHITTESTINFO hti;
719 HMENU hContextMenu;
720 TVITEMW item;
721 MENUITEMINFOW mii;
722 WCHAR resource[256];
723 WCHAR buffer[256];
724 LPWSTR s;
725 LPCWSTR keyPath;
726 HKEY hRootKey;
727 int iLastPos;
728 WORD wID;
729
730 pt.x = (short) LOWORD(lParam);
731 pt.y = (short) HIWORD(lParam);
732
733 if (pt.x == -1 && pt.y == -1)
734 {
735 RECT rc;
736 hti.hItem = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
737 if (hti.hItem != NULL)
738 {
739 TreeView_GetItemRect(g_pChildWnd->hTreeWnd, hti.hItem, &rc, TRUE);
740 pt.x = rc.left + 8;
741 pt.y = rc.top + 8;
742 ClientToScreen(g_pChildWnd->hTreeWnd, &pt);
743 hti.flags = TVHT_ONITEM;
744 }
745 else
746 hti.flags = 0;
747 }
748 else
749 {
750 hti.pt.x = pt.x;
751 hti.pt.y = pt.y;
752 ScreenToClient(g_pChildWnd->hTreeWnd, &hti.pt);
753 TreeView_HitTest(g_pChildWnd->hTreeWnd, &hti);
754 }
755
756 if (hti.flags & TVHT_ONITEM)
757 {
758 hContextMenu = GetSubMenu(hPopupMenus, PM_TREECONTEXT);
759 TreeView_SelectItem(g_pChildWnd->hTreeWnd, hti.hItem);
760
761 memset(&item, 0, sizeof(item));
762 item.mask = TVIF_STATE | TVIF_CHILDREN;
763 item.hItem = hti.hItem;
764 TreeView_GetItem(g_pChildWnd->hTreeWnd, &item);
765
766 /* Set the Expand/Collapse menu item appropriately */
767 LoadStringW(hInst, (item.state & TVIS_EXPANDED) ? IDS_COLLAPSE : IDS_EXPAND, buffer, COUNT_OF(buffer));
768 memset(&mii, 0, sizeof(mii));
769 mii.cbSize = sizeof(mii);
770 mii.fMask = MIIM_STRING | MIIM_STATE | MIIM_ID;
771 mii.fState = (item.cChildren > 0) ? MFS_DEFAULT : MFS_GRAYED;
772 mii.wID = (item.state & TVIS_EXPANDED) ? ID_TREE_COLLAPSEBRANCH : ID_TREE_EXPANDBRANCH;
773 mii.dwTypeData = (LPWSTR) buffer;
774 SetMenuItemInfo(hContextMenu, 0, TRUE, &mii);
775
776 /* Remove any existing suggestions */
777 memset(&mii, 0, sizeof(mii));
778 mii.cbSize = sizeof(mii);
779 mii.fMask = MIIM_ID;
780 GetMenuItemInfo(hContextMenu, GetMenuItemCount(hContextMenu) - 1, TRUE, &mii);
781 if ((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX))
782 {
783 do
784 {
785 iLastPos = GetMenuItemCount(hContextMenu) - 1;
786 GetMenuItemInfo(hContextMenu, iLastPos, TRUE, &mii);
787 RemoveMenu(hContextMenu, iLastPos, MF_BYPOSITION);
788 }
789 while((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX));
790 }
791
792 /* Come up with suggestions */
793 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, NULL, &hRootKey);
794 SuggestKeys(hRootKey, keyPath, Suggestions, COUNT_OF(Suggestions));
795 if (Suggestions[0])
796 {
797 AppendMenu(hContextMenu, MF_SEPARATOR, 0, NULL);
798
799 LoadStringW(hInst, IDS_GOTO_SUGGESTED_KEY, resource, COUNT_OF(resource));
800
801 s = Suggestions;
802 wID = ID_TREE_SUGGESTION_MIN;
803 while(*s && (wID <= ID_TREE_SUGGESTION_MAX))
804 {
805 _snwprintf(buffer, COUNT_OF(buffer), resource, s);
806
807 memset(&mii, 0, sizeof(mii));
808 mii.cbSize = sizeof(mii);
809 mii.fMask = MIIM_STRING | MIIM_ID;
810 mii.wID = wID++;
811 mii.dwTypeData = buffer;
812 InsertMenuItem(hContextMenu, GetMenuItemCount(hContextMenu), TRUE, &mii);
813
814 s += wcslen(s) + 1;
815 }
816 }
817 TrackPopupMenu(hContextMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, g_pChildWnd->hWnd, NULL);
818 }
819 }
820 break;
821 }
822
823 case WM_SIZE:
824 if (wParam != SIZE_MINIMIZED && g_pChildWnd != NULL)
825 {
826 ResizeWnd(LOWORD(lParam), HIWORD(lParam));
827 }
828 /* fall through */
829 default:
830 def:
831 return DefWindowProcW(hWnd, message, wParam, lParam);
832 }
833 return 0;
834 }