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