fixed 4 memory leaks
[reactos.git] / reactos / subsys / system / 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */
22 #include <windows.h>
23 #include <commctrl.h>
24 #include <tchar.h>
25 #include <stdio.h>
26
27 #include "main.h"
28 #include "regproc.h"
29
30 ChildWnd* g_pChildWnd;
31 HBITMAP SizingPattern = 0;
32 HBRUSH SizingBrush = 0;
33 static TCHAR Suggestions[256];
34
35 /*******************************************************************************
36 * Local module support methods
37 */
38
39 static LPCTSTR get_root_key_name(HKEY hRootKey)
40 {
41 if (hRootKey == HKEY_CLASSES_ROOT) return _T("HKEY_CLASSES_ROOT");
42 if (hRootKey == HKEY_CURRENT_USER) return _T("HKEY_CURRENT_USER");
43 if (hRootKey == HKEY_LOCAL_MACHINE) return _T("HKEY_LOCAL_MACHINE");
44 if (hRootKey == HKEY_USERS) return _T("HKEY_USERS");
45 if (hRootKey == HKEY_CURRENT_CONFIG) return _T("HKEY_CURRENT_CONFIG");
46 if (hRootKey == HKEY_DYN_DATA) return _T("HKEY_DYN_DATA");
47 return _T("UKNOWN HKEY, PLEASE REPORT");
48 }
49
50 static void draw_splitbar(HWND hWnd, int x)
51 {
52 RECT rt;
53 HGDIOBJ OldObj;
54 HDC hdc = GetDC(hWnd);
55
56 if(!SizingPattern)
57 {
58 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
59 SizingPattern = CreateBitmap(8, 8, 1, 1, Pattern);
60 }
61 if(!SizingBrush)
62 {
63 SizingBrush = CreatePatternBrush(SizingPattern);
64 }
65 GetClientRect(hWnd, &rt);
66 rt.left = x - SPLIT_WIDTH/2;
67 rt.right = x + SPLIT_WIDTH/2+1;
68 OldObj = SelectObject(hdc, SizingBrush);
69 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
70 SelectObject(hdc, OldObj);
71 ReleaseDC(hWnd, hdc);
72 }
73
74 static void ResizeWnd(ChildWnd* pChildWnd, int cx, int cy)
75 {
76 HDWP hdwp = BeginDeferWindowPos(2);
77 RECT rt = {0, 0, cx, cy};
78
79 cx = pChildWnd->nSplitPos + SPLIT_WIDTH/2;
80 DeferWindowPos(hdwp, pChildWnd->hTreeWnd, 0, rt.left, rt.top, pChildWnd->nSplitPos-SPLIT_WIDTH/2-rt.left, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
81 DeferWindowPos(hdwp, pChildWnd->hListWnd, 0, rt.left+cx , rt.top, rt.right-cx, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
82 EndDeferWindowPos(hdwp);
83 }
84
85 static void OnPaint(HWND hWnd)
86 {
87 PAINTSTRUCT ps;
88 RECT rt;
89 HDC hdc;
90
91 GetClientRect(hWnd, &rt);
92 hdc = BeginPaint(hWnd, &ps);
93 FillRect(ps.hdc, &rt, GetSysColorBrush(COLOR_BTNFACE));
94 EndPaint(hWnd, &ps);
95 }
96
97 /*******************************************************************************
98 *
99 * FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
100 *
101 * PURPOSE: Processes WM_COMMAND messages for the main frame window.
102 *
103 */
104
105 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
106 {
107 ChildWnd* pChildWnd = g_pChildWnd;
108 HTREEITEM hSelection;
109 HKEY hRootKey;
110 LPCTSTR keyPath, s;
111 TCHAR szConfirmTitle[256];
112 TCHAR szConfirmText[256];
113 WORD wID = LOWORD(wParam);
114
115 switch (wID) {
116 /* Parse the menu selections: */
117 case ID_REGISTRY_EXIT:
118 DestroyWindow(hWnd);
119 break;
120 case ID_VIEW_REFRESH:
121 /* TODO */
122 break;
123 case ID_TREE_EXPANDBRANCH:
124 TreeView_Expand(pChildWnd->hTreeWnd, TreeView_GetSelection(pChildWnd->hTreeWnd), TVE_EXPAND);
125 break;
126 case ID_TREE_COLLAPSEBRANCH:
127 TreeView_Expand(pChildWnd->hTreeWnd, TreeView_GetSelection(pChildWnd->hTreeWnd), TVE_COLLAPSE);
128 break;
129 case ID_TREE_RENAME:
130 SetFocus(pChildWnd->hTreeWnd);
131 TreeView_EditLabel(pChildWnd->hTreeWnd, TreeView_GetSelection(pChildWnd->hTreeWnd));
132 break;
133 case ID_TREE_DELETE:
134 hSelection = TreeView_GetSelection(pChildWnd->hTreeWnd);
135 keyPath = GetItemPath(pChildWnd->hTreeWnd, hSelection, &hRootKey);
136
137 LoadString(hInst, IDS_QUERY_DELETE_KEY_CONFIRM, szConfirmTitle, sizeof(szConfirmTitle) / sizeof(szConfirmTitle[0]));
138 LoadString(hInst, IDS_QUERY_DELETE_KEY_ONE, szConfirmText, sizeof(szConfirmText) / sizeof(szConfirmText[0]));
139
140 if (MessageBox(pChildWnd->hWnd, szConfirmText, szConfirmTitle, MB_YESNO) == IDYES)
141 {
142 if (RegDeleteKeyRecursive(hRootKey, keyPath) == ERROR_SUCCESS)
143 TreeView_DeleteItem(pChildWnd->hTreeWnd, hSelection);
144 }
145 break;
146 case ID_EDIT_COPYKEYNAME:
147 hSelection = TreeView_GetSelection(pChildWnd->hTreeWnd);
148 keyPath = GetItemPath(pChildWnd->hTreeWnd, hSelection, &hRootKey);
149 CopyKeyName(hWnd, hRootKey, keyPath);
150 break;
151 case ID_EDIT_NEW_KEY:
152 CreateNewKey(pChildWnd->hTreeWnd, TreeView_GetSelection(pChildWnd->hTreeWnd));
153 break;
154 case ID_EDIT_NEW_STRINGVALUE:
155 case ID_EDIT_NEW_BINARYVALUE:
156 case ID_EDIT_NEW_DWORDVALUE:
157 SendMessage(hFrameWnd, WM_COMMAND, wParam, lParam);
158 break;
159 case ID_SWITCH_PANELS:
160 pChildWnd->nFocusPanel = !pChildWnd->nFocusPanel;
161 SetFocus(pChildWnd->nFocusPanel? pChildWnd->hListWnd: pChildWnd->hTreeWnd);
162 break;
163 default:
164 if ((wID >= ID_TREE_SUGGESTION_MIN) && (wID <= ID_TREE_SUGGESTION_MAX))
165 {
166 s = Suggestions;
167 while(wID > ID_TREE_SUGGESTION_MIN)
168 {
169 if (*s)
170 s += _tcslen(s) + 1;
171 wID--;
172 }
173 SelectNode(pChildWnd->hTreeWnd, s);
174 break;
175 }
176 return FALSE;
177 }
178 return TRUE;
179 }
180
181 /*******************************************************************************
182 *
183 * Key suggestion
184 */
185
186 #define MIN(a,b) ((a < b) ? (a) : (b))
187
188 static void SuggestKeys(HKEY hRootKey, LPCTSTR pszKeyPath, LPTSTR pszSuggestions,
189 size_t iSuggestionsLength)
190 {
191 TCHAR szBuffer[256];
192 TCHAR szLastFound[256];
193 size_t i;
194 HKEY hOtherKey, hSubKey;
195 BOOL bFound;
196
197 memset(pszSuggestions, 0, iSuggestionsLength * sizeof(*pszSuggestions));
198 iSuggestionsLength--;
199
200 /* Are we a root key in HKEY_CLASSES_ROOT? */
201 if ((hRootKey == HKEY_CLASSES_ROOT) && pszKeyPath[0] && !_tcschr(pszKeyPath, '\\'))
202 {
203 do
204 {
205 bFound = FALSE;
206
207 /* Check default key */
208 if (RegQueryStringValue(hRootKey, pszKeyPath, NULL,
209 szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0])) == ERROR_SUCCESS)
210 {
211 /* Sanity check this key; it cannot be empty, nor can it be a
212 * loop back */
213 if ((szBuffer[0] != '\0') && _tcsicmp(szBuffer, pszKeyPath))
214 {
215 if (RegOpenKey(hRootKey, szBuffer, &hOtherKey) == ERROR_SUCCESS)
216 {
217 lstrcpyn(pszSuggestions, TEXT("HKCR\\"), iSuggestionsLength);
218 i = _tcslen(pszSuggestions);
219 pszSuggestions += i;
220 iSuggestionsLength -= i;
221
222 lstrcpyn(pszSuggestions, szBuffer, iSuggestionsLength);
223 i = MIN(_tcslen(pszSuggestions) + 1, iSuggestionsLength);
224 pszSuggestions += i;
225 iSuggestionsLength -= i;
226 RegCloseKey(hOtherKey);
227
228 bFound = TRUE;
229 _tcscpy(szLastFound, szBuffer);
230 pszKeyPath = szLastFound;
231 }
232 }
233 }
234 }
235 while(bFound && (iSuggestionsLength > 0));
236
237 /* Check CLSID key */
238 if (RegOpenKey(hRootKey, pszKeyPath, &hSubKey) == ERROR_SUCCESS)
239 {
240 if (RegQueryStringValue(hSubKey, TEXT("CLSID"), NULL,
241 szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0])) == ERROR_SUCCESS)
242 {
243 lstrcpyn(pszSuggestions, TEXT("HKCR\\CLSID\\"), iSuggestionsLength);
244 i = _tcslen(pszSuggestions);
245 pszSuggestions += i;
246 iSuggestionsLength -= i;
247
248 lstrcpyn(pszSuggestions, szBuffer, iSuggestionsLength);
249 i = MIN(_tcslen(pszSuggestions) + 1, iSuggestionsLength);
250 pszSuggestions += i;
251 iSuggestionsLength -= i;
252 }
253 RegCloseKey(hSubKey);
254 }
255 }
256 }
257
258 /*******************************************************************************
259 *
260 * FUNCTION: ChildWndProc(HWND, unsigned, WORD, LONG)
261 *
262 * PURPOSE: Processes messages for the child windows.
263 *
264 * WM_COMMAND - process the application menu
265 * WM_PAINT - Paint the main window
266 * WM_DESTROY - post a quit message and return
267 *
268 */
269 LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
270 {
271 static short last_split;
272 BOOL Result;
273 ChildWnd* pChildWnd = g_pChildWnd;
274
275 switch (message) {
276 case WM_CREATE:
277 {
278 TCHAR buffer[MAX_PATH];
279 /* load "My Computer" string */
280 LoadString(hInst, IDS_MY_COMPUTER, buffer, sizeof(buffer)/sizeof(TCHAR));
281
282 g_pChildWnd = pChildWnd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ChildWnd));
283
284 if (!pChildWnd) return 0;
285 _tcsncpy(pChildWnd->szPath, buffer, MAX_PATH);
286 pChildWnd->nSplitPos = 250;
287 pChildWnd->hWnd = hWnd;
288 pChildWnd->hTreeWnd = CreateTreeView(hWnd, pChildWnd->szPath, TREE_WINDOW);
289 pChildWnd->hListWnd = CreateListView(hWnd, LIST_WINDOW/*, pChildWnd->szPath*/);
290 SetFocus(pChildWnd->hTreeWnd);
291 break;
292 }
293 case WM_COMMAND:
294 if (!_CmdWndProc(hWnd, message, wParam, lParam)) {
295 goto def;
296 }
297 break;
298 case WM_PAINT:
299 OnPaint(hWnd);
300 return 0;
301 case WM_SETCURSOR:
302 if (LOWORD(lParam) == HTCLIENT) {
303 POINT pt;
304 GetCursorPos(&pt);
305 ScreenToClient(hWnd, &pt);
306 if (pt.x>=pChildWnd->nSplitPos-SPLIT_WIDTH/2 && pt.x<pChildWnd->nSplitPos+SPLIT_WIDTH/2+1) {
307 SetCursor(LoadCursor(0, IDC_SIZEWE));
308 return TRUE;
309 }
310 }
311 goto def;
312 case WM_DESTROY:
313 DestroyTreeView();
314 DestroyListView(pChildWnd->hListWnd);
315 DestroyMainMenu();
316 HeapFree(GetProcessHeap(), 0, pChildWnd);
317 pChildWnd = NULL;
318 PostQuitMessage(0);
319 break;
320 case WM_LBUTTONDOWN: {
321 RECT rt;
322 POINTS pt;
323 pt = MAKEPOINTS(lParam);
324 GetClientRect(hWnd, &rt);
325 if (pt.x>=pChildWnd->nSplitPos-SPLIT_WIDTH/2 && pt.x<pChildWnd->nSplitPos+SPLIT_WIDTH/2+1) {
326 last_split = pChildWnd->nSplitPos;
327 draw_splitbar(hWnd, last_split);
328 SetCapture(hWnd);
329 }
330 break;
331 }
332
333 case WM_LBUTTONUP:
334 if (GetCapture() == hWnd) {
335 RECT rt;
336 POINTS pt;
337 pt = MAKEPOINTS(lParam);
338 GetClientRect(hWnd, &rt);
339 pt.x = (SHORT) min(max(pt.x, SPLIT_MIN), rt.right - SPLIT_MIN);
340 draw_splitbar(hWnd, last_split);
341 last_split = -1;
342 pChildWnd->nSplitPos = pt.x;
343 ResizeWnd(pChildWnd, rt.right, rt.bottom);
344 ReleaseCapture();
345 }
346 break;
347
348 case WM_CAPTURECHANGED:
349 if (GetCapture()==hWnd && last_split>=0)
350 draw_splitbar(hWnd, last_split);
351 break;
352
353 case WM_KEYDOWN:
354 if (wParam == VK_ESCAPE)
355 if (GetCapture() == hWnd) {
356 RECT rt;
357 draw_splitbar(hWnd, last_split);
358 GetClientRect(hWnd, &rt);
359 ResizeWnd(pChildWnd, rt.right, rt.bottom);
360 last_split = -1;
361 ReleaseCapture();
362 SetCursor(LoadCursor(0, IDC_ARROW));
363 }
364 break;
365
366 case WM_MOUSEMOVE:
367 if (GetCapture() == hWnd) {
368 HDC hdc;
369 RECT rt;
370 HGDIOBJ OldObj;
371 POINTS pt;
372 if(!SizingPattern)
373 {
374 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
375 SizingPattern = CreateBitmap(8, 8, 1, 1, Pattern);
376 }
377 if(!SizingBrush)
378 {
379 SizingBrush = CreatePatternBrush(SizingPattern);
380 }
381
382 pt = MAKEPOINTS(lParam);
383 GetClientRect(hWnd, &rt);
384 pt.x = (SHORT) min(max(pt.x, SPLIT_MIN), rt.right - SPLIT_MIN);
385 if(last_split != pt.x)
386 {
387 rt.left = last_split-SPLIT_WIDTH/2;
388 rt.right = last_split+SPLIT_WIDTH/2+1;
389 hdc = GetDC(hWnd);
390 OldObj = SelectObject(hdc, SizingBrush);
391 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
392 last_split = pt.x;
393 rt.left = pt.x-SPLIT_WIDTH/2;
394 rt.right = pt.x+SPLIT_WIDTH/2+1;
395 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
396 SelectObject(hdc, OldObj);
397 ReleaseDC(hWnd, hdc);
398 }
399 }
400 break;
401
402 case WM_SETFOCUS:
403 if (pChildWnd != NULL) {
404 SetFocus(pChildWnd->nFocusPanel? pChildWnd->hListWnd: pChildWnd->hTreeWnd);
405 }
406 break;
407
408 case WM_TIMER:
409 break;
410
411 case WM_NOTIFY:
412 if ((int)wParam == TREE_WINDOW) {
413 switch (((LPNMHDR)lParam)->code) {
414 case TVN_ITEMEXPANDING:
415 return !OnTreeExpanding(pChildWnd->hTreeWnd, (NMTREEVIEW*)lParam);
416 case TVN_SELCHANGED: {
417 LPCTSTR keyPath, rootName;
418 LPTSTR fullPath;
419 HKEY hRootKey;
420
421 keyPath = GetItemPath(pChildWnd->hTreeWnd, ((NMTREEVIEW*)lParam)->itemNew.hItem, &hRootKey);
422 if (keyPath) {
423 RefreshListView(pChildWnd->hListWnd, hRootKey, keyPath);
424 rootName = get_root_key_name(hRootKey);
425 fullPath = HeapAlloc(GetProcessHeap(), 0, (_tcslen(rootName) + 1 + _tcslen(keyPath) + 1) * sizeof(TCHAR));
426 if (fullPath) {
427 _stprintf(fullPath, _T("%s\\%s"), rootName, keyPath);
428 SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)fullPath);
429 HeapFree(GetProcessHeap(), 0, fullPath);
430
431 {
432 HKEY hKey;
433 TCHAR szBuffer[MAX_PATH];
434 _sntprintf(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), _T("My Computer\\%s\\%s"), rootName, keyPath);
435
436 if (RegOpenKey(HKEY_CURRENT_USER,
437 _T("Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit"),
438 &hKey) == ERROR_SUCCESS)
439 {
440 RegSetValueEx(hKey, _T("LastKey"), 0, REG_SZ, (LPBYTE) szBuffer, _tcslen(szBuffer) * sizeof(szBuffer[0]));
441 RegCloseKey(hKey);
442 }
443 }
444 }
445 }
446 }
447 break;
448 case NM_SETFOCUS:
449 pChildWnd->nFocusPanel = 0;
450 break;
451 case TVN_ENDLABELEDIT:
452 {
453 LPCTSTR keyPath;
454 HKEY hRootKey;
455 LPNMTVDISPINFO ptvdi;
456 LONG lResult;
457
458 ptvdi = (LPNMTVDISPINFO) lParam;
459 if (ptvdi->item.pszText)
460 {
461 keyPath = GetItemPath(pChildWnd->hTreeWnd, ptvdi->item.hItem, &hRootKey);
462 lResult = RegRenameKey(hRootKey, keyPath, ptvdi->item.pszText);
463 return lResult == ERROR_SUCCESS;
464 }
465 }
466 default:
467 return 0;
468 }
469 } else
470 {
471 if ((int)wParam == LIST_WINDOW)
472 {
473 switch (((LPNMHDR)lParam)->code) {
474 case NM_SETFOCUS:
475 pChildWnd->nFocusPanel = 1;
476 break;
477 default:
478 if(!ListWndNotifyProc(pChildWnd->hListWnd, wParam, lParam, &Result))
479 {
480 goto def;
481 }
482 return Result;
483 break;
484 }
485 }
486 }
487 break;
488
489 case WM_CONTEXTMENU:
490 {
491 POINTS pt;
492 if((HWND)wParam == pChildWnd->hListWnd)
493 {
494 int i, cnt;
495 BOOL IsDefault;
496 pt = MAKEPOINTS(lParam);
497 cnt = ListView_GetSelectedCount(pChildWnd->hListWnd);
498 i = ListView_GetNextItem(pChildWnd->hListWnd, -1, LVNI_FOCUSED | LVNI_SELECTED);
499 if(i == -1)
500 {
501 TrackPopupMenu(GetSubMenu(hPopupMenus, PM_NEW), TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL);
502 }
503 else
504 {
505 HMENU mnu = GetSubMenu(hPopupMenus, PM_MODIFYVALUE);
506 SetMenuDefaultItem(mnu, ID_EDIT_MODIFY, MF_BYCOMMAND);
507 IsDefault = IsDefaultValue(pChildWnd->hListWnd, i);
508 if(cnt == 1)
509 EnableMenuItem(mnu, ID_EDIT_RENAME, MF_BYCOMMAND | (IsDefault ? MF_DISABLED | MF_GRAYED : MF_ENABLED));
510 else
511 EnableMenuItem(mnu, ID_EDIT_RENAME, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
512 EnableMenuItem(mnu, ID_EDIT_MODIFY, MF_BYCOMMAND | (cnt == 1 ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
513 EnableMenuItem(mnu, ID_EDIT_MODIFY_BIN, MF_BYCOMMAND | (cnt == 1 ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
514
515 TrackPopupMenu(mnu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL);
516 }
517 }
518 else if ((HWND)wParam == pChildWnd->hTreeWnd)
519 {
520 TVHITTESTINFO hti;
521 HMENU hContextMenu;
522 TVITEM item;
523 MENUITEMINFO mii;
524 TCHAR resource[256];
525 TCHAR buffer[256];
526 LPTSTR s;
527 LPCTSTR keyPath;
528 HKEY hRootKey;
529 int iLastPos;
530 WORD wID;
531
532 pt = MAKEPOINTS(lParam);
533 hti.pt.x = pt.x;
534 hti.pt.y = pt.y;
535 ScreenToClient(pChildWnd->hTreeWnd, &hti.pt);
536 TreeView_HitTest(pChildWnd->hTreeWnd, &hti);
537
538 if ((hti.flags & TVHT_ONITEM) != 0)
539 {
540 hContextMenu = GetSubMenu(hPopupMenus, PM_TREECONTEXT);
541 TreeView_SelectItem(pChildWnd->hTreeWnd, hti.hItem);
542
543 memset(&item, 0, sizeof(item));
544 item.mask = TVIF_STATE | TVIF_CHILDREN;
545 item.hItem = hti.hItem;
546 TreeView_GetItem(pChildWnd->hTreeWnd, &item);
547
548 /* Set the Expand/Collapse menu item appropriately */
549 LoadString(hInst, (item.state & TVIS_EXPANDED) ? IDS_COLLAPSE : IDS_EXPAND, buffer, sizeof(buffer) / sizeof(buffer[0]));
550 memset(&mii, 0, sizeof(mii));
551 mii.cbSize = sizeof(mii);
552 mii.fMask = MIIM_STRING | MIIM_STATE | MIIM_ID;
553 mii.fState = (item.cChildren > 0) ? MFS_DEFAULT : MFS_GRAYED;
554 mii.wID = (item.state & TVIS_EXPANDED) ? ID_TREE_COLLAPSEBRANCH : ID_TREE_EXPANDBRANCH;
555 mii.dwTypeData = (LPTSTR) buffer;
556 SetMenuItemInfo(hContextMenu, 0, TRUE, &mii);
557
558 /* Remove any existing suggestions */
559 memset(&mii, 0, sizeof(mii));
560 mii.cbSize = sizeof(mii);
561 mii.fMask = MIIM_ID;
562 GetMenuItemInfo(hContextMenu, GetMenuItemCount(hContextMenu) - 1, TRUE, &mii);
563 if ((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX))
564 {
565 do
566 {
567 iLastPos = GetMenuItemCount(hContextMenu) - 1;
568 GetMenuItemInfo(hContextMenu, iLastPos, TRUE, &mii);
569 RemoveMenu(hContextMenu, iLastPos, MF_BYPOSITION);
570 }
571 while((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX));
572 }
573
574 /* Come up with suggestions */
575 keyPath = GetItemPath(pChildWnd->hTreeWnd, NULL, &hRootKey);
576 SuggestKeys(hRootKey, keyPath, Suggestions, sizeof(Suggestions) / sizeof(Suggestions[0]));
577 if (Suggestions[0])
578 {
579 AppendMenu(hContextMenu, MF_SEPARATOR, 0, NULL);
580
581 LoadString(hInst, IDS_GOTO_SUGGESTED_KEY, resource, sizeof(resource) / sizeof(resource[0]));
582
583 s = Suggestions;
584 wID = ID_TREE_SUGGESTION_MIN;
585 while(*s && (wID <= ID_TREE_SUGGESTION_MAX))
586 {
587 _sntprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), resource, s);
588
589 memset(&mii, 0, sizeof(mii));
590 mii.cbSize = sizeof(mii);
591 mii.fMask = MIIM_STRING | MIIM_ID;
592 mii.wID = wID++;
593 mii.dwTypeData = buffer;
594 InsertMenuItem(hContextMenu, GetMenuItemCount(hContextMenu), TRUE, &mii);
595
596 s += _tcslen(s) + 1;
597 }
598 }
599
600 TrackPopupMenu(hContextMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, pChildWnd->hWnd, NULL);
601 }
602 }
603 break;
604 }
605
606 case WM_SIZE:
607 if (wParam != SIZE_MINIMIZED && pChildWnd != NULL) {
608 ResizeWnd(pChildWnd, LOWORD(lParam), HIWORD(lParam));
609 }
610 /* fall through */
611 default: def:
612 return DefWindowProc(hWnd, message, wParam, lParam);
613 }
614 return 0;
615 }