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