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