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_CONN },
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
CDeviceManager(void)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
~CDeviceManager(void)90 CDeviceManager::~CDeviceManager(void)
91 {
92 }
93
94 bool
Create(_In_ HWND,_In_ HINSTANCE hInst,_In_opt_z_ LPCWSTR,_In_ int nCmdShow)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
Initialize(_In_z_ LPCTSTR lpCaption,_In_ int nCmdShow)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
Uninitialize(void)183 CDeviceManager::Uninitialize(void)
184 {
185 // Unregister the window class
186 UnregisterClassW(m_szMainWndClass, g_hThisInstance);
187 }
188
189 int
Run(void)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
MainWndMenuHint(_In_ WORD CmdId,_In_ const MENU_HINT * HintArray,_In_ DWORD HintsCount,_In_ UINT DefHintId)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
UpdateStatusBar(_In_ bool InMenuLoop)235 CDeviceManager::UpdateStatusBar(_In_ bool InMenuLoop)
236 {
237 SendMessageW(m_hStatusBar,
238 SB_SIMPLE,
239 (WPARAM)InMenuLoop,
240 0);
241 }
242
243 bool
RefreshView(_In_ ViewType Type,_In_ bool ScanForChanges)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
CreateToolBar(void)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
CreateStatusBar(void)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
UpdateToolbar()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
StatusBarLoadString(_In_ HWND hStatusBar,_In_ INT PartId,_In_ HINSTANCE hInstance,_In_ UINT uID)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
OnCreate(_In_ HWND hwnd)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
OnSize(void)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
OnNotify(_In_ LPARAM lParam)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 Ret = m_DeviceView->OnDoubleClick(NmHdr);
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
OnContext(_In_ LPARAM lParam)569 CDeviceManager::OnContext(_In_ LPARAM lParam)
570 {
571 return m_DeviceView->OnContextMenu(lParam);
572 }
573
574 LRESULT
OnCommand(_In_ WPARAM wParam,_In_ LPARAM)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
657 if (!szAppName.LoadStringW(g_hThisInstance, IDS_APPNAME))
658 szAppName = L"ReactOS Device Manager";
659 if (!szAppAuthors.LoadStringW(g_hThisInstance, IDS_APP_AUTHORS))
660 szAppAuthors = L"";
661 ShellAboutW(m_hMainWnd, szAppName, szAppAuthors,
662 LoadIconW(g_hThisInstance, MAKEINTRESOURCEW(IDI_MAIN_ICON)));
663
664 // Set focus back to the treeview
665 m_DeviceView->SetFocus();
666 break;
667 }
668
669 case IDM_EXIT:
670 {
671 // Post a close message to the window
672 PostMessageW(m_hMainWnd,
673 WM_CLOSE,
674 0,
675 0);
676 break;
677 }
678
679 default:
680 // We didn't handle it
681 RetCode = -1;
682 break;
683 }
684
685 return RetCode;
686 }
687
688 void
OnActivate(void)689 CDeviceManager::OnActivate(void)
690 {
691 m_DeviceView->SetFocus();
692 }
693
694 LRESULT
OnDestroy(void)695 CDeviceManager::OnDestroy(void)
696 {
697 // Uninitialize the device view
698 m_DeviceView->Uninitialize();
699
700 // Kill the object
701 delete m_DeviceView;
702 m_DeviceView = NULL;
703
704 // Clear the user data pointer
705 SetWindowLongPtr(m_hMainWnd, GWLP_USERDATA, 0);
706
707 // Break the message loop
708 PostQuitMessage(0);
709
710 return 0;
711 }
712
713 LRESULT CALLBACK
MainWndProc(_In_ HWND hwnd,_In_ UINT msg,_In_ WPARAM wParam,_In_ LPARAM lParam)714 CDeviceManager::MainWndProc(_In_ HWND hwnd,
715 _In_ UINT msg,
716 _In_ WPARAM wParam,
717 _In_ LPARAM lParam)
718 {
719 CDeviceManager *This;
720 LRESULT RetCode = 0;
721
722 // Get the object pointer from window context
723 This = (CDeviceManager *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
724 if (This == NULL)
725 {
726 // Check that this isn't a create message
727 if (msg != WM_CREATE)
728 {
729 // Don't handle null info pointer
730 goto HandleDefaultMessage;
731 }
732 }
733
734 switch(msg)
735 {
736 case WM_CREATE:
737 {
738 // Get the object pointer from the create param
739 This = (CDeviceManager *)((LPCREATESTRUCT)lParam)->lpCreateParams;
740
741 // Store the pointer in the window's global user data
742 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)This);
743
744 // Call the create handler
745 RetCode = This->OnCreate(hwnd);
746 break;
747 }
748
749 case WM_SIZE:
750 {
751 RetCode = This->OnSize();
752 break;
753 }
754
755 case WM_NOTIFY:
756 {
757 RetCode = This->OnNotify(lParam);
758 break;
759 }
760
761 case WM_CONTEXTMENU:
762 {
763 RetCode = This->OnContext(lParam);
764 break;
765 }
766
767 case WM_MENUSELECT:
768 {
769 if (This->m_hStatusBar != NULL)
770 {
771 if (!This->MainWndMenuHint(LOWORD(wParam),
772 MainMenuHintTable,
773 sizeof(MainMenuHintTable) / sizeof(MainMenuHintTable[0]),
774 IDS_HINT_BLANK))
775 {
776 This->MainWndMenuHint(LOWORD(wParam),
777 SystemMenuHintTable,
778 sizeof(SystemMenuHintTable) / sizeof(SystemMenuHintTable[0]),
779 IDS_HINT_BLANK);
780 }
781 }
782
783 break;
784 }
785
786 case WM_COMMAND:
787 {
788 // Handle the command message
789 RetCode = This->OnCommand(wParam, lParam);
790 if (RetCode == -1)
791 {
792 // Hand it off to the default message handler
793 goto HandleDefaultMessage;
794 }
795 break;
796 }
797
798 case WM_DEVICECHANGE:
799 {
800 if (wParam == DBT_DEVNODES_CHANGED)
801 {
802 //
803 // The OS can send multiple change messages in quick succession. To avoid
804 // refreshing multiple times (and to avoid waiting in the message thread)
805 // we set a timer to run in 500ms, which should leave enough time for all
806 // the messages to come through. Wrap so we don't set multiple timers
807 //
808 if (InterlockedCompareExchange((LONG *)&This->m_RefreshPending, TRUE, FALSE) == FALSE)
809 {
810 SetTimer(hwnd, REFRESH_TIMER, 500, NULL);
811 }
812 }
813 break;
814 }
815
816 case WM_TIMER:
817 {
818 if (wParam == REFRESH_TIMER)
819 {
820 // Schedule a refresh (this just creates a thread and returns)
821 This->RefreshView(This->m_DeviceView->GetCurrentView(), true);
822
823 // Cleanup the timer
824 KillTimer(hwnd, REFRESH_TIMER);
825
826 // Allow more change notifications
827 InterlockedExchange((LONG *)&This->m_RefreshPending, FALSE);
828 }
829 break;
830 }
831
832 case WM_ENTERMENULOOP:
833 {
834 This->UpdateStatusBar(true);
835 break;
836 }
837
838 case WM_EXITMENULOOP:
839 {
840 This->UpdateStatusBar(false);
841 break;
842 }
843
844 case WM_CLOSE:
845 {
846 // Destroy the main window
847 DestroyWindow(hwnd);
848 break;
849 }
850
851 case WM_ACTIVATE:
852 {
853 if (LOWORD(hwnd))
854 This->OnActivate();
855 break;
856 }
857
858 case WM_DESTROY:
859 {
860 // Call the destroy handler
861 RetCode = This->OnDestroy();
862 break;
863 }
864
865 default:
866 {
867 HandleDefaultMessage:
868 RetCode = DefWindowProc(hwnd, msg, wParam, lParam);
869 break;
870 }
871 }
872
873 return RetCode;
874 }
875