[FORMATTING] Remove trailing whitespace. Addendum to 34593d93.
[reactos.git] / 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 /* 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 }