b708b8dd9b2d6977a47ff9e21cfc2d9179a4ad2d
[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/devmgr/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 "stdafx.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_SEPERATOR -1
20 #define BTN_ENABLE_DRV 2
21 #define BTN_DISABLE_DRV 3
22 #define BTN_UPDATE_DRV 4
23 #define BTN_UNINSTALL_DRV 5
24
25
26 // menu hints
27 static const MENU_HINT MainMenuHintTable[] =
28 {
29 // File Menu
30 { IDC_EXIT, IDS_HINT_EXIT },
31
32 // Action Menu
33 { IDC_UPDATE_DRV, NULL },
34 { IDC_DISABLE_DRV, NULL },
35 { IDC_UNINSTALL_DRV, NULL },
36 { IDC_SCAN_HARDWARE, IDS_HINT_REFRESH },
37 { IDC_ADD_HARDWARE, NULL },
38 { IDC_PROPERTIES, IDS_HINT_PROP},
39
40 // View Menu
41 { IDC_DEVBYTYPE, IDS_HINT_DEV_BY_TYPE},
42 { IDC_DEVBYCONN, IDS_HINT_DEV_BY_CONN},
43 { IDC_RESBYTYPE, IDS_HINT_RES_BY_TYPE},
44 { IDC_RESBYCONN, IDS_HINT_RES_BY_TYPE},
45
46 { IDC_ABOUT, IDS_HINT_ABOUT }
47
48 };
49
50 // system menu hints
51 static const MENU_HINT SystemMenuHintTable[] =
52 {
53 {SC_RESTORE, IDS_HINT_SYS_RESTORE},
54 {SC_MOVE, IDS_HINT_SYS_MOVE},
55 {SC_SIZE, IDS_HINT_SYS_SIZE},
56 {SC_MINIMIZE, IDS_HINT_SYS_MINIMIZE},
57 {SC_MAXIMIZE, IDS_HINT_SYS_MAXIMIZE},
58 {SC_CLOSE, IDS_HINT_SYS_CLOSE},
59 };
60
61 static TBBUTTON TbButtons[] =
62 {
63 { BTN_PROPERTIES, IDC_PROPERTIES, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
64 { BTN_SCAN_HARDWARE, IDC_SCAN_HARDWARE, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
65 { 2, IDC_STATIC, TBSTATE_ENABLED, BTNS_SEP, 0, 0 },
66 { BTN_ENABLE_DRV, IDC_ENABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
67 { BTN_DISABLE_DRV, IDC_DISABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
68 { BTN_UPDATE_DRV, IDC_UPDATE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
69 { BTN_UNINSTALL_DRV, IDC_UNINSTALL_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 }
70 };
71
72
73 /* PUBLIC METHODS **********************************************/
74
75 CMainWindow::CMainWindow(void) :
76 m_ToolbarhImageList(NULL),
77 m_hMainWnd(NULL),
78 m_hStatusBar(NULL),
79 m_hToolBar(NULL),
80 m_CmdShow(0)
81 {
82 m_szMainWndClass = L"DevMgmtWndClass";
83 }
84
85 CMainWindow::~CMainWindow(void)
86 {
87 // Destroy any previous list
88 if (m_ToolbarhImageList) ImageList_Destroy(m_ToolbarhImageList);
89 }
90
91 bool
92 CMainWindow::Initialize(LPCTSTR lpCaption,
93 int nCmdShow)
94 {
95 CAtlStringW szCaption;
96 WNDCLASSEXW wc = {0};
97
98 // Store the show window value
99 m_CmdShow = nCmdShow;
100
101 // Setup the window class struct
102 wc.cbSize = sizeof(WNDCLASSEXW);
103 wc.lpfnWndProc = MainWndProc;
104 wc.hInstance = g_hInstance;
105 wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCEW(IDI_MAIN_ICON));
106 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
107 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
108 wc.lpszMenuName = MAKEINTRESOURCEW(IDR_MAINMENU);
109 wc.lpszClassName = m_szMainWndClass;
110 wc.hIconSm = (HICON)LoadImage(g_hInstance,
111 MAKEINTRESOURCE(IDI_MAIN_ICON),
112 IMAGE_ICON,
113 16,
114 16,
115 LR_SHARED);
116
117 // Register the window
118 if (RegisterClassExW(&wc))
119 {
120 // Create the main window and store the object pointer
121 m_hMainWnd = CreateWindowExW(WS_EX_WINDOWEDGE,
122 m_szMainWndClass,
123 lpCaption,
124 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
125 CW_USEDEFAULT,
126 CW_USEDEFAULT,
127 500,
128 500,
129 NULL,
130 NULL,
131 g_hInstance,
132 this);
133 }
134
135 // Return creation result
136 return !!(m_hMainWnd);
137 }
138
139 void
140 CMainWindow::Uninitialize()
141 {
142 // Unregister the window class
143 UnregisterClassW(m_szMainWndClass, g_hInstance);
144 }
145
146 int
147 CMainWindow::Run()
148 {
149 MSG Msg;
150
151 // Pump the message queue
152 while (GetMessageW(&Msg, NULL, 0, 0 ) != 0)
153 {
154 TranslateMessage(&Msg);
155 DispatchMessageW(&Msg);
156 }
157
158 return 0;
159 }
160
161
162 /* PRIVATE METHODS **********************************************/
163
164 bool
165 CMainWindow::MainWndMenuHint(WORD CmdId,
166 const MENU_HINT *HintArray,
167 DWORD HintsCount,
168 UINT DefHintId)
169 {
170 bool Found = false;
171 const MENU_HINT *LastHint;
172 UINT HintId = DefHintId;
173
174 LastHint = HintArray + HintsCount;
175 while (HintArray != LastHint)
176 {
177 if (HintArray->CmdId == CmdId)
178 {
179 HintId = HintArray->HintId;
180 Found = true;
181 break;
182 }
183 HintArray++;
184 }
185
186 StatusBarLoadString(m_hStatusBar,
187 SB_SIMPLEID,
188 g_hInstance,
189 HintId);
190
191 return Found;
192 }
193
194 bool
195 CMainWindow::RefreshView(ViewType Type)
196 {
197 UINT CheckId;
198 BOOL bSuccess;
199
200 // Refreshed the cached view
201 m_DeviceView->Refresh(Type, FALSE, TRUE);
202
203 // Get the menu item id
204 switch (Type)
205 {
206 case DevicesByType: CheckId = IDC_DEVBYTYPE; break;
207 case DevicesByConnection: CheckId = IDC_DEVBYCONN; break;
208 case ResourcesByType: CheckId = IDC_RESBYTYPE; break;
209 case ResourcesByConnection: CheckId = IDC_RESBYCONN; break;
210 default: ATLASSERT(FALSE); break;
211 }
212
213 // Set the new check item
214 bSuccess = CheckMenuRadioItem(m_hMenu,
215 IDC_DEVBYTYPE,
216 IDC_RESBYCONN,
217 CheckId,
218 MF_BYCOMMAND);
219
220 return TRUE;
221 }
222
223 bool
224 CMainWindow::ScanForHardwareChanges()
225 {
226 // Refresh the cache and and display
227 m_DeviceView->Refresh(m_DeviceView->GetCurrentView(),
228 true,
229 true);
230 return true;
231 }
232
233
234
235
236 bool
237 CMainWindow::CreateToolBar()
238 {
239 TBADDBITMAP TbAddBitmap;
240 INT Index;
241
242 DWORD dwStyles = WS_CHILDWINDOW | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
243 DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
244
245 // Create the toolbar window
246 m_hToolBar = CreateWindowExW(dwExStyles,
247 TOOLBARCLASSNAME,
248 NULL,
249 dwStyles,
250 0, 0, 0, 0,
251 m_hMainWnd,
252 (HMENU)IDC_TOOLBAR,
253 g_hInstance,
254 NULL);
255 if (m_hToolBar == NULL) return FALSE;
256
257 // Don't show clipped buttons
258 SendMessageW(m_hToolBar,
259 TB_SETEXTENDEDSTYLE,
260 0,
261 TBSTYLE_EX_HIDECLIPPEDBUTTONS);
262
263 SendMessageW(m_hToolBar, TB_SETBITMAPSIZE, 0, MAKELONG(16, 16));
264
265 // Set the struct size, the toobar needs this...
266 SendMessageW(m_hToolBar,
267 TB_BUTTONSTRUCTSIZE,
268 sizeof(TBBUTTON),
269 0);
270
271 TbAddBitmap.hInst = g_hInstance;
272 TbAddBitmap.nID = IDB_TOOLBAR;
273 Index = SendMessageW(m_hToolBar, TB_ADDBITMAP, _countof(TbButtons), (LPARAM)&TbAddBitmap);
274
275 SendMessageW(m_hToolBar, TB_ADDBUTTONSW, _countof(TbButtons), (LPARAM)TbButtons);
276 SendMessageW(m_hToolBar, TB_AUTOSIZE, 0, 0);
277
278 if (TRUE)
279 {
280 ShowWindow(m_hToolBar, SW_SHOW);
281 }
282
283 return TRUE;
284 }
285
286 bool
287 CMainWindow::CreateStatusBar()
288 {
289 int StatWidths[] = {110, -1}; // widths of status bar
290 bool bRet = FALSE;
291
292 // Create the status bar
293 m_hStatusBar = CreateWindowExW(0,
294 STATUSCLASSNAME,
295 NULL,
296 WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
297 0, 0, 0, 0,
298 m_hMainWnd,
299 (HMENU)IDC_STATUSBAR,
300 g_hInstance,
301 NULL);
302 if (m_hStatusBar)
303 {
304 // Set the width
305 bRet = (SendMessageW(m_hStatusBar,
306 SB_SETPARTS,
307 sizeof(StatWidths) / sizeof(int),
308 (LPARAM)StatWidths) != 0);
309 }
310
311 return bRet;
312 }
313
314 void CMainWindow::UpdateContext(_In_ LPTV_ITEMW TvItem)
315 {
316 WORD State;
317
318 // properties button
319 if (m_DeviceView->HasProperties(TvItem))
320 {
321 State = TBSTATE_ENABLED;
322 }
323 else
324 {
325 State = TBSTATE_HIDDEN;
326 }
327 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_PROPERTIES, MAKELPARAM(State, 0));
328 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_UPDATE_DRV, MAKELPARAM(State, 0)); //hack
329 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_UNINSTALL_DRV, MAKELPARAM(State, 0)); // hack
330
331 // enable driver button
332 if (m_DeviceView->IsDisabled(TvItem))
333 {
334 State = TBSTATE_ENABLED;
335 }
336 else
337 {
338 State = TBSTATE_HIDDEN;
339 }
340 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_ENABLE_DRV, MAKELPARAM(State, 0));
341
342 // disable driver button
343 if (m_DeviceView->CanDisable(TvItem) && !m_DeviceView->IsDisabled(TvItem))
344 {
345 State = TBSTATE_ENABLED;
346 }
347 else
348 {
349 State = TBSTATE_HIDDEN;
350 }
351 SendMessageW(m_hToolBar, TB_SETSTATE, IDC_DISABLE_DRV, MAKELPARAM(State, 0));
352
353
354
355
356
357 }
358
359
360
361 bool
362 CMainWindow::StatusBarLoadString(IN HWND hStatusBar,
363 IN INT PartId,
364 IN HINSTANCE hInstance,
365 IN UINT uID)
366 {
367 CAtlStringW szMessage;
368 bool bRet = false;
369
370 // Load the string
371 if (szMessage.LoadStringW(hInstance, uID))
372 {
373 // Show the string on the status bar
374 bRet = (SendMessageW(hStatusBar,
375 SB_SETTEXT,
376 (WPARAM)PartId,
377 (LPARAM)szMessage.GetBuffer()) != 0);
378 }
379
380 return bRet;
381 }
382
383 LRESULT
384 CMainWindow::OnCreate(HWND hwnd)
385 {
386 LRESULT RetCode;
387
388 RetCode = -1;
389 m_hMainWnd = hwnd;
390
391 // Store a handle to the main menu
392 m_hMenu = GetMenu(m_hMainWnd);
393
394 // Create the toolbar and statusbar
395 if (CreateToolBar() && CreateStatusBar())
396 {
397 // Create the device view object
398 m_DeviceView = new CDeviceView(m_hMainWnd);
399 if (m_DeviceView->Initialize())
400 {
401 // Do the initial scan
402 ScanForHardwareChanges();
403
404 // Display the window according to the user request
405 ShowWindow(hwnd, m_CmdShow);
406 RetCode = 0;
407 }
408 }
409
410 return RetCode;
411 }
412
413 LRESULT
414 CMainWindow::OnSize()
415 {
416 RECT rcClient, rcTool, rcStatus;
417 INT lvHeight, iToolHeight, iStatusHeight;
418
419 // Autosize the toolbar
420 SendMessage(m_hToolBar, TB_AUTOSIZE, 0, 0);
421
422 // Get the toolbar rect and save the height
423 GetWindowRect(m_hToolBar, &rcTool);
424 iToolHeight = rcTool.bottom - rcTool.top;
425
426 // Resize the status bar
427 SendMessage(m_hStatusBar, WM_SIZE, 0, 0);
428
429 // Get the statusbar rect and save the height
430 GetWindowRect(m_hStatusBar, &rcStatus);
431 iStatusHeight = rcStatus.bottom - rcStatus.top;
432
433 // Get the full client rect
434 GetClientRect(m_hMainWnd, &rcClient);
435
436 // Calculate the remaining height for the treeview
437 lvHeight = rcClient.bottom - iToolHeight - iStatusHeight;
438
439 // Resize the device view
440 m_DeviceView->Size(0,
441 iToolHeight,
442 rcClient.right,
443 lvHeight);
444
445 return 0;
446 }
447
448 LRESULT
449 CMainWindow::OnNotify(LPARAM lParam)
450 {
451 LPNMHDR NmHdr = (LPNMHDR)lParam;
452
453 switch (NmHdr->code)
454 {
455 case TVN_SELCHANGED:
456 {
457 LPNMTREEVIEW NmTreeView = (LPNMTREEVIEW)lParam;
458 UpdateContext(&NmTreeView->itemNew);
459 break;
460 }
461
462 case TVN_DELETEITEMW:
463 {
464 LPNMTREEVIEW NmTreeView = (LPNMTREEVIEW)lParam;
465 NmTreeView->action = NmTreeView->action;
466
467 break;
468 }
469
470 case NM_DBLCLK:
471 {
472 m_DeviceView->DisplayPropertySheet();
473 break;
474 }
475
476 case NM_RETURN:
477 {
478 m_DeviceView->DisplayPropertySheet();
479 break;
480 }
481 }
482
483 return 0;
484 }
485
486 LRESULT
487 CMainWindow::OnContext(LPARAM lParam)
488 {
489 return 0;
490 }
491
492 LRESULT
493 CMainWindow::OnCommand(WPARAM wParam,
494 LPARAM lParam)
495 {
496 LRESULT RetCode = 0;
497 WORD Msg;
498
499 // Get the message
500 Msg = LOWORD(wParam);
501
502 switch (Msg)
503 {
504 case IDC_PROPERTIES:
505 {
506 m_DeviceView->DisplayPropertySheet();
507 break;
508 }
509
510 case IDC_SCAN_HARDWARE:
511 {
512 ScanForHardwareChanges();
513 break;
514 }
515
516 case IDC_DEVBYTYPE:
517 {
518 RefreshView(DevicesByType);
519 break;
520 }
521
522 case IDC_DEVBYCONN:
523 {
524 RefreshView(DevicesByConnection);
525 break;
526 }
527
528 case IDC_SHOWHIDDEN:
529 {
530 UINT CurCheckState, NewCheckState;
531
532 // Get the current state
533 CurCheckState = GetMenuState(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND);
534
535 if (CurCheckState == MF_CHECKED)
536 {
537 // Inform the device view of the change
538 m_DeviceView->ShowHiddenDevices(false);
539 NewCheckState = MF_UNCHECKED;
540 }
541 else if (CurCheckState == MF_UNCHECKED)
542 {
543 m_DeviceView->ShowHiddenDevices(true);
544 NewCheckState = MF_CHECKED;
545 }
546 else
547 {
548 ATLASSERT(FALSE);
549 break;
550 }
551
552 // Set the new check state
553 CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | NewCheckState);
554
555 // Refresh the device view
556 m_DeviceView->Refresh(m_DeviceView->GetCurrentView(),
557 false,
558 true);
559 break;
560 }
561
562 case IDC_ABOUT:
563 {
564 // Apportion blame
565 MessageBoxW(m_hMainWnd,
566 L"ReactOS Device Manager\r\nCopyright Ged Murphy 2015",
567 L"About",
568 MB_OK | MB_APPLMODAL);
569
570 // Set focus back to the treeview
571 m_DeviceView->SetFocus();
572 break;
573 }
574
575 case IDC_EXIT:
576 {
577 // Post a close message to the window
578 PostMessageW(m_hMainWnd,
579 WM_CLOSE,
580 0,
581 0);
582 break;
583 }
584
585 default:
586 // We didn't handle it
587 RetCode = -1;
588 break;
589 }
590
591 return RetCode;
592 }
593
594 LRESULT
595 CMainWindow::OnDestroy()
596 {
597 // Uninitialize the device view
598 m_DeviceView->Uninitialize();
599
600 // Kill the object
601 delete m_DeviceView;
602 m_DeviceView = NULL;
603
604 // Clear the user data pointer
605 SetWindowLongPtr(m_hMainWnd, GWLP_USERDATA, 0);
606
607 // Break the message loop
608 PostQuitMessage(0);
609
610 return 0;
611 }
612
613 LRESULT CALLBACK
614 CMainWindow::MainWndProc(HWND hwnd,
615 UINT msg,
616 WPARAM wParam,
617 LPARAM lParam)
618 {
619 CMainWindow *pThis;
620 LRESULT RetCode = 0;
621
622 // Get the object pointer from window context
623 pThis = (CMainWindow *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
624 if (pThis == NULL)
625 {
626 // Check that this isn't a create message
627 if (msg != WM_CREATE)
628 {
629 // Don't handle null info pointer
630 goto HandleDefaultMessage;
631 }
632 }
633
634 switch(msg)
635 {
636 case WM_CREATE:
637 {
638 // Get the object pointer from the create param
639 pThis = (CMainWindow *)((LPCREATESTRUCT)lParam)->lpCreateParams;
640
641 // Store the pointer in the window's global user data
642 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
643
644 // Call the create handler
645 RetCode = pThis->OnCreate(hwnd);
646 break;
647 }
648
649 case WM_SIZE:
650 {
651 RetCode = pThis->OnSize();
652 break;
653 }
654
655 case WM_NOTIFY:
656 {
657 RetCode = pThis->OnNotify(lParam);
658 break;
659 }
660
661 case WM_CONTEXTMENU:
662 {
663 RetCode = pThis->OnContext(lParam);
664 break;
665 }
666
667 case WM_MENUSELECT:
668 {
669 if (pThis->m_hStatusBar != NULL)
670 {
671 if (!pThis->MainWndMenuHint(LOWORD(wParam),
672 MainMenuHintTable,
673 sizeof(MainMenuHintTable) / sizeof(MainMenuHintTable[0]),
674 IDS_HINT_BLANK))
675 {
676 pThis->MainWndMenuHint(LOWORD(wParam),
677 SystemMenuHintTable,
678 sizeof(SystemMenuHintTable) / sizeof(SystemMenuHintTable[0]),
679 IDS_HINT_BLANK);
680 }
681 }
682
683 break;
684 }
685
686 case WM_COMMAND:
687 {
688 // Handle the command message
689 RetCode = pThis->OnCommand(wParam, lParam);
690 if (RetCode == -1)
691 {
692 // Hand it off to the default message handler
693 goto HandleDefaultMessage;
694 }
695 }
696
697 case WM_CLOSE:
698 {
699 // Destroy the main window
700 DestroyWindow(hwnd);
701 }
702 break;
703
704 case WM_DESTROY:
705 {
706 // Call the destroy handler
707 RetCode = pThis->OnDestroy();
708 break;
709 }
710
711 default:
712 {
713 HandleDefaultMessage:
714 RetCode = DefWindowProc(hwnd, msg, wParam, lParam);
715 break;
716 }
717 }
718
719 return RetCode;
720 }
721
722
723 //////// MOVE ME ////////////////
724
725 HINSTANCE g_hInstance = NULL;
726 HANDLE ProcessHeap = NULL;
727
728 BOOL
729 WINAPI
730 DeviceManager_ExecuteW(HWND hWndParent,
731 HINSTANCE hInst,
732 LPCWSTR lpMachineName,
733 int nCmdShow)
734 {
735 CMainWindow MainWindow;
736 INITCOMMONCONTROLSEX icex;
737 CAtlStringW szAppName;
738 int Ret = 1;
739
740 // Store the global values
741 g_hInstance = hInst;
742 ProcessHeap = GetProcessHeap();
743
744 // Initialize common controls
745 icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
746 icex.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES;
747 InitCommonControlsEx(&icex);
748
749 // Load the application name
750 if (szAppName.LoadStringW(g_hInstance, IDS_APPNAME))
751 {
752 // Initialize the main window
753 if (MainWindow.Initialize(szAppName, nCmdShow))
754 {
755 // Run the application
756 Ret = MainWindow.Run();
757
758 // Uninitialize the main window
759 MainWindow.Uninitialize();
760 }
761 }
762
763 return Ret;
764 }