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