/*
* PROJECT: ReactOS Device Manager
* LICENSE: GPL - See COPYING in the top level directory
- * FILE: dll/win32/devmgr/devmgr/MainWindow.cpp
+ * FILE: dll/win32/devmgr/devmgmt/MainWindow.cpp
* PURPOSE: Implements the main container window for the device view
* COPYRIGHT: Copyright 2014 - 2015 Ged Murphy <gedmurphy@reactos.org>
*/
-#include "stdafx.h"
+#include "precomp.h"
#include "devmgmt.h"
#include "MainWindow.h"
#define BTN_UPDATE_DRV 4
#define BTN_UNINSTALL_DRV 5
+#define REFRESH_TIMER 1
+
+HINSTANCE g_hThisInstance = NULL;
+HINSTANCE g_hParentInstance = NULL;
// menu hints
static const MENU_HINT MainMenuHintTable[] =
};
-
-
-#define IDS_HINT_BLANK 20000
-#define IDS_HINT_PROPERTIES 20001
-#define IDS_HINT_SCAN 20002
-#define IDS_HINT_ENABLE 20003
-#define IDS_HINT_DISABLE 20004
-#define IDS_HINT_UPDATE 20005
-#define IDS_HINT_UNINSTALL 20006
-#define IDS_HINT_ADD 20007
-#define IDS_HINT_ABOUT 20008
-#define IDS_HINT_EXIT 20009
-
// system menu hints
static const MENU_HINT SystemMenuHintTable[] =
{
{SC_SIZE, IDS_HINT_SYS_SIZE},
{SC_MINIMIZE, IDS_HINT_SYS_MINIMIZE},
{SC_MAXIMIZE, IDS_HINT_SYS_MAXIMIZE},
- {SC_CLOSE, IDS_HINT_SYS_CLOSE},
+ {SC_CLOSE, IDS_HINT_SYS_CLOSE}
};
static TBBUTTON TbButtons[] =
{
- { BTN_PROPERTIES, IDC_PROPERTIES, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
- { BTN_SCAN_HARDWARE, IDC_SCAN_HARDWARE, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
- { 2, IDC_STATIC, TBSTATE_ENABLED, BTNS_SEP, 0, 0 },
- { BTN_ENABLE_DRV, IDC_ENABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
- { BTN_DISABLE_DRV, IDC_DISABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
- { BTN_UPDATE_DRV, IDC_UPDATE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
- { BTN_UNINSTALL_DRV, IDC_UNINSTALL_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 }
+ { BTN_PROPERTIES, IDC_PROPERTIES, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 },
+ { BTN_SCAN_HARDWARE, IDC_SCAN_HARDWARE, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 },
+ { 2, IDC_STATIC, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0 },
+ { BTN_ENABLE_DRV, IDC_ENABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 },
+ { BTN_DISABLE_DRV, IDC_DISABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 },
+ { BTN_UPDATE_DRV, IDC_UPDATE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 },
+ { BTN_UNINSTALL_DRV, IDC_UNINSTALL_DRV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 }
};
/* PUBLIC METHODS **********************************************/
-CMainWindow::CMainWindow(void) :
- m_ToolbarhImageList(NULL),
+CDeviceManager::CDeviceManager(void) :
m_hMainWnd(NULL),
m_hStatusBar(NULL),
m_hToolBar(NULL),
- m_CmdShow(0)
+ m_CmdShow(0),
+ m_RefreshPending(false)
{
m_szMainWndClass = L"DevMgmtWndClass";
}
-CMainWindow::~CMainWindow(void)
+CDeviceManager::~CDeviceManager(void)
{
- // Destroy any previous list
- if (m_ToolbarhImageList) ImageList_Destroy(m_ToolbarhImageList);
}
bool
-CMainWindow::Initialize(LPCTSTR lpCaption,
- int nCmdShow)
+CDeviceManager::Create(_In_ HWND /*hWndParent*/,
+ _In_ HINSTANCE hInst,
+ _In_opt_z_ LPCWSTR /*lpMachineName*/,
+ _In_ int nCmdShow)
+{
+ CDeviceManager MainWindow;
+ INITCOMMONCONTROLSEX icex;
+ CAtlStringW szAppName;
+ int Ret = 1;
+
+ // Store the instances
+ g_hParentInstance = hInst;
+ g_hThisInstance = GetModuleHandleW(L"devmgr.dll");
+
+ // Initialize common controls
+ icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ icex.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES;
+ InitCommonControlsEx(&icex);
+
+ // Load the application name
+ if (szAppName.LoadStringW(g_hThisInstance, IDS_APPNAME))
+ {
+ // Initialize the main window
+ if (MainWindow.Initialize(szAppName, nCmdShow))
+ {
+ // Run the application
+ Ret = MainWindow.Run();
+
+ // Uninitialize the main window
+ MainWindow.Uninitialize();
+ }
+ }
+
+ return (Ret == 0);
+}
+
+
+/* PRIVATE METHODS **********************************************/
+
+bool
+CDeviceManager::Initialize(_In_z_ LPCTSTR lpCaption,
+ _In_ int nCmdShow)
{
CAtlStringW szCaption;
WNDCLASSEXW wc = {0};
// Setup the window class struct
wc.cbSize = sizeof(WNDCLASSEXW);
wc.lpfnWndProc = MainWndProc;
- wc.hInstance = g_hInstance;
- wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCEW(IDI_MAIN_ICON));
+ wc.hInstance = g_hThisInstance;
+ wc.hIcon = LoadIcon(g_hThisInstance, MAKEINTRESOURCEW(IDI_MAIN_ICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName = MAKEINTRESOURCEW(IDR_MAINMENU);
wc.lpszClassName = m_szMainWndClass;
- wc.hIconSm = (HICON)LoadImage(g_hInstance,
+ wc.hIconSm = (HICON)LoadImage(g_hThisInstance,
MAKEINTRESOURCE(IDI_MAIN_ICON),
IMAGE_ICON,
16,
500,
NULL,
NULL,
- g_hInstance,
+ g_hThisInstance,
this);
}
}
void
-CMainWindow::Uninitialize()
+CDeviceManager::Uninitialize(void)
{
// Unregister the window class
- UnregisterClassW(m_szMainWndClass, g_hInstance);
+ UnregisterClassW(m_szMainWndClass, g_hThisInstance);
}
int
-CMainWindow::Run()
+CDeviceManager::Run(void)
{
MSG Msg;
return 0;
}
-
-/* PRIVATE METHODS **********************************************/
-
bool
-CMainWindow::MainWndMenuHint(WORD CmdId,
- const MENU_HINT *HintArray,
- DWORD HintsCount,
- UINT DefHintId)
+CDeviceManager::MainWndMenuHint(_In_ WORD CmdId,
+ _In_ const MENU_HINT *HintArray,
+ _In_ DWORD HintsCount,
+ _In_ UINT DefHintId)
{
bool Found = false;
const MENU_HINT *LastHint;
StatusBarLoadString(m_hStatusBar,
SB_SIMPLEID,
- g_hInstance,
+ g_hThisInstance,
HintId);
return Found;
}
void
-CMainWindow::UpdateStatusBar(
- _In_ bool InMenuLoop
- )
+CDeviceManager::UpdateStatusBar(_In_ bool InMenuLoop)
{
SendMessageW(m_hStatusBar,
SB_SIMPLE,
}
bool
-CMainWindow::RefreshView(ViewType Type)
+CDeviceManager::RefreshView(_In_ ViewType Type,
+ _In_ bool ScanForChanges)
{
- UINT CheckId;
- BOOL bSuccess;
+ UINT CheckId = 0;
// Refreshed the cached view
- m_DeviceView->Refresh(Type, FALSE, TRUE);
+ m_DeviceView->Refresh(Type, ScanForChanges, true);
// Get the menu item id
switch (Type)
{
- case DevicesByType: CheckId = IDC_DEVBYTYPE; break;
- case DevicesByConnection: CheckId = IDC_DEVBYCONN; break;
- case ResourcesByType: CheckId = IDC_RESBYTYPE; break;
- case ResourcesByConnection: CheckId = IDC_RESBYCONN; break;
- default: ATLASSERT(FALSE); break;
+ case DevicesByType:
+ CheckId = IDC_DEVBYTYPE;
+ break;
+
+ case DevicesByConnection:
+ CheckId = IDC_DEVBYCONN;
+ break;
+
+ case ResourcesByType:
+ CheckId = IDC_RESBYTYPE;
+ break;
+
+ case ResourcesByConnection:
+ CheckId = IDC_RESBYCONN;
+ break;
+
+ default:
+ ATLASSERT(FALSE);
+ break;
}
// Set the new check item
- bSuccess = CheckMenuRadioItem(m_hMenu,
- IDC_DEVBYTYPE,
- IDC_RESBYCONN,
- CheckId,
- MF_BYCOMMAND);
-
- return TRUE;
-}
+ CheckMenuRadioItem(m_hMenu,
+ IDC_DEVBYTYPE,
+ IDC_RESBYCONN,
+ CheckId,
+ MF_BYCOMMAND);
-bool
-CMainWindow::ScanForHardwareChanges()
-{
- // Refresh the cache and and display
- m_DeviceView->Refresh(m_DeviceView->GetCurrentView(),
- true,
- true);
return true;
}
bool
-CMainWindow::CreateToolBar()
+CDeviceManager::CreateToolBar(void)
{
TBADDBITMAP TbAddBitmap;
- INT Index;
DWORD dwStyles = WS_CHILDWINDOW | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
0, 0, 0, 0,
m_hMainWnd,
(HMENU)IDC_TOOLBAR,
- g_hInstance,
+ g_hThisInstance,
NULL);
- if (m_hToolBar == NULL) return FALSE;
+ if (m_hToolBar == NULL)
+ return FALSE;
// Don't show clipped buttons
SendMessageW(m_hToolBar,
sizeof(TBBUTTON),
0);
- TbAddBitmap.hInst = g_hInstance;
+ TbAddBitmap.hInst = g_hThisInstance;
TbAddBitmap.nID = IDB_TOOLBAR;
- Index = SendMessageW(m_hToolBar, TB_ADDBITMAP, _countof(TbButtons), (LPARAM)&TbAddBitmap);
+ SendMessageW(m_hToolBar, TB_ADDBITMAP, _countof(TbButtons), (LPARAM)&TbAddBitmap);
SendMessageW(m_hToolBar, TB_ADDBUTTONSW, _countof(TbButtons), (LPARAM)TbButtons);
SendMessageW(m_hToolBar, TB_AUTOSIZE, 0, 0);
}
bool
-CMainWindow::CreateStatusBar()
+CDeviceManager::CreateStatusBar(void)
{
int StatWidths[] = {110, -1}; // widths of status bar
bool bRet = FALSE;
0, 0, 0, 0,
m_hMainWnd,
(HMENU)IDC_STATUSBAR,
- g_hInstance,
+ g_hThisInstance,
NULL);
if (m_hStatusBar)
{
return bRet;
}
-void CMainWindow::UpdateUiContext(_In_ LPTV_ITEMW TvItem)
+void CDeviceManager::UpdateToolbar()
{
WORD State;
+ CNode *Node = m_DeviceView->GetSelectedNode();
+
// properties button
- if (m_DeviceView->HasProperties(TvItem))
+ if (Node->HasProperties())
{
State = TBSTATE_ENABLED;
}
SendMessageW(m_hToolBar, TB_SETSTATE, IDC_UNINSTALL_DRV, MAKELPARAM(State, 0)); // hack
// enable driver button
- if (m_DeviceView->IsDisabled(TvItem))
+ if (Node->GetNodeType() == DeviceNode &&
+ dynamic_cast<CDeviceNode *>(Node)->IsDisabled())
{
State = TBSTATE_ENABLED;
}
SendMessageW(m_hToolBar, TB_SETSTATE, IDC_ENABLE_DRV, MAKELPARAM(State, 0));
// disable driver button
- if (m_DeviceView->CanDisable(TvItem) && !m_DeviceView->IsDisabled(TvItem))
+ if (Node->GetNodeType() == DeviceNode &&
+ dynamic_cast<CDeviceNode *>(Node)->CanDisable() &&
+ !dynamic_cast<CDeviceNode *>(Node)->IsDisabled())
{
State = TBSTATE_ENABLED;
}
State = TBSTATE_HIDDEN;
}
SendMessageW(m_hToolBar, TB_SETSTATE, IDC_DISABLE_DRV, MAKELPARAM(State, 0));
-
-
-
-
-
}
-
-
bool
-CMainWindow::StatusBarLoadString(IN HWND hStatusBar,
- IN INT PartId,
- IN HINSTANCE hInstance,
- IN UINT uID)
+CDeviceManager::StatusBarLoadString(_In_ HWND hStatusBar,
+ _In_ INT PartId,
+ _In_ HINSTANCE hInstance,
+ _In_ UINT uID)
{
CAtlStringW szMessage;
bool bRet = false;
}
LRESULT
-CMainWindow::OnCreate(HWND hwnd)
+CDeviceManager::OnCreate(_In_ HWND hwnd)
{
LRESULT RetCode;
if (m_DeviceView->Initialize())
{
// Do the initial scan
- ScanForHardwareChanges();
+ RefreshView(m_DeviceView->GetCurrentView(), true);
// Display the window according to the user request
ShowWindow(hwnd, m_CmdShow);
}
LRESULT
-CMainWindow::OnSize()
+CDeviceManager::OnSize(void)
{
RECT rcClient, rcTool, rcStatus;
INT lvHeight, iToolHeight, iStatusHeight;
}
LRESULT
-CMainWindow::OnNotify(LPARAM lParam)
+CDeviceManager::OnNotify(_In_ LPARAM lParam)
{
LPNMHDR NmHdr = (LPNMHDR)lParam;
- LRESULT Ret;
+ LRESULT Ret = 0;
switch (NmHdr->code)
{
case TVN_SELCHANGED:
{
- LPNMTREEVIEW NmTreeView = (LPNMTREEVIEW)lParam;
- UpdateUiContext(&NmTreeView->itemNew);
+ UpdateToolbar();
break;
}
case NM_DBLCLK:
{
- LPNMTREEVIEW NmTreeView = (LPNMTREEVIEW)lParam;
m_DeviceView->DisplayPropertySheet();
break;
}
case TTN_GETDISPINFO:
{
LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam;
+ lpttt->hinst = g_hThisInstance;
UINT_PTR idButton = lpttt->hdr.idFrom;
switch (idButton)
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_SCAN);
break;
case IDC_ENABLE_DRV:
- lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ENABLE);
+ lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_ENABLE);
break;
case IDC_DISABLE_DRV:
- lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_DIABLE);
+ lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_DISABLE);
break;
case IDC_UPDATE_DRV:
- lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_UPDATE);
+ lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UPDATE);
break;
case IDC_UNINSTALL_DRV:
- lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_UNINSTALL);
+ lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UNINSTALL);
break;
}
break;
}
}
- return 0;
+ return Ret;
}
LRESULT
-CMainWindow::OnContext(LPARAM lParam)
+CDeviceManager::OnContext(_In_ LPARAM lParam)
{
return m_DeviceView->OnContextMenu(lParam);
}
LRESULT
-CMainWindow::OnCommand(WPARAM wParam,
- LPARAM lParam)
+CDeviceManager::OnCommand(_In_ WPARAM wParam,
+ _In_ LPARAM /*lParam*/)
{
LRESULT RetCode = 0;
WORD Msg;
switch (Msg)
{
case IDC_PROPERTIES:
- {
- m_DeviceView->DisplayPropertySheet();
- break;
- }
-
case IDC_SCAN_HARDWARE:
- {
- ScanForHardwareChanges();
- break;
- }
-
case IDC_ENABLE_DRV:
- {
- bool NeedsReboot;
- if (m_DeviceView->EnableSelectedDevice(true, NeedsReboot) &&
- NeedsReboot)
- {
- MessageBox(m_hMainWnd, L"Rebooting", L"Enable", MB_OK);
- }
- break;
- }
-
case IDC_DISABLE_DRV:
- {
- bool NeedsReboot;
- m_DeviceView->EnableSelectedDevice(false, NeedsReboot);
- break;
- }
-
case IDC_UPDATE_DRV:
- {
- MessageBox(m_hMainWnd, L"Not yet implemented", L"Update Driver", MB_OK);
- break;
- }
-
case IDC_UNINSTALL_DRV:
+ case IDC_ADD_HARDWARE:
{
- MessageBox(m_hMainWnd, L"Not yet implemented", L"Uninstall Driver", MB_OK);
+ m_DeviceView->OnAction(Msg);
break;
}
- case IDC_ADD_HARDWARE:
+ case IDC_ACTIONMENU:
{
- MessageBox(m_hMainWnd, L"Not yet implemented", L"Add Hardware", MB_OK);
+ // Create a popup menu with all the actions for the selected node
+ HMENU hMenu = CreatePopupMenu();
+ m_DeviceView->CreateActionMenu(hMenu, true);
+
+ // Calculate where to put the menu
+ RECT rc;
+ GetMenuItemRect(m_hMainWnd, m_hMenu, 1, &rc);
+ LONG Height = rc.bottom - rc.top;
+
+ // Display the menu
+ TrackPopupMenuEx(hMenu,
+ TPM_RIGHTBUTTON,
+ rc.left,
+ rc.top + Height,
+ m_hMainWnd,
+ NULL);
+
+ DestroyMenu(hMenu);
break;
}
case IDC_DEVBYTYPE:
{
- RefreshView(DevicesByType);
+ RefreshView(DevicesByType, false);
break;
}
case IDC_DEVBYCONN:
{
- RefreshView(DevicesByConnection);
+ RefreshView(DevicesByConnection, false);
break;
}
CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | MF_CHECKED);
}
// Refresh the device view
- m_DeviceView->Refresh(m_DeviceView->GetCurrentView(),
- false,
- true);
+ RefreshView(m_DeviceView->GetCurrentView(), false);
break;
}
return RetCode;
}
+void
+CDeviceManager::OnActivate(void)
+{
+ m_DeviceView->SetFocus();
+}
+
LRESULT
-CMainWindow::OnDestroy()
+CDeviceManager::OnDestroy(void)
{
// Uninitialize the device view
m_DeviceView->Uninitialize();
}
LRESULT CALLBACK
-CMainWindow::MainWndProc(HWND hwnd,
- UINT msg,
- WPARAM wParam,
- LPARAM lParam)
+CDeviceManager::MainWndProc(_In_ HWND hwnd,
+ _In_ UINT msg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam)
{
- CMainWindow *This;
+ CDeviceManager *This;
LRESULT RetCode = 0;
// Get the object pointer from window context
- This = (CMainWindow *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ This = (CDeviceManager *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (This == NULL)
{
// Check that this isn't a create message
case WM_CREATE:
{
// Get the object pointer from the create param
- This = (CMainWindow *)((LPCREATESTRUCT)lParam)->lpCreateParams;
+ This = (CDeviceManager *)((LPCREATESTRUCT)lParam)->lpCreateParams;
// Store the pointer in the window's global user data
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)This);
break;
}
+ case WM_DEVICECHANGE:
+ {
+ if (wParam == DBT_DEVNODES_CHANGED)
+ {
+ //
+ // The OS can send multiple change messages in quick succession. To avoid
+ // refreshing multiple times (and to avoid waiting in the message thread)
+ // we set a timer to run in 500ms, which should leave enough time for all
+ // the messages to come through. Wrap so we don't set multiple timers
+ //
+ if (InterlockedCompareExchange((LONG *)&This->m_RefreshPending, TRUE, FALSE) == FALSE)
+ {
+ SetTimer(hwnd, REFRESH_TIMER, 500, NULL);
+ }
+ }
+ break;
+ }
+
+ case WM_TIMER:
+ {
+ if (wParam == REFRESH_TIMER)
+ {
+ // Schedule a refresh (this just creates a thread and returns)
+ This->RefreshView(This->m_DeviceView->GetCurrentView(), true);
+
+ // Cleanup the timer
+ KillTimer(hwnd, REFRESH_TIMER);
+
+ // Allow more change notifications
+ InterlockedExchange((LONG *)&This->m_RefreshPending, FALSE);
+ }
+ break;
+ }
+
case WM_ENTERMENULOOP:
{
This->UpdateStatusBar(true);
DestroyWindow(hwnd);
break;
}
-
+
+ case WM_ACTIVATE:
+ {
+ if (LOWORD(hwnd))
+ This->OnActivate();
+ break;
+ }
case WM_DESTROY:
{
return RetCode;
}
-
-
-//////// MOVE ME ////////////////
-
-HINSTANCE g_hInstance = NULL;
-HANDLE ProcessHeap = NULL;
-
-BOOL
-WINAPI
-DeviceManager_ExecuteW(HWND hWndParent,
- HINSTANCE hInst,
- LPCWSTR lpMachineName,
- int nCmdShow)
-{
- CMainWindow MainWindow;
- INITCOMMONCONTROLSEX icex;
- CAtlStringW szAppName;
- int Ret = 1;
-
- // Store the global values
- g_hInstance = hInst;
- ProcessHeap = GetProcessHeap();
-
- // Initialize common controls
- icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
- icex.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES;
- InitCommonControlsEx(&icex);
-
- // Load the application name
- if (szAppName.LoadStringW(g_hInstance, IDS_APPNAME))
- {
- // Initialize the main window
- if (MainWindow.Initialize(szAppName, nCmdShow))
- {
- // Run the application
- Ret = MainWindow.Run();
-
- // Uninitialize the main window
- MainWindow.Uninitialize();
- }
- }
-
- return Ret;
-}