1 /* 2 * PROJECT: ReactOS Device Manager 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/win32/devmgr/devmgmt/MainWindow.cpp 5 * PURPOSE: Implements the main container window for the device view 6 * COPYRIGHT: Copyright 2014 - 2015 Ged Murphy <gedmurphy@reactos.org> 7 */ 8 9 10 #include "precomp.h" 11 #include "devmgmt.h" 12 #include "MainWindow.h" 13 14 15 /* DATA *****************************************************/ 16 17 #define BTN_PROPERTIES 0 18 #define BTN_SCAN_HARDWARE 1 19 #define BTN_ENABLE_DRV 2 20 #define BTN_DISABLE_DRV 3 21 #define BTN_UPDATE_DRV 4 22 #define BTN_UNINSTALL_DRV 5 23 24 #define REFRESH_TIMER 1 25 26 HINSTANCE g_hThisInstance = NULL; 27 HINSTANCE g_hParentInstance = NULL; 28 29 // menu hints 30 static const MENU_HINT MainMenuHintTable[] = 31 { 32 // File Menu 33 { IDC_EXIT, IDS_HINT_EXIT }, 34 35 // Action Menu 36 { IDC_PROPERTIES, IDS_HINT_PROPERTIES }, 37 { IDC_SCAN_HARDWARE, IDS_HINT_SCAN }, 38 { IDC_ENABLE_DRV, IDS_HINT_ENABLE }, 39 { IDC_DISABLE_DRV, IDS_HINT_DISABLE }, 40 { IDC_UPDATE_DRV, IDS_HINT_UPDATE }, 41 { IDC_UNINSTALL_DRV, IDS_HINT_UNINSTALL }, 42 { IDC_ADD_HARDWARE, IDS_HINT_ADD }, 43 44 45 // View Menu 46 { IDC_DEVBYTYPE, IDS_HINT_DEV_BY_TYPE}, 47 { IDC_DEVBYCONN, IDS_HINT_DEV_BY_CONN}, 48 { IDC_RESBYTYPE, IDS_HINT_RES_BY_TYPE}, 49 { IDC_RESBYCONN, IDS_HINT_RES_BY_TYPE}, 50 { IDC_SHOWHIDDEN, IDS_HINT_SHOW_HIDDEN }, 51 52 { IDC_ABOUT, IDS_HINT_ABOUT } 53 54 }; 55 56 57 // system menu hints 58 static const MENU_HINT SystemMenuHintTable[] = 59 { 60 {SC_RESTORE, IDS_HINT_SYS_RESTORE}, 61 {SC_MOVE, IDS_HINT_SYS_MOVE}, 62 {SC_SIZE, IDS_HINT_SYS_SIZE}, 63 {SC_MINIMIZE, IDS_HINT_SYS_MINIMIZE}, 64 {SC_MAXIMIZE, IDS_HINT_SYS_MAXIMIZE}, 65 {SC_CLOSE, IDS_HINT_SYS_CLOSE} 66 }; 67 68 static TBBUTTON TbButtons[] = 69 { 70 { BTN_PROPERTIES, IDC_PROPERTIES, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 }, 71 { BTN_SCAN_HARDWARE, IDC_SCAN_HARDWARE, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 }, 72 { 2, IDC_STATIC, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0 }, 73 { BTN_ENABLE_DRV, IDC_ENABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 }, 74 { BTN_DISABLE_DRV, IDC_DISABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 }, 75 { BTN_UPDATE_DRV, IDC_UPDATE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 }, 76 { BTN_UNINSTALL_DRV, IDC_UNINSTALL_DRV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 } 77 }; 78 79 80 /* PUBLIC METHODS **********************************************/ 81 82 CDeviceManager::CDeviceManager(void) : 83 m_hMainWnd(NULL), 84 m_hStatusBar(NULL), 85 m_hToolBar(NULL), 86 m_CmdShow(0), 87 m_RefreshPending(false) 88 { 89 m_szMainWndClass = L"DevMgmtWndClass"; 90 } 91 92 CDeviceManager::~CDeviceManager(void) 93 { 94 } 95 96 bool 97 CDeviceManager::Create(_In_ HWND /*hWndParent*/, 98 _In_ HINSTANCE hInst, 99 _In_opt_z_ LPCWSTR /*lpMachineName*/, 100 _In_ int nCmdShow) 101 { 102 CDeviceManager MainWindow; 103 INITCOMMONCONTROLSEX icex; 104 CAtlStringW szAppName; 105 int Ret = 1; 106 107 // Store the instances 108 g_hParentInstance = hInst; 109 g_hThisInstance = GetModuleHandleW(L"devmgr.dll"); 110 111 // Initialize common controls 112 icex.dwSize = sizeof(INITCOMMONCONTROLSEX); 113 icex.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES; 114 InitCommonControlsEx(&icex); 115 116 // Load the application name 117 if (szAppName.LoadStringW(g_hThisInstance, IDS_APPNAME)) 118 { 119 // Initialize the main window 120 if (MainWindow.Initialize(szAppName, nCmdShow)) 121 { 122 // Run the application 123 Ret = MainWindow.Run(); 124 125 // Uninitialize the main window 126 MainWindow.Uninitialize(); 127 } 128 } 129 130 return (Ret == 0); 131 } 132 133 134 /* PRIVATE METHODS **********************************************/ 135 136 bool 137 CDeviceManager::Initialize(_In_z_ LPCTSTR lpCaption, 138 _In_ int nCmdShow) 139 { 140 CAtlStringW szCaption; 141 WNDCLASSEXW wc = {0}; 142 143 // Store the show window value 144 m_CmdShow = nCmdShow; 145 146 // Setup the window class struct 147 wc.cbSize = sizeof(WNDCLASSEXW); 148 wc.lpfnWndProc = MainWndProc; 149 wc.hInstance = g_hThisInstance; 150 wc.hIcon = LoadIcon(g_hThisInstance, MAKEINTRESOURCEW(IDI_MAIN_ICON)); 151 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 152 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 153 wc.lpszMenuName = MAKEINTRESOURCEW(IDR_MAINMENU); 154 wc.lpszClassName = m_szMainWndClass; 155 wc.hIconSm = (HICON)LoadImage(g_hThisInstance, 156 MAKEINTRESOURCE(IDI_MAIN_ICON), 157 IMAGE_ICON, 158 GetSystemMetrics(SM_CXSMICON), 159 GetSystemMetrics(SM_CYSMICON), 160 0); 161 162 // Register the window 163 if (RegisterClassExW(&wc)) 164 { 165 // Create the main window and store the object pointer 166 m_hMainWnd = CreateWindowExW(WS_EX_WINDOWEDGE, 167 m_szMainWndClass, 168 lpCaption, 169 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 170 CW_USEDEFAULT, 171 CW_USEDEFAULT, 172 550, 173 500, 174 NULL, 175 NULL, 176 g_hThisInstance, 177 this); 178 } 179 180 // Return creation result 181 return !!(m_hMainWnd); 182 } 183 184 void 185 CDeviceManager::Uninitialize(void) 186 { 187 // Unregister the window class 188 UnregisterClassW(m_szMainWndClass, g_hThisInstance); 189 } 190 191 int 192 CDeviceManager::Run(void) 193 { 194 MSG Msg; 195 196 // Pump the message queue 197 while (GetMessageW(&Msg, NULL, 0, 0 ) != 0) 198 { 199 TranslateMessage(&Msg); 200 DispatchMessageW(&Msg); 201 } 202 203 return 0; 204 } 205 206 bool 207 CDeviceManager::MainWndMenuHint(_In_ WORD CmdId, 208 _In_ const MENU_HINT *HintArray, 209 _In_ DWORD HintsCount, 210 _In_ UINT DefHintId) 211 { 212 bool Found = false; 213 const MENU_HINT *LastHint; 214 UINT HintId = DefHintId; 215 216 LastHint = HintArray + HintsCount; 217 while (HintArray != LastHint) 218 { 219 if (HintArray->CmdId == CmdId) 220 { 221 HintId = HintArray->HintId; 222 Found = true; 223 break; 224 } 225 HintArray++; 226 } 227 228 StatusBarLoadString(m_hStatusBar, 229 SB_SIMPLEID, 230 g_hThisInstance, 231 HintId); 232 233 return Found; 234 } 235 236 void 237 CDeviceManager::UpdateStatusBar(_In_ bool InMenuLoop) 238 { 239 SendMessageW(m_hStatusBar, 240 SB_SIMPLE, 241 (WPARAM)InMenuLoop, 242 0); 243 } 244 245 bool 246 CDeviceManager::RefreshView(_In_ ViewType Type, 247 _In_ bool ScanForChanges) 248 { 249 UINT CheckId = 0; 250 251 // Refreshed the cached view 252 m_DeviceView->Refresh(Type, ScanForChanges, true); 253 254 // Get the menu item id 255 switch (Type) 256 { 257 case DevicesByType: 258 CheckId = IDC_DEVBYTYPE; 259 break; 260 261 case DevicesByConnection: 262 CheckId = IDC_DEVBYCONN; 263 break; 264 265 case ResourcesByType: 266 CheckId = IDC_RESBYTYPE; 267 break; 268 269 case ResourcesByConnection: 270 CheckId = IDC_RESBYCONN; 271 break; 272 273 default: 274 ATLASSERT(FALSE); 275 break; 276 } 277 278 // Set the new check item 279 CheckMenuRadioItem(m_hMenu, 280 IDC_DEVBYTYPE, 281 IDC_RESBYCONN, 282 CheckId, 283 MF_BYCOMMAND); 284 285 return true; 286 } 287 288 bool 289 CDeviceManager::CreateToolBar(void) 290 { 291 TBADDBITMAP TbAddBitmap; 292 293 DWORD dwStyles = WS_CHILDWINDOW | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER; 294 DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR; 295 296 // Create the toolbar window 297 m_hToolBar = CreateWindowExW(dwExStyles, 298 TOOLBARCLASSNAME, 299 NULL, 300 dwStyles, 301 0, 0, 0, 0, 302 m_hMainWnd, 303 (HMENU)IDC_TOOLBAR, 304 g_hThisInstance, 305 NULL); 306 if (m_hToolBar == NULL) 307 return FALSE; 308 309 // Don't show clipped buttons 310 SendMessageW(m_hToolBar, 311 TB_SETEXTENDEDSTYLE, 312 0, 313 TBSTYLE_EX_HIDECLIPPEDBUTTONS); 314 315 SendMessageW(m_hToolBar, TB_SETBITMAPSIZE, 0, MAKELONG(16, 16)); 316 317 // Set the struct size, the toobar needs this... 318 SendMessageW(m_hToolBar, 319 TB_BUTTONSTRUCTSIZE, 320 sizeof(TBBUTTON), 321 0); 322 323 TbAddBitmap.hInst = g_hThisInstance; 324 TbAddBitmap.nID = IDB_TOOLBAR; 325 SendMessageW(m_hToolBar, TB_ADDBITMAP, _countof(TbButtons), (LPARAM)&TbAddBitmap); 326 327 SendMessageW(m_hToolBar, TB_ADDBUTTONSW, _countof(TbButtons), (LPARAM)TbButtons); 328 SendMessageW(m_hToolBar, TB_AUTOSIZE, 0, 0); 329 330 if (TRUE) 331 { 332 ShowWindow(m_hToolBar, SW_SHOW); 333 } 334 335 return TRUE; 336 } 337 338 bool 339 CDeviceManager::CreateStatusBar(void) 340 { 341 int StatWidths[] = {110, -1}; // widths of status bar 342 bool bRet = FALSE; 343 344 // Create the status bar 345 m_hStatusBar = CreateWindowExW(0, 346 STATUSCLASSNAME, 347 NULL, 348 WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 349 0, 0, 0, 0, 350 m_hMainWnd, 351 (HMENU)IDC_STATUSBAR, 352 g_hThisInstance, 353 NULL); 354 if (m_hStatusBar) 355 { 356 // Set the width 357 bRet = (SendMessageW(m_hStatusBar, 358 SB_SETPARTS, 359 sizeof(StatWidths) / sizeof(int), 360 (LPARAM)StatWidths) != 0); 361 } 362 363 return bRet; 364 } 365 366 void CDeviceManager::UpdateToolbar() 367 { 368 WORD State; 369 370 CNode *Node = m_DeviceView->GetSelectedNode(); 371 372 // properties button 373 if (Node->HasProperties()) 374 { 375 State = TBSTATE_ENABLED; 376 } 377 else 378 { 379 State = TBSTATE_HIDDEN; 380 } 381 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_PROPERTIES, MAKELPARAM(State, 0)); 382 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_UPDATE_DRV, MAKELPARAM(State, 0)); //hack 383 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_UNINSTALL_DRV, MAKELPARAM(State, 0)); // hack 384 385 // enable driver button 386 if (Node->GetNodeType() == DeviceNode && 387 dynamic_cast<CDeviceNode *>(Node)->IsDisabled()) 388 { 389 State = TBSTATE_ENABLED; 390 } 391 else 392 { 393 State = TBSTATE_HIDDEN; 394 } 395 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_ENABLE_DRV, MAKELPARAM(State, 0)); 396 397 // disable driver button 398 if (Node->GetNodeType() == DeviceNode && 399 dynamic_cast<CDeviceNode *>(Node)->CanDisable() && 400 !dynamic_cast<CDeviceNode *>(Node)->IsDisabled()) 401 { 402 State = TBSTATE_ENABLED; 403 } 404 else 405 { 406 State = TBSTATE_HIDDEN; 407 } 408 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_DISABLE_DRV, MAKELPARAM(State, 0)); 409 } 410 411 bool 412 CDeviceManager::StatusBarLoadString(_In_ HWND hStatusBar, 413 _In_ INT PartId, 414 _In_ HINSTANCE hInstance, 415 _In_ UINT uID) 416 { 417 CAtlStringW szMessage; 418 bool bRet = false; 419 420 // Load the string 421 if (szMessage.LoadStringW(hInstance, uID)) 422 { 423 // Show the string on the status bar 424 bRet = (SendMessageW(hStatusBar, 425 SB_SETTEXT, 426 (WPARAM)PartId, 427 (LPARAM)szMessage.GetBuffer()) != 0); 428 } 429 430 return bRet; 431 } 432 433 LRESULT 434 CDeviceManager::OnCreate(_In_ HWND hwnd) 435 { 436 LRESULT RetCode; 437 438 RetCode = -1; 439 m_hMainWnd = hwnd; 440 441 // Store a handle to the main menu 442 m_hMenu = GetMenu(m_hMainWnd); 443 444 // Create the toolbar and statusbar 445 if (CreateToolBar() && CreateStatusBar()) 446 { 447 // Create the device view object 448 m_DeviceView = new CDeviceView(m_hMainWnd); 449 if (m_DeviceView->Initialize()) 450 { 451 // Do the initial scan 452 RefreshView(m_DeviceView->GetCurrentView(), true); 453 454 // Display the window according to the user request 455 ShowWindow(hwnd, m_CmdShow); 456 RetCode = 0; 457 } 458 } 459 460 return RetCode; 461 } 462 463 LRESULT 464 CDeviceManager::OnSize(void) 465 { 466 RECT rcClient, rcTool, rcStatus; 467 INT lvHeight, iToolHeight, iStatusHeight; 468 469 // Autosize the toolbar 470 SendMessage(m_hToolBar, TB_AUTOSIZE, 0, 0); 471 472 // Get the toolbar rect and save the height 473 GetWindowRect(m_hToolBar, &rcTool); 474 iToolHeight = rcTool.bottom - rcTool.top; 475 476 // Resize the status bar 477 SendMessage(m_hStatusBar, WM_SIZE, 0, 0); 478 479 // Get the statusbar rect and save the height 480 GetWindowRect(m_hStatusBar, &rcStatus); 481 iStatusHeight = rcStatus.bottom - rcStatus.top; 482 483 // Get the full client rect 484 GetClientRect(m_hMainWnd, &rcClient); 485 486 // Calculate the remaining height for the treeview 487 lvHeight = rcClient.bottom - iToolHeight - iStatusHeight; 488 489 // Resize the device view 490 m_DeviceView->OnSize(0, 491 iToolHeight, 492 rcClient.right, 493 lvHeight); 494 495 return 0; 496 } 497 498 LRESULT 499 CDeviceManager::OnNotify(_In_ LPARAM lParam) 500 { 501 LPNMHDR NmHdr = (LPNMHDR)lParam; 502 LRESULT Ret = 0; 503 504 switch (NmHdr->code) 505 { 506 case TVN_SELCHANGED: 507 { 508 UpdateToolbar(); 509 break; 510 } 511 512 case NM_DBLCLK: 513 { 514 m_DeviceView->DisplayPropertySheet(); 515 break; 516 } 517 518 case NM_RCLICK: 519 { 520 Ret = m_DeviceView->OnRightClick(NmHdr); 521 break; 522 } 523 524 case NM_RETURN: 525 { 526 m_DeviceView->DisplayPropertySheet(); 527 break; 528 } 529 530 case TTN_GETDISPINFO: 531 { 532 LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam; 533 lpttt->hinst = g_hThisInstance; 534 535 UINT_PTR idButton = lpttt->hdr.idFrom; 536 switch (idButton) 537 { 538 case IDC_PROPERTIES: 539 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_PROPERTIES); 540 break; 541 case IDC_SCAN_HARDWARE: 542 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_SCAN); 543 break; 544 case IDC_ENABLE_DRV: 545 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_ENABLE); 546 break; 547 case IDC_DISABLE_DRV: 548 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_DISABLE); 549 break; 550 case IDC_UPDATE_DRV: 551 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UPDATE); 552 break; 553 case IDC_UNINSTALL_DRV: 554 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UNINSTALL); 555 break; 556 } 557 break; 558 } 559 } 560 561 return Ret; 562 } 563 564 LRESULT 565 CDeviceManager::OnContext(_In_ LPARAM lParam) 566 { 567 return m_DeviceView->OnContextMenu(lParam); 568 } 569 570 LRESULT 571 CDeviceManager::OnCommand(_In_ WPARAM wParam, 572 _In_ LPARAM /*lParam*/) 573 { 574 LRESULT RetCode = 0; 575 WORD Msg; 576 577 // Get the message 578 Msg = LOWORD(wParam); 579 580 switch (Msg) 581 { 582 case IDC_PROPERTIES: 583 case IDC_SCAN_HARDWARE: 584 case IDC_ENABLE_DRV: 585 case IDC_DISABLE_DRV: 586 case IDC_UPDATE_DRV: 587 case IDC_UNINSTALL_DRV: 588 case IDC_ADD_HARDWARE: 589 { 590 m_DeviceView->OnAction(Msg); 591 break; 592 } 593 594 case IDC_ACTIONMENU: 595 { 596 // Create a popup menu with all the actions for the selected node 597 HMENU hMenu = CreatePopupMenu(); 598 m_DeviceView->CreateActionMenu(hMenu, true); 599 600 // Calculate where to put the menu 601 RECT rc; 602 GetMenuItemRect(m_hMainWnd, m_hMenu, 1, &rc); 603 LONG Height = rc.bottom - rc.top; 604 605 // Display the menu 606 TrackPopupMenuEx(hMenu, 607 TPM_RIGHTBUTTON, 608 rc.left, 609 rc.top + Height, 610 m_hMainWnd, 611 NULL); 612 613 DestroyMenu(hMenu); 614 break; 615 } 616 617 case IDC_DEVBYTYPE: 618 { 619 RefreshView(DevicesByType, false); 620 break; 621 } 622 623 case IDC_DEVBYCONN: 624 { 625 RefreshView(DevicesByConnection, false); 626 break; 627 } 628 629 case IDC_SHOWHIDDEN: 630 { 631 // Get the current state 632 UINT CurCheckState = GetMenuState(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND); 633 if (CurCheckState == MF_CHECKED) 634 { 635 m_DeviceView->SetHiddenDevices(false); 636 CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | MF_UNCHECKED); 637 } 638 else if (CurCheckState == MF_UNCHECKED) 639 { 640 m_DeviceView->SetHiddenDevices(true); 641 CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | MF_CHECKED); 642 } 643 // Refresh the device view 644 RefreshView(m_DeviceView->GetCurrentView(), false); 645 break; 646 } 647 648 case IDC_ABOUT: 649 { 650 // Apportion blame 651 MessageBoxW(m_hMainWnd, 652 L"ReactOS Device Manager\r\nCopyright Ged Murphy 2015", 653 L"About", 654 MB_OK | MB_APPLMODAL); 655 656 // Set focus back to the treeview 657 m_DeviceView->SetFocus(); 658 break; 659 } 660 661 case IDC_EXIT: 662 { 663 // Post a close message to the window 664 PostMessageW(m_hMainWnd, 665 WM_CLOSE, 666 0, 667 0); 668 break; 669 } 670 671 default: 672 // We didn't handle it 673 RetCode = -1; 674 break; 675 } 676 677 return RetCode; 678 } 679 680 void 681 CDeviceManager::OnActivate(void) 682 { 683 m_DeviceView->SetFocus(); 684 } 685 686 LRESULT 687 CDeviceManager::OnDestroy(void) 688 { 689 // Uninitialize the device view 690 m_DeviceView->Uninitialize(); 691 692 // Kill the object 693 delete m_DeviceView; 694 m_DeviceView = NULL; 695 696 // Clear the user data pointer 697 SetWindowLongPtr(m_hMainWnd, GWLP_USERDATA, 0); 698 699 // Break the message loop 700 PostQuitMessage(0); 701 702 return 0; 703 } 704 705 LRESULT CALLBACK 706 CDeviceManager::MainWndProc(_In_ HWND hwnd, 707 _In_ UINT msg, 708 _In_ WPARAM wParam, 709 _In_ LPARAM lParam) 710 { 711 CDeviceManager *This; 712 LRESULT RetCode = 0; 713 714 // Get the object pointer from window context 715 This = (CDeviceManager *)GetWindowLongPtr(hwnd, GWLP_USERDATA); 716 if (This == NULL) 717 { 718 // Check that this isn't a create message 719 if (msg != WM_CREATE) 720 { 721 // Don't handle null info pointer 722 goto HandleDefaultMessage; 723 } 724 } 725 726 switch(msg) 727 { 728 case WM_CREATE: 729 { 730 // Get the object pointer from the create param 731 This = (CDeviceManager *)((LPCREATESTRUCT)lParam)->lpCreateParams; 732 733 // Store the pointer in the window's global user data 734 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)This); 735 736 // Call the create handler 737 RetCode = This->OnCreate(hwnd); 738 break; 739 } 740 741 case WM_SIZE: 742 { 743 RetCode = This->OnSize(); 744 break; 745 } 746 747 case WM_NOTIFY: 748 { 749 RetCode = This->OnNotify(lParam); 750 break; 751 } 752 753 case WM_CONTEXTMENU: 754 { 755 RetCode = This->OnContext(lParam); 756 break; 757 } 758 759 case WM_MENUSELECT: 760 { 761 if (This->m_hStatusBar != NULL) 762 { 763 if (!This->MainWndMenuHint(LOWORD(wParam), 764 MainMenuHintTable, 765 sizeof(MainMenuHintTable) / sizeof(MainMenuHintTable[0]), 766 IDS_HINT_BLANK)) 767 { 768 This->MainWndMenuHint(LOWORD(wParam), 769 SystemMenuHintTable, 770 sizeof(SystemMenuHintTable) / sizeof(SystemMenuHintTable[0]), 771 IDS_HINT_BLANK); 772 } 773 } 774 775 break; 776 } 777 778 case WM_COMMAND: 779 { 780 // Handle the command message 781 RetCode = This->OnCommand(wParam, lParam); 782 if (RetCode == -1) 783 { 784 // Hand it off to the default message handler 785 goto HandleDefaultMessage; 786 } 787 break; 788 } 789 790 case WM_DEVICECHANGE: 791 { 792 if (wParam == DBT_DEVNODES_CHANGED) 793 { 794 // 795 // The OS can send multiple change messages in quick succession. To avoid 796 // refreshing multiple times (and to avoid waiting in the message thread) 797 // we set a timer to run in 500ms, which should leave enough time for all 798 // the messages to come through. Wrap so we don't set multiple timers 799 // 800 if (InterlockedCompareExchange((LONG *)&This->m_RefreshPending, TRUE, FALSE) == FALSE) 801 { 802 SetTimer(hwnd, REFRESH_TIMER, 500, NULL); 803 } 804 } 805 break; 806 } 807 808 case WM_TIMER: 809 { 810 if (wParam == REFRESH_TIMER) 811 { 812 // Schedule a refresh (this just creates a thread and returns) 813 This->RefreshView(This->m_DeviceView->GetCurrentView(), true); 814 815 // Cleanup the timer 816 KillTimer(hwnd, REFRESH_TIMER); 817 818 // Allow more change notifications 819 InterlockedExchange((LONG *)&This->m_RefreshPending, FALSE); 820 } 821 break; 822 } 823 824 case WM_ENTERMENULOOP: 825 { 826 This->UpdateStatusBar(true); 827 break; 828 } 829 830 case WM_EXITMENULOOP: 831 { 832 This->UpdateStatusBar(false); 833 break; 834 } 835 836 case WM_CLOSE: 837 { 838 // Destroy the main window 839 DestroyWindow(hwnd); 840 break; 841 } 842 843 case WM_ACTIVATE: 844 { 845 if (LOWORD(hwnd)) 846 This->OnActivate(); 847 break; 848 } 849 850 case WM_DESTROY: 851 { 852 // Call the destroy handler 853 RetCode = This->OnDestroy(); 854 break; 855 } 856 857 default: 858 { 859 HandleDefaultMessage: 860 RetCode = DefWindowProc(hwnd, msg, wParam, lParam); 861 break; 862 } 863 } 864 865 return RetCode; 866 } 867