The c++ bool is 1 byte, not 4. Thanks Thomas
[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 {
250 UINT CheckId = 0;
251
252 // Refreshed the cached view
253 m_DeviceView->Refresh(Type, FALSE, TRUE, NULL);
254
255 // Get the menu item id
256 switch (Type)
257 {
258 case DevicesByType: CheckId = IDC_DEVBYTYPE; break;
259 case DevicesByConnection: CheckId = IDC_DEVBYCONN; break;
260 case ResourcesByType: CheckId = IDC_RESBYTYPE; break;
261 case ResourcesByConnection: CheckId = IDC_RESBYCONN; break;
262 default: ATLASSERT(FALSE); break;
263 }
264
265 // Set the new check item
266 CheckMenuRadioItem(m_hMenu,
267 IDC_DEVBYTYPE,
268 IDC_RESBYCONN,
269 CheckId,
270 MF_BYCOMMAND);
271
272 return true;
273 }
274
275 bool
276 CDeviceManager::CreateToolBar(void)
277 {
278 TBADDBITMAP TbAddBitmap;
279
280 DWORD dwStyles = WS_CHILDWINDOW | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
281 DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
282
283 // Create the toolbar window
284 m_hToolBar = CreateWindowExW(dwExStyles,
285 TOOLBARCLASSNAME,
286 NULL,
287 dwStyles,
288 0, 0, 0, 0,
289 m_hMainWnd,
290 (HMENU)IDC_TOOLBAR,
291 g_hThisInstance,
292 NULL);
293 if (m_hToolBar == NULL) return FALSE;
294
295 // Don't show clipped buttons
296 SendMessageW(m_hToolBar,
297 TB_SETEXTENDEDSTYLE,
298 0,
299 TBSTYLE_EX_HIDECLIPPEDBUTTONS);
300
301 SendMessageW(m_hToolBar, TB_SETBITMAPSIZE, 0, MAKELONG(16, 16));
302
303 // Set the struct size, the toobar needs this...
304 SendMessageW(m_hToolBar,
305 TB_BUTTONSTRUCTSIZE,
306 sizeof(TBBUTTON),
307 0);
308
309 TbAddBitmap.hInst = g_hThisInstance;
310 TbAddBitmap.nID = IDB_TOOLBAR;
311 SendMessageW(m_hToolBar, TB_ADDBITMAP, _countof(TbButtons), (LPARAM)&TbAddBitmap);
312
313 SendMessageW(m_hToolBar, TB_ADDBUTTONSW, _countof(TbButtons), (LPARAM)TbButtons);
314 SendMessageW(m_hToolBar, TB_AUTOSIZE, 0, 0);
315
316 if (TRUE)
317 {
318 ShowWindow(m_hToolBar, SW_SHOW);
319 }
320
321 return TRUE;
322 }
323
324 bool
325 CDeviceManager::CreateStatusBar(void)
326 {
327 int StatWidths[] = {110, -1}; // widths of status bar
328 bool bRet = FALSE;
329
330 // Create the status bar
331 m_hStatusBar = CreateWindowExW(0,
332 STATUSCLASSNAME,
333 NULL,
334 WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
335 0, 0, 0, 0,
336 m_hMainWnd,
337 (HMENU)IDC_STATUSBAR,
338 g_hThisInstance,
339 NULL);
340 if (m_hStatusBar)
341 {
342 // Set the width
343 bRet = (SendMessageW(m_hStatusBar,
344 SB_SETPARTS,
345 sizeof(StatWidths) / sizeof(int),
346 (LPARAM)StatWidths) != 0);
347 }
348
349 return bRet;
350 }
351
352 void CDeviceManager::UpdateToolbar()
353 {
354 WORD State;
355
356 CNode *Node = m_DeviceView->GetSelectedNode();
357
358 // properties button
359 if (Node->HasProperties())
360 {
361 State = TBSTATE_ENABLED;
362 }
363 else
364 {
365 State = TBSTATE_HIDDEN;
366 }
367 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_PROPERTIES, MAKELPARAM(State, 0));
368 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_UPDATE_DRV, MAKELPARAM(State, 0)); //hack
369 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_UNINSTALL_DRV, MAKELPARAM(State, 0)); // hack
370
371 // enable driver button
372 if (Node->GetNodeType() == DeviceNode &&
373 dynamic_cast<CDeviceNode *>(Node)->IsDisabled())
374 {
375 State = TBSTATE_ENABLED;
376 }
377 else
378 {
379 State = TBSTATE_HIDDEN;
380 }
381 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_ENABLE_DRV, MAKELPARAM(State, 0));
382
383 // disable driver button
384 if (Node->GetNodeType() == DeviceNode &&
385 dynamic_cast<CDeviceNode *>(Node)->CanDisable() &&
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, IDC_DISABLE_DRV, MAKELPARAM(State, 0));
395 }
396
397
398
399 bool
400 CDeviceManager::StatusBarLoadString(_In_ HWND hStatusBar,
401 _In_ INT PartId,
402 _In_ HINSTANCE hInstance,
403 _In_ UINT uID)
404 {
405 CAtlStringW szMessage;
406 bool bRet = false;
407
408 // Load the string
409 if (szMessage.LoadStringW(hInstance, uID))
410 {
411 // Show the string on the status bar
412 bRet = (SendMessageW(hStatusBar,
413 SB_SETTEXT,
414 (WPARAM)PartId,
415 (LPARAM)szMessage.GetBuffer()) != 0);
416 }
417
418 return bRet;
419 }
420
421 LRESULT
422 CDeviceManager::OnCreate(_In_ HWND hwnd)
423 {
424 LRESULT RetCode;
425
426 RetCode = -1;
427 m_hMainWnd = hwnd;
428
429 // Store a handle to the main menu
430 m_hMenu = GetMenu(m_hMainWnd);
431
432 // Create the toolbar and statusbar
433 if (CreateToolBar() && CreateStatusBar())
434 {
435 // Create the device view object
436 m_DeviceView = new CDeviceView(m_hMainWnd);
437 if (m_DeviceView->Initialize())
438 {
439 // Do the initial scan
440 m_DeviceView->Refresh(m_DeviceView->GetCurrentView(),
441 true,
442 true,
443 NULL);
444
445 // Display the window according to the user request
446 ShowWindow(hwnd, m_CmdShow);
447 RetCode = 0;
448 }
449 }
450
451 return RetCode;
452 }
453
454 LRESULT
455 CDeviceManager::OnSize(void)
456 {
457 RECT rcClient, rcTool, rcStatus;
458 INT lvHeight, iToolHeight, iStatusHeight;
459
460 // Autosize the toolbar
461 SendMessage(m_hToolBar, TB_AUTOSIZE, 0, 0);
462
463 // Get the toolbar rect and save the height
464 GetWindowRect(m_hToolBar, &rcTool);
465 iToolHeight = rcTool.bottom - rcTool.top;
466
467 // Resize the status bar
468 SendMessage(m_hStatusBar, WM_SIZE, 0, 0);
469
470 // Get the statusbar rect and save the height
471 GetWindowRect(m_hStatusBar, &rcStatus);
472 iStatusHeight = rcStatus.bottom - rcStatus.top;
473
474 // Get the full client rect
475 GetClientRect(m_hMainWnd, &rcClient);
476
477 // Calculate the remaining height for the treeview
478 lvHeight = rcClient.bottom - iToolHeight - iStatusHeight;
479
480 // Resize the device view
481 m_DeviceView->OnSize(0,
482 iToolHeight,
483 rcClient.right,
484 lvHeight);
485
486 return 0;
487 }
488
489 LRESULT
490 CDeviceManager::OnNotify(_In_ LPARAM lParam)
491 {
492 LPNMHDR NmHdr = (LPNMHDR)lParam;
493 LRESULT Ret = 0;
494
495 switch (NmHdr->code)
496 {
497 case TVN_SELCHANGED:
498 {
499 UpdateToolbar();
500 break;
501 }
502
503 case NM_DBLCLK:
504 {
505 m_DeviceView->DisplayPropertySheet();
506 break;
507 }
508
509 case NM_RCLICK:
510 {
511 Ret = m_DeviceView->OnRightClick(NmHdr);
512 break;
513 }
514
515 case NM_RETURN:
516 {
517 m_DeviceView->DisplayPropertySheet();
518 break;
519 }
520
521 case TTN_GETDISPINFO:
522 {
523 LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam;
524 lpttt->hinst = g_hThisInstance;
525
526 UINT_PTR idButton = lpttt->hdr.idFrom;
527 switch (idButton)
528 {
529 case IDC_PROPERTIES:
530 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_PROPERTIES);
531 break;
532 case IDC_SCAN_HARDWARE:
533 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_SCAN);
534 break;
535 case IDC_ENABLE_DRV:
536 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_ENABLE);
537 break;
538 case IDC_DISABLE_DRV:
539 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_DISABLE);
540 break;
541 case IDC_UPDATE_DRV:
542 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UPDATE);
543 break;
544 case IDC_UNINSTALL_DRV:
545 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UNINSTALL);
546 break;
547 }
548 idButton = idButton;
549 break;
550 }
551 }
552
553 return Ret;
554 }
555
556 LRESULT
557 CDeviceManager::OnContext(_In_ LPARAM lParam)
558 {
559 return m_DeviceView->OnContextMenu(lParam);
560 }
561
562 LRESULT
563 CDeviceManager::OnCommand(_In_ WPARAM wParam,
564 _In_ LPARAM /*lParam*/)
565 {
566 LRESULT RetCode = 0;
567 WORD Msg;
568
569 // Get the message
570 Msg = LOWORD(wParam);
571
572 switch (Msg)
573 {
574 case IDC_PROPERTIES:
575 case IDC_SCAN_HARDWARE:
576 case IDC_ENABLE_DRV:
577 case IDC_DISABLE_DRV:
578 case IDC_UPDATE_DRV:
579 case IDC_UNINSTALL_DRV:
580 case IDC_ADD_HARDWARE:
581 {
582 m_DeviceView->OnAction(Msg);
583 break;
584 }
585
586 case IDC_ACTIONMENU:
587 {
588 // Create a popup menu with all the actions for the selected node
589 HMENU hMenu = CreatePopupMenu();
590 m_DeviceView->CreateActionMenu(hMenu, true);
591
592 // Calculate where to put the menu
593 RECT rc;
594 GetMenuItemRect(m_hMainWnd, m_hMenu, 1, &rc);
595 LONG Height = rc.bottom - rc.top;
596
597 // Display the menu
598 TrackPopupMenuEx(hMenu,
599 TPM_RIGHTBUTTON,
600 rc.left,
601 rc.top + Height,
602 m_hMainWnd,
603 NULL);
604
605 DestroyMenu(hMenu);
606 break;
607 }
608
609 case IDC_DEVBYTYPE:
610 {
611 RefreshView(DevicesByType);
612 break;
613 }
614
615 case IDC_DEVBYCONN:
616 {
617 RefreshView(DevicesByConnection);
618 break;
619 }
620
621 case IDC_SHOWHIDDEN:
622 {
623 // Get the current state
624 UINT CurCheckState = GetMenuState(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND);
625 if (CurCheckState == MF_CHECKED)
626 {
627 m_DeviceView->SetHiddenDevices(false);
628 CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | MF_UNCHECKED);
629 }
630 else if (CurCheckState == MF_UNCHECKED)
631 {
632 m_DeviceView->SetHiddenDevices(true);
633 CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | MF_CHECKED);
634 }
635 // Refresh the device view
636 m_DeviceView->Refresh(m_DeviceView->GetCurrentView(),
637 false,
638 true,
639 NULL);
640 break;
641 }
642
643 case IDC_ABOUT:
644 {
645 // Apportion blame
646 MessageBoxW(m_hMainWnd,
647 L"ReactOS Device Manager\r\nCopyright Ged Murphy 2015",
648 L"About",
649 MB_OK | MB_APPLMODAL);
650
651 // Set focus back to the treeview
652 m_DeviceView->SetFocus();
653 break;
654 }
655
656 case IDC_EXIT:
657 {
658 // Post a close message to the window
659 PostMessageW(m_hMainWnd,
660 WM_CLOSE,
661 0,
662 0);
663 break;
664 }
665
666 default:
667 // We didn't handle it
668 RetCode = -1;
669 break;
670 }
671
672 return RetCode;
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 sucsession. 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->m_DeviceView->Refresh(This->m_DeviceView->GetCurrentView(),
802 true,
803 true,
804 NULL);
805
806 // Cleanup the timer
807 KillTimer(hwnd, REFRESH_TIMER);
808
809 // Allow more change notifications
810 InterlockedExchange((LONG *)&This->m_RefreshPending, FALSE);
811 }
812 break;
813 }
814
815 case WM_ENTERMENULOOP:
816 {
817 This->UpdateStatusBar(true);
818 break;
819 }
820
821 case WM_EXITMENULOOP:
822 {
823 This->UpdateStatusBar(false);
824 break;
825 }
826
827 case WM_CLOSE:
828 {
829 // Destroy the main window
830 DestroyWindow(hwnd);
831 break;
832 }
833
834
835 case WM_DESTROY:
836 {
837 // Call the destroy handler
838 RetCode = This->OnDestroy();
839 break;
840 }
841
842 default:
843 {
844 HandleDefaultMessage:
845 RetCode = DefWindowProc(hwnd, msg, wParam, lParam);
846 break;
847 }
848 }
849
850 return RetCode;
851 }