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