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