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