mirror of
https://github.com/reactos/reactos.git
synced 2024-08-21 10:53:15 +00:00
867 lines
23 KiB
C++
867 lines
23 KiB
C++
/*
|
|
* PROJECT: ReactOS Device Manager
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* 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 "precomp.h"
|
|
#include "devmgmt.h"
|
|
#include "MainWindow.h"
|
|
|
|
|
|
/* DATA *****************************************************/
|
|
|
|
#define BTN_PROPERTIES 0
|
|
#define BTN_SCAN_HARDWARE 1
|
|
#define BTN_ENABLE_DRV 2
|
|
#define BTN_DISABLE_DRV 3
|
|
#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[] =
|
|
{
|
|
// File Menu
|
|
{ IDC_EXIT, IDS_HINT_EXIT },
|
|
|
|
// Action Menu
|
|
{ IDC_PROPERTIES, IDS_HINT_PROPERTIES },
|
|
{ IDC_SCAN_HARDWARE, IDS_HINT_SCAN },
|
|
{ IDC_ENABLE_DRV, IDS_HINT_ENABLE },
|
|
{ IDC_DISABLE_DRV, IDS_HINT_DISABLE },
|
|
{ IDC_UPDATE_DRV, IDS_HINT_UPDATE },
|
|
{ IDC_UNINSTALL_DRV, IDS_HINT_UNINSTALL },
|
|
{ IDC_ADD_HARDWARE, IDS_HINT_ADD },
|
|
|
|
|
|
// View Menu
|
|
{ IDC_DEVBYTYPE, IDS_HINT_DEV_BY_TYPE},
|
|
{ IDC_DEVBYCONN, IDS_HINT_DEV_BY_CONN},
|
|
{ IDC_RESBYTYPE, IDS_HINT_RES_BY_TYPE},
|
|
{ IDC_RESBYCONN, IDS_HINT_RES_BY_TYPE},
|
|
{ IDC_SHOWHIDDEN, IDS_HINT_SHOW_HIDDEN },
|
|
|
|
{ IDC_ABOUT, IDS_HINT_ABOUT }
|
|
|
|
};
|
|
|
|
|
|
// system menu hints
|
|
static const MENU_HINT SystemMenuHintTable[] =
|
|
{
|
|
{SC_RESTORE, IDS_HINT_SYS_RESTORE},
|
|
{SC_MOVE, IDS_HINT_SYS_MOVE},
|
|
{SC_SIZE, IDS_HINT_SYS_SIZE},
|
|
{SC_MINIMIZE, IDS_HINT_SYS_MINIMIZE},
|
|
{SC_MAXIMIZE, IDS_HINT_SYS_MAXIMIZE},
|
|
{SC_CLOSE, IDS_HINT_SYS_CLOSE}
|
|
};
|
|
|
|
static TBBUTTON TbButtons[] =
|
|
{
|
|
{ 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 **********************************************/
|
|
|
|
CDeviceManager::CDeviceManager(void) :
|
|
m_hMainWnd(NULL),
|
|
m_hStatusBar(NULL),
|
|
m_hToolBar(NULL),
|
|
m_CmdShow(0),
|
|
m_RefreshPending(false)
|
|
{
|
|
m_szMainWndClass = L"DevMgmtWndClass";
|
|
}
|
|
|
|
CDeviceManager::~CDeviceManager(void)
|
|
{
|
|
}
|
|
|
|
bool
|
|
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};
|
|
|
|
// Store the show window value
|
|
m_CmdShow = nCmdShow;
|
|
|
|
// Setup the window class struct
|
|
wc.cbSize = sizeof(WNDCLASSEXW);
|
|
wc.lpfnWndProc = MainWndProc;
|
|
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_hThisInstance,
|
|
MAKEINTRESOURCE(IDI_MAIN_ICON),
|
|
IMAGE_ICON,
|
|
16,
|
|
16,
|
|
LR_SHARED);
|
|
|
|
// Register the window
|
|
if (RegisterClassExW(&wc))
|
|
{
|
|
// Create the main window and store the object pointer
|
|
m_hMainWnd = CreateWindowExW(WS_EX_WINDOWEDGE,
|
|
m_szMainWndClass,
|
|
lpCaption,
|
|
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
550,
|
|
500,
|
|
NULL,
|
|
NULL,
|
|
g_hThisInstance,
|
|
this);
|
|
}
|
|
|
|
// Return creation result
|
|
return !!(m_hMainWnd);
|
|
}
|
|
|
|
void
|
|
CDeviceManager::Uninitialize(void)
|
|
{
|
|
// Unregister the window class
|
|
UnregisterClassW(m_szMainWndClass, g_hThisInstance);
|
|
}
|
|
|
|
int
|
|
CDeviceManager::Run(void)
|
|
{
|
|
MSG Msg;
|
|
|
|
// Pump the message queue
|
|
while (GetMessageW(&Msg, NULL, 0, 0 ) != 0)
|
|
{
|
|
TranslateMessage(&Msg);
|
|
DispatchMessageW(&Msg);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
CDeviceManager::MainWndMenuHint(_In_ WORD CmdId,
|
|
_In_ const MENU_HINT *HintArray,
|
|
_In_ DWORD HintsCount,
|
|
_In_ UINT DefHintId)
|
|
{
|
|
bool Found = false;
|
|
const MENU_HINT *LastHint;
|
|
UINT HintId = DefHintId;
|
|
|
|
LastHint = HintArray + HintsCount;
|
|
while (HintArray != LastHint)
|
|
{
|
|
if (HintArray->CmdId == CmdId)
|
|
{
|
|
HintId = HintArray->HintId;
|
|
Found = true;
|
|
break;
|
|
}
|
|
HintArray++;
|
|
}
|
|
|
|
StatusBarLoadString(m_hStatusBar,
|
|
SB_SIMPLEID,
|
|
g_hThisInstance,
|
|
HintId);
|
|
|
|
return Found;
|
|
}
|
|
|
|
void
|
|
CDeviceManager::UpdateStatusBar(_In_ bool InMenuLoop)
|
|
{
|
|
SendMessageW(m_hStatusBar,
|
|
SB_SIMPLE,
|
|
(WPARAM)InMenuLoop,
|
|
0);
|
|
}
|
|
|
|
bool
|
|
CDeviceManager::RefreshView(_In_ ViewType Type,
|
|
_In_ bool ScanForChanges)
|
|
{
|
|
UINT CheckId = 0;
|
|
|
|
// Refreshed the cached view
|
|
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;
|
|
}
|
|
|
|
// Set the new check item
|
|
CheckMenuRadioItem(m_hMenu,
|
|
IDC_DEVBYTYPE,
|
|
IDC_RESBYCONN,
|
|
CheckId,
|
|
MF_BYCOMMAND);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
CDeviceManager::CreateToolBar(void)
|
|
{
|
|
TBADDBITMAP TbAddBitmap;
|
|
|
|
DWORD dwStyles = WS_CHILDWINDOW | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
|
|
DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
|
|
|
|
// Create the toolbar window
|
|
m_hToolBar = CreateWindowExW(dwExStyles,
|
|
TOOLBARCLASSNAME,
|
|
NULL,
|
|
dwStyles,
|
|
0, 0, 0, 0,
|
|
m_hMainWnd,
|
|
(HMENU)IDC_TOOLBAR,
|
|
g_hThisInstance,
|
|
NULL);
|
|
if (m_hToolBar == NULL)
|
|
return FALSE;
|
|
|
|
// Don't show clipped buttons
|
|
SendMessageW(m_hToolBar,
|
|
TB_SETEXTENDEDSTYLE,
|
|
0,
|
|
TBSTYLE_EX_HIDECLIPPEDBUTTONS);
|
|
|
|
SendMessageW(m_hToolBar, TB_SETBITMAPSIZE, 0, MAKELONG(16, 16));
|
|
|
|
// Set the struct size, the toobar needs this...
|
|
SendMessageW(m_hToolBar,
|
|
TB_BUTTONSTRUCTSIZE,
|
|
sizeof(TBBUTTON),
|
|
0);
|
|
|
|
TbAddBitmap.hInst = g_hThisInstance;
|
|
TbAddBitmap.nID = IDB_TOOLBAR;
|
|
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);
|
|
|
|
if (TRUE)
|
|
{
|
|
ShowWindow(m_hToolBar, SW_SHOW);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool
|
|
CDeviceManager::CreateStatusBar(void)
|
|
{
|
|
int StatWidths[] = {110, -1}; // widths of status bar
|
|
bool bRet = FALSE;
|
|
|
|
// Create the status bar
|
|
m_hStatusBar = CreateWindowExW(0,
|
|
STATUSCLASSNAME,
|
|
NULL,
|
|
WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
|
|
0, 0, 0, 0,
|
|
m_hMainWnd,
|
|
(HMENU)IDC_STATUSBAR,
|
|
g_hThisInstance,
|
|
NULL);
|
|
if (m_hStatusBar)
|
|
{
|
|
// Set the width
|
|
bRet = (SendMessageW(m_hStatusBar,
|
|
SB_SETPARTS,
|
|
sizeof(StatWidths) / sizeof(int),
|
|
(LPARAM)StatWidths) != 0);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
void CDeviceManager::UpdateToolbar()
|
|
{
|
|
WORD State;
|
|
|
|
CNode *Node = m_DeviceView->GetSelectedNode();
|
|
|
|
// properties button
|
|
if (Node->HasProperties())
|
|
{
|
|
State = TBSTATE_ENABLED;
|
|
}
|
|
else
|
|
{
|
|
State = TBSTATE_HIDDEN;
|
|
}
|
|
SendMessageW(m_hToolBar, TB_SETSTATE, IDC_PROPERTIES, MAKELPARAM(State, 0));
|
|
SendMessageW(m_hToolBar, TB_SETSTATE, IDC_UPDATE_DRV, MAKELPARAM(State, 0)); //hack
|
|
SendMessageW(m_hToolBar, TB_SETSTATE, IDC_UNINSTALL_DRV, MAKELPARAM(State, 0)); // hack
|
|
|
|
// enable driver button
|
|
if (Node->GetNodeType() == DeviceNode &&
|
|
dynamic_cast<CDeviceNode *>(Node)->IsDisabled())
|
|
{
|
|
State = TBSTATE_ENABLED;
|
|
}
|
|
else
|
|
{
|
|
State = TBSTATE_HIDDEN;
|
|
}
|
|
SendMessageW(m_hToolBar, TB_SETSTATE, IDC_ENABLE_DRV, MAKELPARAM(State, 0));
|
|
|
|
// disable driver button
|
|
if (Node->GetNodeType() == DeviceNode &&
|
|
dynamic_cast<CDeviceNode *>(Node)->CanDisable() &&
|
|
!dynamic_cast<CDeviceNode *>(Node)->IsDisabled())
|
|
{
|
|
State = TBSTATE_ENABLED;
|
|
}
|
|
else
|
|
{
|
|
State = TBSTATE_HIDDEN;
|
|
}
|
|
SendMessageW(m_hToolBar, TB_SETSTATE, IDC_DISABLE_DRV, MAKELPARAM(State, 0));
|
|
}
|
|
|
|
bool
|
|
CDeviceManager::StatusBarLoadString(_In_ HWND hStatusBar,
|
|
_In_ INT PartId,
|
|
_In_ HINSTANCE hInstance,
|
|
_In_ UINT uID)
|
|
{
|
|
CAtlStringW szMessage;
|
|
bool bRet = false;
|
|
|
|
// Load the string
|
|
if (szMessage.LoadStringW(hInstance, uID))
|
|
{
|
|
// Show the string on the status bar
|
|
bRet = (SendMessageW(hStatusBar,
|
|
SB_SETTEXT,
|
|
(WPARAM)PartId,
|
|
(LPARAM)szMessage.GetBuffer()) != 0);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
LRESULT
|
|
CDeviceManager::OnCreate(_In_ HWND hwnd)
|
|
{
|
|
LRESULT RetCode;
|
|
|
|
RetCode = -1;
|
|
m_hMainWnd = hwnd;
|
|
|
|
// Store a handle to the main menu
|
|
m_hMenu = GetMenu(m_hMainWnd);
|
|
|
|
// Create the toolbar and statusbar
|
|
if (CreateToolBar() && CreateStatusBar())
|
|
{
|
|
// Create the device view object
|
|
m_DeviceView = new CDeviceView(m_hMainWnd);
|
|
if (m_DeviceView->Initialize())
|
|
{
|
|
// Do the initial scan
|
|
RefreshView(m_DeviceView->GetCurrentView(), true);
|
|
|
|
// Display the window according to the user request
|
|
ShowWindow(hwnd, m_CmdShow);
|
|
RetCode = 0;
|
|
}
|
|
}
|
|
|
|
return RetCode;
|
|
}
|
|
|
|
LRESULT
|
|
CDeviceManager::OnSize(void)
|
|
{
|
|
RECT rcClient, rcTool, rcStatus;
|
|
INT lvHeight, iToolHeight, iStatusHeight;
|
|
|
|
// Autosize the toolbar
|
|
SendMessage(m_hToolBar, TB_AUTOSIZE, 0, 0);
|
|
|
|
// Get the toolbar rect and save the height
|
|
GetWindowRect(m_hToolBar, &rcTool);
|
|
iToolHeight = rcTool.bottom - rcTool.top;
|
|
|
|
// Resize the status bar
|
|
SendMessage(m_hStatusBar, WM_SIZE, 0, 0);
|
|
|
|
// Get the statusbar rect and save the height
|
|
GetWindowRect(m_hStatusBar, &rcStatus);
|
|
iStatusHeight = rcStatus.bottom - rcStatus.top;
|
|
|
|
// Get the full client rect
|
|
GetClientRect(m_hMainWnd, &rcClient);
|
|
|
|
// Calculate the remaining height for the treeview
|
|
lvHeight = rcClient.bottom - iToolHeight - iStatusHeight;
|
|
|
|
// Resize the device view
|
|
m_DeviceView->OnSize(0,
|
|
iToolHeight,
|
|
rcClient.right,
|
|
lvHeight);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
CDeviceManager::OnNotify(_In_ LPARAM lParam)
|
|
{
|
|
LPNMHDR NmHdr = (LPNMHDR)lParam;
|
|
LRESULT Ret = 0;
|
|
|
|
switch (NmHdr->code)
|
|
{
|
|
case TVN_SELCHANGED:
|
|
{
|
|
UpdateToolbar();
|
|
break;
|
|
}
|
|
|
|
case NM_DBLCLK:
|
|
{
|
|
m_DeviceView->DisplayPropertySheet();
|
|
break;
|
|
}
|
|
|
|
case NM_RCLICK:
|
|
{
|
|
Ret = m_DeviceView->OnRightClick(NmHdr);
|
|
break;
|
|
}
|
|
|
|
case NM_RETURN:
|
|
{
|
|
m_DeviceView->DisplayPropertySheet();
|
|
break;
|
|
}
|
|
|
|
case TTN_GETDISPINFO:
|
|
{
|
|
LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam;
|
|
lpttt->hinst = g_hThisInstance;
|
|
|
|
UINT_PTR idButton = lpttt->hdr.idFrom;
|
|
switch (idButton)
|
|
{
|
|
case IDC_PROPERTIES:
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_PROPERTIES);
|
|
break;
|
|
case IDC_SCAN_HARDWARE:
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_SCAN);
|
|
break;
|
|
case IDC_ENABLE_DRV:
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_ENABLE);
|
|
break;
|
|
case IDC_DISABLE_DRV:
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_DISABLE);
|
|
break;
|
|
case IDC_UPDATE_DRV:
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UPDATE);
|
|
break;
|
|
case IDC_UNINSTALL_DRV:
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UNINSTALL);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
LRESULT
|
|
CDeviceManager::OnContext(_In_ LPARAM lParam)
|
|
{
|
|
return m_DeviceView->OnContextMenu(lParam);
|
|
}
|
|
|
|
LRESULT
|
|
CDeviceManager::OnCommand(_In_ WPARAM wParam,
|
|
_In_ LPARAM /*lParam*/)
|
|
{
|
|
LRESULT RetCode = 0;
|
|
WORD Msg;
|
|
|
|
// Get the message
|
|
Msg = LOWORD(wParam);
|
|
|
|
switch (Msg)
|
|
{
|
|
case IDC_PROPERTIES:
|
|
case IDC_SCAN_HARDWARE:
|
|
case IDC_ENABLE_DRV:
|
|
case IDC_DISABLE_DRV:
|
|
case IDC_UPDATE_DRV:
|
|
case IDC_UNINSTALL_DRV:
|
|
case IDC_ADD_HARDWARE:
|
|
{
|
|
m_DeviceView->OnAction(Msg);
|
|
break;
|
|
}
|
|
|
|
case IDC_ACTIONMENU:
|
|
{
|
|
// 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, false);
|
|
break;
|
|
}
|
|
|
|
case IDC_DEVBYCONN:
|
|
{
|
|
RefreshView(DevicesByConnection, false);
|
|
break;
|
|
}
|
|
|
|
case IDC_SHOWHIDDEN:
|
|
{
|
|
// Get the current state
|
|
UINT CurCheckState = GetMenuState(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND);
|
|
if (CurCheckState == MF_CHECKED)
|
|
{
|
|
m_DeviceView->SetHiddenDevices(false);
|
|
CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | MF_UNCHECKED);
|
|
}
|
|
else if (CurCheckState == MF_UNCHECKED)
|
|
{
|
|
m_DeviceView->SetHiddenDevices(true);
|
|
CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | MF_CHECKED);
|
|
}
|
|
// Refresh the device view
|
|
RefreshView(m_DeviceView->GetCurrentView(), false);
|
|
break;
|
|
}
|
|
|
|
case IDC_ABOUT:
|
|
{
|
|
// Apportion blame
|
|
MessageBoxW(m_hMainWnd,
|
|
L"ReactOS Device Manager\r\nCopyright Ged Murphy 2015",
|
|
L"About",
|
|
MB_OK | MB_APPLMODAL);
|
|
|
|
// Set focus back to the treeview
|
|
m_DeviceView->SetFocus();
|
|
break;
|
|
}
|
|
|
|
case IDC_EXIT:
|
|
{
|
|
// Post a close message to the window
|
|
PostMessageW(m_hMainWnd,
|
|
WM_CLOSE,
|
|
0,
|
|
0);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// We didn't handle it
|
|
RetCode = -1;
|
|
break;
|
|
}
|
|
|
|
return RetCode;
|
|
}
|
|
|
|
void
|
|
CDeviceManager::OnActivate(void)
|
|
{
|
|
m_DeviceView->SetFocus();
|
|
}
|
|
|
|
LRESULT
|
|
CDeviceManager::OnDestroy(void)
|
|
{
|
|
// Uninitialize the device view
|
|
m_DeviceView->Uninitialize();
|
|
|
|
// Kill the object
|
|
delete m_DeviceView;
|
|
m_DeviceView = NULL;
|
|
|
|
// Clear the user data pointer
|
|
SetWindowLongPtr(m_hMainWnd, GWLP_USERDATA, 0);
|
|
|
|
// Break the message loop
|
|
PostQuitMessage(0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CALLBACK
|
|
CDeviceManager::MainWndProc(_In_ HWND hwnd,
|
|
_In_ UINT msg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam)
|
|
{
|
|
CDeviceManager *This;
|
|
LRESULT RetCode = 0;
|
|
|
|
// Get the object pointer from window context
|
|
This = (CDeviceManager *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
if (This == NULL)
|
|
{
|
|
// Check that this isn't a create message
|
|
if (msg != WM_CREATE)
|
|
{
|
|
// Don't handle null info pointer
|
|
goto HandleDefaultMessage;
|
|
}
|
|
}
|
|
|
|
switch(msg)
|
|
{
|
|
case WM_CREATE:
|
|
{
|
|
// Get the object pointer from the create param
|
|
This = (CDeviceManager *)((LPCREATESTRUCT)lParam)->lpCreateParams;
|
|
|
|
// Store the pointer in the window's global user data
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)This);
|
|
|
|
// Call the create handler
|
|
RetCode = This->OnCreate(hwnd);
|
|
break;
|
|
}
|
|
|
|
case WM_SIZE:
|
|
{
|
|
RetCode = This->OnSize();
|
|
break;
|
|
}
|
|
|
|
case WM_NOTIFY:
|
|
{
|
|
RetCode = This->OnNotify(lParam);
|
|
break;
|
|
}
|
|
|
|
case WM_CONTEXTMENU:
|
|
{
|
|
RetCode = This->OnContext(lParam);
|
|
break;
|
|
}
|
|
|
|
case WM_MENUSELECT:
|
|
{
|
|
if (This->m_hStatusBar != NULL)
|
|
{
|
|
if (!This->MainWndMenuHint(LOWORD(wParam),
|
|
MainMenuHintTable,
|
|
sizeof(MainMenuHintTable) / sizeof(MainMenuHintTable[0]),
|
|
IDS_HINT_BLANK))
|
|
{
|
|
This->MainWndMenuHint(LOWORD(wParam),
|
|
SystemMenuHintTable,
|
|
sizeof(SystemMenuHintTable) / sizeof(SystemMenuHintTable[0]),
|
|
IDS_HINT_BLANK);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
// Handle the command message
|
|
RetCode = This->OnCommand(wParam, lParam);
|
|
if (RetCode == -1)
|
|
{
|
|
// Hand it off to the default message handler
|
|
goto HandleDefaultMessage;
|
|
}
|
|
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);
|
|
break;
|
|
}
|
|
|
|
case WM_EXITMENULOOP:
|
|
{
|
|
This->UpdateStatusBar(false);
|
|
break;
|
|
}
|
|
|
|
case WM_CLOSE:
|
|
{
|
|
// Destroy the main window
|
|
DestroyWindow(hwnd);
|
|
break;
|
|
}
|
|
|
|
case WM_ACTIVATE:
|
|
{
|
|
if (LOWORD(hwnd))
|
|
This->OnActivate();
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
// Call the destroy handler
|
|
RetCode = This->OnDestroy();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
HandleDefaultMessage:
|
|
RetCode = DefWindowProc(hwnd, msg, wParam, lParam);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return RetCode;
|
|
}
|