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 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 * Key suggestion 135 */ 136 137 #define MIN(a,b) ((a < b) ? (a) : (b)) 138 139 static void SuggestKeys(HKEY hRootKey, LPCWSTR pszKeyPath, LPWSTR pszSuggestions, 140 size_t iSuggestionsLength) 141 { 142 WCHAR szBuffer[256]; 143 WCHAR szLastFound[256]; 144 size_t i; 145 HKEY hOtherKey, hSubKey; 146 BOOL bFound; 147 148 memset(pszSuggestions, 0, iSuggestionsLength * sizeof(*pszSuggestions)); 149 iSuggestionsLength--; 150 151 /* Are we a root key in HKEY_CLASSES_ROOT? */ 152 if ((hRootKey == HKEY_CLASSES_ROOT) && pszKeyPath[0] && !wcschr(pszKeyPath, L'\\')) 153 { 154 do 155 { 156 bFound = FALSE; 157 158 /* Check default key */ 159 if (QueryStringValue(hRootKey, pszKeyPath, NULL, 160 szBuffer, ARRAY_SIZE(szBuffer)) == ERROR_SUCCESS) 161 { 162 /* Sanity check this key; it cannot be empty, nor can it be a 163 * loop back */ 164 if ((szBuffer[0] != L'\0') && _wcsicmp(szBuffer, pszKeyPath)) 165 { 166 if (RegOpenKeyW(hRootKey, szBuffer, &hOtherKey) == ERROR_SUCCESS) 167 { 168 lstrcpynW(pszSuggestions, L"HKCR\\", (int) iSuggestionsLength); 169 i = wcslen(pszSuggestions); 170 pszSuggestions += i; 171 iSuggestionsLength -= i; 172 173 lstrcpynW(pszSuggestions, szBuffer, (int) iSuggestionsLength); 174 i = MIN(wcslen(pszSuggestions) + 1, iSuggestionsLength); 175 pszSuggestions += i; 176 iSuggestionsLength -= i; 177 RegCloseKey(hOtherKey); 178 179 bFound = TRUE; 180 wcscpy(szLastFound, szBuffer); 181 pszKeyPath = szLastFound; 182 } 183 } 184 } 185 } 186 while(bFound && (iSuggestionsLength > 0)); 187 188 /* Check CLSID key */ 189 if (RegOpenKeyW(hRootKey, pszKeyPath, &hSubKey) == ERROR_SUCCESS) 190 { 191 if (QueryStringValue(hSubKey, L"CLSID", NULL, szBuffer, 192 ARRAY_SIZE(szBuffer)) == ERROR_SUCCESS) 193 { 194 lstrcpynW(pszSuggestions, L"HKCR\\CLSID\\", (int)iSuggestionsLength); 195 i = wcslen(pszSuggestions); 196 pszSuggestions += i; 197 iSuggestionsLength -= i; 198 199 lstrcpynW(pszSuggestions, szBuffer, (int)iSuggestionsLength); 200 i = MIN(wcslen(pszSuggestions) + 1, iSuggestionsLength); 201 pszSuggestions += i; 202 iSuggestionsLength -= i; 203 } 204 RegCloseKey(hSubKey); 205 } 206 } 207 } 208 209 210 LRESULT CALLBACK AddressBarProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 211 { 212 WNDPROC oldwndproc; 213 static WCHAR s_szNode[256]; 214 oldwndproc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); 215 216 switch (uMsg) 217 { 218 case WM_KEYUP: 219 if (wParam == VK_RETURN) 220 { 221 GetWindowTextW(hwnd, s_szNode, ARRAY_SIZE(s_szNode)); 222 SelectNode(g_pChildWnd->hTreeWnd, s_szNode); 223 } 224 break; 225 default: 226 break; 227 } 228 return CallWindowProcW(oldwndproc, hwnd, uMsg, wParam, lParam); 229 } 230 231 VOID 232 UpdateAddress(HTREEITEM hItem, HKEY hRootKey, LPCWSTR pszPath, BOOL bSelectNone) 233 { 234 LPCWSTR keyPath, rootName; 235 LPWSTR fullPath; 236 DWORD cbFullPath; 237 238 /* Wipe the listview, the status bar and the address bar if the root key was selected */ 239 if (TreeView_GetParent(g_pChildWnd->hTreeWnd, hItem) == NULL) 240 { 241 ListView_DeleteAllItems(g_pChildWnd->hListWnd); 242 SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)NULL); 243 SendMessageW(g_pChildWnd->hAddressBarWnd, WM_SETTEXT, 0, (LPARAM)NULL); 244 return; 245 } 246 247 if (pszPath == NULL) 248 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, hItem, &hRootKey); 249 else 250 keyPath = pszPath; 251 252 if (keyPath) 253 { 254 RefreshListView(g_pChildWnd->hListWnd, hRootKey, keyPath, bSelectNone); 255 rootName = get_root_key_name(hRootKey); 256 cbFullPath = (wcslen(rootName) + 1 + wcslen(keyPath) + 1) * sizeof(WCHAR); 257 fullPath = malloc(cbFullPath); 258 if (fullPath) 259 { 260 /* set (correct) the address bar text */ 261 if (keyPath[0] != L'\0') 262 swprintf(fullPath, L"%s%s%s", rootName, keyPath[0]==L'\\'?L"":L"\\", keyPath); 263 else 264 fullPath = wcscpy(fullPath, rootName); 265 266 SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)fullPath); 267 SendMessageW(g_pChildWnd->hAddressBarWnd, WM_SETTEXT, 0, (LPARAM)fullPath); 268 free(fullPath); 269 270 /* disable hive manipulation items temporarily (enable only if necessary) */ 271 EnableMenuItem(hMenuFrame, ID_REGISTRY_LOADHIVE, MF_BYCOMMAND | MF_GRAYED); 272 EnableMenuItem(hMenuFrame, ID_REGISTRY_UNLOADHIVE, MF_BYCOMMAND | MF_GRAYED); 273 /* compare the strings to see if we should enable/disable the "Load Hive" menus accordingly */ 274 if (_wcsicmp(rootName, L"HKEY_LOCAL_MACHINE") != 0 || 275 _wcsicmp(rootName, L"HKEY_USERS") != 0) 276 { 277 /* 278 * enable the unload menu item if at the root, otherwise 279 * enable the load menu item if there is no slash in 280 * keyPath (ie. immediate child selected) 281 */ 282 if (keyPath[0] == UNICODE_NULL) 283 EnableMenuItem(hMenuFrame, ID_REGISTRY_LOADHIVE, MF_BYCOMMAND | MF_ENABLED); 284 else if (!wcschr(keyPath, L'\\')) 285 EnableMenuItem(hMenuFrame, ID_REGISTRY_UNLOADHIVE, MF_BYCOMMAND | MF_ENABLED); 286 } 287 } 288 } 289 } 290 291 /******************************************************************************* 292 * 293 * FUNCTION: ChildWndProc(HWND, unsigned, WORD, LONG) 294 * 295 * PURPOSE: Processes messages for the child windows. 296 * 297 * WM_COMMAND - process the application menu 298 * WM_DESTROY - post a quit message and return 299 * 300 */ 301 LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 302 { 303 BOOL Result; 304 RECT rc; 305 306 switch (message) 307 { 308 case WM_CREATE: 309 { 310 WNDPROC oldproc; 311 HFONT hFont; 312 WCHAR buffer[MAX_PATH]; 313 DWORD style; 314 315 /* Load "My Computer" string */ 316 LoadStringW(hInst, IDS_MY_COMPUTER, buffer, ARRAY_SIZE(buffer)); 317 318 g_pChildWnd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ChildWnd)); 319 if (!g_pChildWnd) return 0; 320 321 wcsncpy(g_pChildWnd->szPath, buffer, MAX_PATH); 322 g_pChildWnd->nSplitPos = 190; 323 g_pChildWnd->hWnd = hWnd; 324 325 style = WS_CHILD | WS_VISIBLE | WS_TABSTOP; 326 g_pChildWnd->hAddressBarWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL, style, 327 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 328 hWnd, (HMENU)0, hInst, 0); 329 330 style = WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_ICON | BS_CENTER | 331 BS_VCENTER | BS_FLAT | BS_DEFPUSHBUTTON; 332 g_pChildWnd->hAddressBtnWnd = CreateWindowExW(0, L"Button", L"\x00BB", style, 333 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 334 hWnd, (HMENU)0, hInst, 0); 335 g_pChildWnd->hArrowIcon = (HICON)LoadImageW(hInst, MAKEINTRESOURCEW(IDI_ARROW), 336 IMAGE_ICON, 12, 12, 0); 337 SendMessageW(g_pChildWnd->hAddressBtnWnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_pChildWnd->hArrowIcon); 338 339 GetClientRect(hWnd, &rc); 340 g_pChildWnd->hTreeWnd = CreateTreeView(hWnd, g_pChildWnd->szPath, (HMENU) TREE_WINDOW); 341 g_pChildWnd->hListWnd = CreateListView(hWnd, (HMENU) LIST_WINDOW, rc.right - g_pChildWnd->nSplitPos); 342 SetFocus(g_pChildWnd->hTreeWnd); 343 344 /* set the address bar and button font */ 345 if ((g_pChildWnd->hAddressBarWnd) && (g_pChildWnd->hAddressBtnWnd)) 346 { 347 hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); 348 SendMessageW(g_pChildWnd->hAddressBarWnd, 349 WM_SETFONT, 350 (WPARAM)hFont, 351 0); 352 SendMessageW(g_pChildWnd->hAddressBtnWnd, 353 WM_SETFONT, 354 (WPARAM)hFont, 355 0); 356 } 357 /* Subclass the AddressBar */ 358 oldproc = (WNDPROC)GetWindowLongPtr(g_pChildWnd->hAddressBarWnd, GWLP_WNDPROC); 359 SetWindowLongPtr(g_pChildWnd->hAddressBarWnd, GWLP_USERDATA, (DWORD_PTR)oldproc); 360 SetWindowLongPtr(g_pChildWnd->hAddressBarWnd, GWLP_WNDPROC, (DWORD_PTR)AddressBarProc); 361 break; 362 } 363 case WM_COMMAND: 364 if(HIWORD(wParam) == BN_CLICKED) 365 { 366 PostMessageW(g_pChildWnd->hAddressBarWnd, WM_KEYUP, VK_RETURN, 0); 367 } 368 break; //goto def; 369 case WM_SETCURSOR: 370 if (LOWORD(lParam) == HTCLIENT) 371 { 372 POINT pt; 373 GetCursorPos(&pt); 374 ScreenToClient(hWnd, &pt); 375 if (pt.x>=g_pChildWnd->nSplitPos-SPLIT_WIDTH/2 && pt.x<g_pChildWnd->nSplitPos+SPLIT_WIDTH/2+1) 376 { 377 SetCursor(LoadCursorW(0, IDC_SIZEWE)); 378 return TRUE; 379 } 380 } 381 goto def; 382 case WM_DESTROY: 383 DestroyListView(g_pChildWnd->hListWnd); 384 DestroyTreeView(g_pChildWnd->hTreeWnd); 385 DestroyMainMenu(); 386 DestroyIcon(g_pChildWnd->hArrowIcon); 387 HeapFree(GetProcessHeap(), 0, g_pChildWnd); 388 g_pChildWnd = NULL; 389 PostQuitMessage(0); 390 break; 391 case WM_LBUTTONDOWN: 392 { 393 RECT rt; 394 int x = (short)LOWORD(lParam); 395 GetClientRect(hWnd, &rt); 396 if (x>=g_pChildWnd->nSplitPos-SPLIT_WIDTH/2 && x<g_pChildWnd->nSplitPos+SPLIT_WIDTH/2+1) 397 { 398 last_split = g_pChildWnd->nSplitPos; 399 draw_splitbar(hWnd, last_split); 400 SetCapture(hWnd); 401 } 402 break; 403 } 404 405 case WM_LBUTTONUP: 406 case WM_RBUTTONDOWN: 407 if (GetCapture() == hWnd) 408 { 409 finish_splitbar(hWnd, LOWORD(lParam)); 410 } 411 break; 412 413 case WM_CAPTURECHANGED: 414 if (GetCapture()==hWnd && last_split>=0) 415 draw_splitbar(hWnd, last_split); 416 break; 417 418 case WM_KEYDOWN: 419 if (wParam == VK_ESCAPE) 420 if (GetCapture() == hWnd) 421 { 422 RECT rt; 423 draw_splitbar(hWnd, last_split); 424 GetClientRect(hWnd, &rt); 425 ResizeWnd(rt.right, rt.bottom); 426 last_split = -1; 427 ReleaseCapture(); 428 SetCursor(LoadCursorW(0, IDC_ARROW)); 429 } 430 break; 431 432 case WM_MOUSEMOVE: 433 if (GetCapture() == hWnd) 434 { 435 HDC hdc; 436 RECT rt; 437 HGDIOBJ OldObj; 438 int x = LOWORD(lParam); 439 if(!SizingPattern) 440 { 441 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA}; 442 SizingPattern = CreateBitmap(8, 8, 1, 1, Pattern); 443 } 444 if(!SizingBrush) 445 { 446 SizingBrush = CreatePatternBrush(SizingPattern); 447 } 448 449 GetClientRect(hWnd, &rt); 450 x = (SHORT) min(max(x, SPLIT_MIN), rt.right - SPLIT_MIN); 451 if(last_split != x) 452 { 453 rt.left = last_split-SPLIT_WIDTH/2; 454 rt.right = last_split+SPLIT_WIDTH/2+1; 455 hdc = GetDC(hWnd); 456 OldObj = SelectObject(hdc, SizingBrush); 457 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT); 458 last_split = x; 459 rt.left = x-SPLIT_WIDTH/2; 460 rt.right = x+SPLIT_WIDTH/2+1; 461 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT); 462 SelectObject(hdc, OldObj); 463 ReleaseDC(hWnd, hdc); 464 } 465 } 466 break; 467 468 case WM_SETFOCUS: 469 if (g_pChildWnd != NULL) 470 { 471 SetFocus(g_pChildWnd->nFocusPanel? g_pChildWnd->hListWnd: g_pChildWnd->hTreeWnd); 472 } 473 break; 474 475 case WM_TIMER: 476 break; 477 478 case WM_NOTIFY: 479 if (g_pChildWnd == NULL) break; 480 481 if (((LPNMHDR)lParam)->idFrom == TREE_WINDOW) 482 { 483 if (!TreeWndNotifyProc(g_pChildWnd->hListWnd, wParam, lParam, &Result)) 484 { 485 goto def; 486 } 487 488 return Result; 489 } 490 else 491 { 492 if (((LPNMHDR)lParam)->idFrom == LIST_WINDOW) 493 { 494 if (!ListWndNotifyProc(g_pChildWnd->hListWnd, wParam, lParam, &Result)) 495 { 496 goto def; 497 } 498 499 return Result; 500 } 501 else 502 { 503 goto def; 504 } 505 } 506 break; 507 508 case WM_CONTEXTMENU: 509 { 510 POINT pt; 511 if((HWND)wParam == g_pChildWnd->hListWnd) 512 { 513 int i, cnt; 514 BOOL IsDefault; 515 pt.x = (short) LOWORD(lParam); 516 pt.y = (short) HIWORD(lParam); 517 cnt = ListView_GetSelectedCount(g_pChildWnd->hListWnd); 518 i = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_FOCUSED | LVNI_SELECTED); 519 if (pt.x == -1 && pt.y == -1) 520 { 521 RECT rc; 522 if (i != -1) 523 { 524 rc.left = LVIR_BOUNDS; 525 SendMessageW(g_pChildWnd->hListWnd, LVM_GETITEMRECT, i, (LPARAM) &rc); 526 pt.x = rc.left + 8; 527 pt.y = rc.top + 8; 528 } 529 else 530 pt.x = pt.y = 0; 531 ClientToScreen(g_pChildWnd->hListWnd, &pt); 532 } 533 if(i == -1) 534 { 535 TrackPopupMenu(GetSubMenu(hPopupMenus, PM_NEW), TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL); 536 } 537 else 538 { 539 HMENU mnu = GetSubMenu(hPopupMenus, PM_MODIFYVALUE); 540 SetMenuDefaultItem(mnu, ID_EDIT_MODIFY, MF_BYCOMMAND); 541 IsDefault = IsDefaultValue(g_pChildWnd->hListWnd, i); 542 if(cnt == 1) 543 EnableMenuItem(mnu, ID_EDIT_RENAME, MF_BYCOMMAND | (IsDefault ? MF_DISABLED | MF_GRAYED : MF_ENABLED)); 544 else 545 EnableMenuItem(mnu, ID_EDIT_RENAME, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); 546 EnableMenuItem(mnu, ID_EDIT_MODIFY, MF_BYCOMMAND | (cnt == 1 ? MF_ENABLED : MF_DISABLED | MF_GRAYED)); 547 EnableMenuItem(mnu, ID_EDIT_MODIFY_BIN, MF_BYCOMMAND | (cnt == 1 ? MF_ENABLED : MF_DISABLED | MF_GRAYED)); 548 549 TrackPopupMenu(mnu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL); 550 } 551 } 552 else if ((HWND)wParam == g_pChildWnd->hTreeWnd) 553 { 554 TVHITTESTINFO hti; 555 HMENU hContextMenu; 556 TVITEMW item; 557 MENUITEMINFOW mii; 558 WCHAR resource[256]; 559 WCHAR buffer[256]; 560 LPWSTR s; 561 LPCWSTR keyPath; 562 HKEY hRootKey; 563 int iLastPos; 564 WORD wID; 565 BOOL isRoot; 566 567 pt.x = (short) LOWORD(lParam); 568 pt.y = (short) HIWORD(lParam); 569 570 if (pt.x == -1 && pt.y == -1) 571 { 572 RECT rc; 573 hti.hItem = TreeView_GetSelection(g_pChildWnd->hTreeWnd); 574 if (hti.hItem != NULL) 575 { 576 TreeView_GetItemRect(g_pChildWnd->hTreeWnd, hti.hItem, &rc, TRUE); 577 pt.x = rc.left + 8; 578 pt.y = rc.top + 8; 579 ClientToScreen(g_pChildWnd->hTreeWnd, &pt); 580 hti.flags = TVHT_ONITEM; 581 } 582 else 583 hti.flags = 0; 584 } 585 else 586 { 587 hti.pt.x = pt.x; 588 hti.pt.y = pt.y; 589 ScreenToClient(g_pChildWnd->hTreeWnd, &hti.pt); 590 TreeView_HitTest(g_pChildWnd->hTreeWnd, &hti); 591 } 592 593 if (hti.flags & TVHT_ONITEM) 594 { 595 TreeView_SelectItem(g_pChildWnd->hTreeWnd, hti.hItem); 596 597 isRoot = (TreeView_GetParent(g_pChildWnd->hTreeWnd, hti.hItem) == NULL); 598 hContextMenu = GetSubMenu(hPopupMenus, isRoot ? PM_ROOTITEM : PM_TREECONTEXT); 599 600 memset(&item, 0, sizeof(item)); 601 item.mask = TVIF_STATE | TVIF_CHILDREN; 602 item.hItem = hti.hItem; 603 TreeView_GetItem(g_pChildWnd->hTreeWnd, &item); 604 605 /* Set the Expand/Collapse menu item appropriately */ 606 LoadStringW(hInst, (item.state & TVIS_EXPANDED) ? IDS_COLLAPSE : IDS_EXPAND, buffer, ARRAY_SIZE(buffer)); 607 memset(&mii, 0, sizeof(mii)); 608 mii.cbSize = sizeof(mii); 609 mii.fMask = MIIM_STRING | MIIM_STATE | MIIM_ID; 610 mii.fState = (item.cChildren > 0) ? MFS_DEFAULT : MFS_GRAYED; 611 mii.wID = (item.state & TVIS_EXPANDED) ? ID_TREE_COLLAPSEBRANCH : ID_TREE_EXPANDBRANCH; 612 mii.dwTypeData = (LPWSTR) buffer; 613 SetMenuItemInfo(hContextMenu, 0, TRUE, &mii); 614 615 if (isRoot == FALSE) 616 { 617 /* Remove any existing suggestions */ 618 memset(&mii, 0, sizeof(mii)); 619 mii.cbSize = sizeof(mii); 620 mii.fMask = MIIM_ID; 621 GetMenuItemInfo(hContextMenu, GetMenuItemCount(hContextMenu) - 1, TRUE, &mii); 622 if ((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX)) 623 { 624 do 625 { 626 iLastPos = GetMenuItemCount(hContextMenu) - 1; 627 GetMenuItemInfo(hContextMenu, iLastPos, TRUE, &mii); 628 RemoveMenu(hContextMenu, iLastPos, MF_BYPOSITION); 629 } 630 while((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX)); 631 } 632 633 /* Come up with suggestions */ 634 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, NULL, &hRootKey); 635 SuggestKeys(hRootKey, keyPath, Suggestions, ARRAY_SIZE(Suggestions)); 636 if (Suggestions[0]) 637 { 638 AppendMenu(hContextMenu, MF_SEPARATOR, 0, NULL); 639 640 LoadStringW(hInst, IDS_GOTO_SUGGESTED_KEY, resource, ARRAY_SIZE(resource)); 641 642 s = Suggestions; 643 wID = ID_TREE_SUGGESTION_MIN; 644 while(*s && (wID <= ID_TREE_SUGGESTION_MAX)) 645 { 646 _snwprintf(buffer, ARRAY_SIZE(buffer), resource, s); 647 648 memset(&mii, 0, sizeof(mii)); 649 mii.cbSize = sizeof(mii); 650 mii.fMask = MIIM_STRING | MIIM_ID; 651 mii.wID = wID++; 652 mii.dwTypeData = buffer; 653 InsertMenuItem(hContextMenu, GetMenuItemCount(hContextMenu), TRUE, &mii); 654 655 s += wcslen(s) + 1; 656 } 657 } 658 } 659 TrackPopupMenu(hContextMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL); 660 } 661 } 662 break; 663 } 664 665 case WM_SIZE: 666 if (wParam != SIZE_MINIMIZED && g_pChildWnd != NULL) 667 { 668 ResizeWnd(LOWORD(lParam), HIWORD(lParam)); 669 } 670 /* fall through */ 671 default: 672 def: 673 return DefWindowProcW(hWnd, message, wParam, lParam); 674 } 675 return 0; 676 } 677