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