- Move the devmgmt code to devmgr where it belongs and start to rewrite it (devmgmt_new wasn't a good design). It's not part of devmgr yet, I'll merge it and add it to the build when it's more complete.
- Add support for caching devices to speed up switching device views
- start to add dynamic context support so we can enable/disable, update and uninstall devices depending on its state.
- WIP

svn path=/trunk/; revision=68165
This commit is contained in:
Ged Murphy 2015-06-16 21:13:28 +00:00
parent 89f1ac6897
commit a676d524c9
14 changed files with 2565 additions and 0 deletions

View file

@ -0,0 +1,873 @@
/*
* PROJECT: ReactOS Device Manager
* LICENSE: GPL - See COPYING in the top level directory
* FILE: dll/win32/devmgr/devmgr/DeviceView.cpp
* PURPOSE: Implements the tree view which contains the devices
* COPYRIGHT: Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
*
*/
#include "stdafx.h"
#include "devmgmt.h"
#include "DeviceView.h"
/* DATA *********************************************/
#define CLASS_NAME_LEN 256
#define CLASS_DESC_LEN 256
INT_PTR
WINAPI
DevicePropertiesExW(
IN HWND hWndParent OPTIONAL,
IN LPCWSTR lpMachineName OPTIONAL,
IN LPCWSTR lpDeviceID OPTIONAL,
IN DWORD dwFlags OPTIONAL,
IN BOOL bShowDevMgr
);
typedef INT_PTR(WINAPI *pDevicePropertiesExW)(HWND,LPCWSTR,LPCWSTR,DWORD,BOOL);
struct RefreshThreadData
{
CDeviceView *This;
BOOL ScanForChanges;
BOOL UpdateView;
};
/* PUBLIC METHODS *************************************/
CDeviceView::CDeviceView(
HWND hMainWnd
) :
m_hMainWnd(hMainWnd),
m_hTreeView(NULL),
m_hPropertyDialog(NULL),
m_hShortcutMenu(NULL),
m_ViewType(DevicesByType),
m_ShowHidden(FALSE),
m_RootClassImage(-1),
m_RootDevInst(0)
{
ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA));
}
CDeviceView::~CDeviceView(void)
{
}
bool
CDeviceView::Initialize()
{
// Get the device image list
m_ImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
BOOL bSuccess = SetupDiGetClassImageList(&m_ImageListData);
if (bSuccess == FALSE) return false;
// Create the main treeview
m_hTreeView = CreateWindowExW(WS_EX_CLIENTEDGE,
WC_TREEVIEW,
NULL,
WS_CHILD | WS_VISIBLE | WS_BORDER | TVS_HASLINES |
TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_LINESATROOT,
0, 0, 0, 0,
m_hMainWnd,
(HMENU)IDC_TREEVIEW,
g_hInstance,
NULL);
if (m_hTreeView)
{
// Set the image list against the treeview
(void)TreeView_SetImageList(m_hTreeView,
m_ImageListData.ImageList,
TVSIL_NORMAL);
// Give the treeview arrows instead of +/- boxes (on Win7)
SetWindowTheme(m_hTreeView, L"explorer", NULL);
}
return !!(m_hTreeView);
}
bool
CDeviceView::Uninitialize()
{
EmptyDeviceView();
if (m_ImageListData.ImageList != NULL)
{
SetupDiDestroyClassImageList(&m_ImageListData);
ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA));
}
return true;
}
void
CDeviceView::Size(
_In_ int x,
_In_ int y,
_In_ int cx,
_In_ int cy
)
{
// Resize the treeview
SetWindowPos(m_hTreeView,
NULL,
x,
y,
cx,
cy,
SWP_NOZORDER);
}
void
CDeviceView::Refresh(_In_ ViewType Type,
_In_ bool ScanForChanges,
_In_ bool UpdateView)
{
// Enum devices on a seperate thread to keep the gui responsive
m_ViewType = Type;
RefreshThreadData *ThreadData;
ThreadData = new RefreshThreadData();
ThreadData->This = this;
ThreadData->ScanForChanges = ScanForChanges;
ThreadData->UpdateView = UpdateView;
HANDLE hThread;
hThread = (HANDLE)_beginthreadex(NULL,
0,
&RefreshThread,
ThreadData,
0,
NULL);
if (hThread) CloseHandle(hThread);
}
void
CDeviceView::DisplayPropertySheet()
{
//
// In ReactOS we can link to DevicePropertiesEx but
// not in windows as it's not part of the SDK
#ifndef __REACTOS__
HMODULE hModule = LoadLibraryW(L"devmgr.dll");
if (hModule == NULL) return;
pDevicePropertiesExW DevicePropertiesExW;
DevicePropertiesExW = (pDevicePropertiesExW)GetProcAddress(hModule,
"DevicePropertiesExW");
if (DevicePropertiesExW == NULL)
{
FreeLibrary(hModule);
return;
}
#endif
CNode *Node = GetSelectedNode();
if (Node && Node->HasProperties())
{
DevicePropertiesExW(m_hTreeView,
NULL,
Node->GetDeviceId(),
1,//DPF_EXTENDED,
FALSE);
}
#ifndef __REACTOS__
FreeLibrary(hModule);
#endif
}
void
CDeviceView::SetFocus()
{
}
bool
CDeviceView::HasProperties(_In_ LPTV_ITEMW TvItem)
{
CNode *Node = GetNode(TvItem);
if (Node)
{
return Node->HasProperties();
}
return false;
}
bool
CDeviceView::IsDisabled(_In_ LPTV_ITEMW TvItem)
{
CNode *Node = GetNode(TvItem);
if (Node)
{
return Node->IsDisabled();
}
return false;
}
bool
CDeviceView::CanDisable(_In_ LPTV_ITEMW TvItem)
{
CNode *Node = GetNode(TvItem);
if (Node)
{
return Node->CanDisable();
}
return false;
}
/* PRIVATE METHODS ********************************************/
bool
CDeviceView::AddRootDevice()
{
// Check whether we've loaded the root bitmap into the imagelist (done on first run)
if (m_RootClassImage == -1)
{
// Load the bitmap we'll be using as the root image
HBITMAP hRootImage;
hRootImage = LoadBitmapW(g_hInstance,
MAKEINTRESOURCEW(IDB_ROOT_IMAGE));
if (hRootImage == NULL) return FALSE;
// Add this bitmap to the device image list. This is a bit hacky, but it's safe
m_RootClassImage = ImageList_Add(m_ImageListData.ImageList,
hRootImage,
NULL);
DeleteObject(hRootImage);
}
/* Get the root instance */
CONFIGRET cr;
cr = CM_Locate_DevNodeW(&m_RootDevInst,
NULL,
CM_LOCATE_DEVNODE_NORMAL);
if (cr != CR_SUCCESS)
{
return false;
}
/* The root name is the computer name */
WCHAR RootDeviceName[ROOT_NAME_SIZE];
DWORD Size = ROOT_NAME_SIZE;
if (GetComputerNameW(RootDeviceName, &Size))
_wcslwr_s(RootDeviceName);
TV_ITEMW tvi;
TV_INSERTSTRUCT tvins;
ZeroMemory(&tvi, sizeof(tvi));
ZeroMemory(&tvins, sizeof(tvins));
// Insert the root / parent item into our treeview
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tvi.pszText = RootDeviceName;
tvi.cchTextMax = wcslen(RootDeviceName);
tvi.iImage = m_RootClassImage;
tvi.iSelectedImage = m_RootClassImage;
tvins.item = tvi;
m_hTreeRoot = TreeView_InsertItem(m_hTreeView, &tvins);
return (m_hTreeRoot != NULL);
}
bool
CDeviceView::GetNextClass(_In_ ULONG ClassIndex,
_Out_ LPGUID ClassGuid,
_Out_ HDEVINFO *hDevInfo)
{
CONFIGRET cr;
// Get the next class in the list
cr = CM_Enumerate_Classes(ClassIndex,
ClassGuid,
0);
if (cr != CR_SUCCESS) return false;
// Check for devices without a class
if (IsEqualGUID(*ClassGuid, GUID_DEVCLASS_UNKNOWN))
{
// Get device info for all devices for all classes
*hDevInfo = SetupDiGetClassDevsW(NULL,
NULL,
NULL,
DIGCF_ALLCLASSES);
}
else
{
// We only want the devices for this class
*hDevInfo = SetupDiGetClassDevsW(ClassGuid,
NULL,
NULL,
DIGCF_PRESENT);
}
return (hDevInfo != INVALID_HANDLE_VALUE);
}
unsigned int __stdcall CDeviceView::RefreshThread(void *Param)
{
RefreshThreadData *ThreadData = (RefreshThreadData *)Param;
CDeviceView *This = ThreadData->This;
// Empty the treeview
This->EmptyDeviceView();
This->m_hTreeRoot = NULL;
// Refresh the devices only if requested. This means
// switching views uses the cache and remains fast
if (ThreadData->ScanForChanges)
{
This->RefreshDeviceList();
}
// display the type of view the user wants
switch (This->m_ViewType)
{
case DevicesByType:
(void)This->ListDevicesByType();
break;
case DevicesByConnection:
(VOID)This->ListDevicesByConnection();
break;
case ResourcesByType:
break;
case ResourcesByConnection:
break;
}
delete ThreadData;
return 0;
}
bool
CDeviceView::ListDevicesByType()
{
CNode *ClassNode, *DeviceNode;
HDEVINFO hDevInfo;
HTREEITEM hTreeItem = NULL;
GUID ClassGuid;
INT ClassIndex;
LPTSTR DeviceId = NULL;
BOOL bClassSuccess, bSuccess;
// Start by adding the root node to the tree
bSuccess = AddRootDevice();
if (bSuccess == false) return false;
ClassIndex = 0;
do
{
// Loop through all the device classes
bClassSuccess = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo);
if (bClassSuccess)
{
bool bClassUnknown = false;
bool AddedParent = false;
INT DeviceIndex = 0;
BOOL MoreItems;
// Get the cached class node
ClassNode = GetClassNode(&ClassGuid);
if (ClassNode == NULL)
{
ATLASSERT(FALSE);
ClassIndex++;
continue;
}
// Set a flag is this is the (special case) unknown class
if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_UNKNOWN))
bClassUnknown = true;
do
{
// Get a handle to all the devices in this class
SP_DEVINFO_DATA DeviceInfoData;
ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
bSuccess = SetupDiEnumDeviceInfo(hDevInfo,
DeviceIndex,
&DeviceInfoData);
if (bSuccess == FALSE && GetLastError() == ERROR_NO_MORE_ITEMS)
MoreItems = FALSE;
if (bSuccess)
{
MoreItems = TRUE;
// The unknown class handle contains all devices on the system,
// and we're just looking for the ones with a null GUID
if (bClassUnknown)
{
if (IsEqualGUID(DeviceInfoData.ClassGuid, GUID_NULL) == FALSE)
{
// This is a known device, we aren't interested in it
DeviceIndex++;
continue;
}
}
// Get the cached device node
DeviceNode = GetDeviceNode(DeviceInfoData.DevInst);
if (DeviceNode == NULL)
{
ATLASSERT(bClassUnknown == true);
DeviceIndex++;
continue;
}
// Check if this is a hidden device
if (DeviceNode->IsHidden())
{
// Ignore this device if we aren't displaying hidden devices
if (m_ShowHidden == FALSE)
{
DeviceIndex++;
continue;
}
}
// We have a device, we need to add the parent if it hasn't yet been added
if (AddedParent == false)
{
// Insert the new class under the root item
hTreeItem = InsertIntoTreeView(m_hTreeRoot,
ClassNode);
AddedParent = true;
}
// Add the device under the class item node
(void)InsertIntoTreeView(hTreeItem, DeviceNode);
// Expand the class if it has a problem device
if (DeviceNode->HasProblem())
{
(void)TreeView_Expand(m_hTreeView,
hTreeItem,
TVE_EXPAND);
}
}
DeviceIndex++;
} while (MoreItems);
// If this class has devices, sort them alphabetically
if (AddedParent == true)
{
(void)TreeView_SortChildren(m_hTreeView,
hTreeItem,
0);
}
}
ClassIndex++;
} while (bClassSuccess);
// Sort the classes alphabetically
(void)TreeView_SortChildren(m_hTreeView,
m_hTreeRoot,
0);
// Expand the root item
(void)TreeView_Expand(m_hTreeView,
m_hTreeRoot,
TVE_EXPAND);
// Pre-select the root item
(VOID)TreeView_SelectItem(m_hTreeView,
m_hTreeRoot);
return 0;
}
bool
CDeviceView::ListDevicesByConnection()
{
BOOL bSuccess;
// Start by adding the root node to the tree
bSuccess = AddRootDevice();
if (bSuccess == false) return false;
/* Walk the device tree and add all the devices */
RecurseChildDevices(m_RootDevInst, m_hTreeRoot);
/* Expand the root item */
(VOID)TreeView_Expand(m_hTreeView,
m_hTreeRoot,
TVE_EXPAND);
return true;
}
VOID
CDeviceView::RecurseChildDevices(
_In_ DEVINST ParentDevice,
_In_ HTREEITEM hParentTreeItem
)
{
HTREEITEM hDevItem = NULL;
DEVINST Device;
BOOL bSuccess;
/* Check if the parent has any child devices */
if (GetChildDevice(ParentDevice, &Device) == FALSE)
return;
// Get the cached device node
CNode *DeviceNode;
DeviceNode = GetDeviceNode(Device);
if (DeviceNode == NULL)
{
ATLASSERT(FALSE);
return;
}
/* Check if this is a hidden device */
if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden())))
{
/* Add this device to the tree under its parent */
hDevItem = InsertIntoTreeView(hParentTreeItem,
DeviceNode);
if (hDevItem)
{
/* Check if this child has any children itself */
RecurseChildDevices(Device, hDevItem);
}
}
for (;;)
{
/* Check if the parent device has anything at the same level */
bSuccess = GetSiblingDevice(Device, &Device);
if (bSuccess == FALSE) break;
DeviceNode = GetDeviceNode(Device);
if (DeviceNode == NULL)
{
ATLASSERT(FALSE);
}
/* Check if this is a hidden device */
if (DeviceNode->IsHidden())
{
if (m_ShowHidden == FALSE)
continue;
}
/* Add this device to the tree under its parent */
hDevItem = InsertIntoTreeView(hParentTreeItem,
DeviceNode);
if (hDevItem)
{
/* Check if this child has any children itself */
RecurseChildDevices(Device, hDevItem);
}
}
(void)TreeView_SortChildren(m_hTreeView,
hParentTreeItem,
0);
}
bool
CDeviceView::GetChildDevice(
_In_ DEVINST ParentDevInst,
_Out_ PDEVINST DevInst
)
{
CONFIGRET cr;
cr = CM_Get_Child(DevInst,
ParentDevInst,
0);
return (cr == CR_SUCCESS);
}
bool
CDeviceView::GetSiblingDevice(
_In_ DEVINST PrevDevice,
_Out_ PDEVINST DevInst
)
{
CONFIGRET cr;
cr = CM_Get_Sibling(DevInst,
PrevDevice,
0);
return (cr == CR_SUCCESS);
}
HTREEITEM
CDeviceView::InsertIntoTreeView(
_In_ HTREEITEM hParent,
_In_ CNode *Node
)
{
LPWSTR lpLabel;
lpLabel = Node->GetDisplayName();
TV_ITEMW tvi;
TV_INSERTSTRUCT tvins;
ZeroMemory(&tvi, sizeof(tvi));
ZeroMemory(&tvins, sizeof(tvins));
tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tvi.pszText = lpLabel;
tvi.cchTextMax = wcslen(lpLabel);
tvi.lParam = (LPARAM)Node;
tvi.iImage = Node->GetClassImage();
tvi.iSelectedImage = Node->GetClassImage();
if (Node->GetOverlayImage())
{
tvi.mask |= TVIF_STATE;
tvi.stateMask = TVIS_OVERLAYMASK;
tvi.state = INDEXTOOVERLAYMASK(Node->GetOverlayImage());
}
tvins.item = tvi;
tvins.hParent = hParent;
return TreeView_InsertItem(m_hTreeView, &tvins);
}
void
CDeviceView::RecurseDeviceView(
_In_ HTREEITEM hParentItem
)
{
HTREEITEM hItem;
TVITEMW tvItem;
// Check if this node has any children
hItem = TreeView_GetChild(m_hTreeView, hParentItem);
if (hItem == NULL) return;
// The lParam contains the node pointer data
tvItem.hItem = hItem;
tvItem.mask = TVIF_PARAM;
if (TreeView_GetItem(m_hTreeView, &tvItem) &&
tvItem.lParam != NULL)
{
// Delete the node class
//delete reinterpret_cast<CNode *>(tvItem.lParam);
}
// This node may have its own children
RecurseDeviceView(hItem);
// Delete all the siblings
for (;;)
{
// Get the next item at this level
hItem = TreeView_GetNextSibling(m_hTreeView, hItem);
if (hItem == NULL) break;
// The lParam contains the node pointer data
tvItem.hItem = hItem;
tvItem.mask = TVIF_PARAM;
if (TreeView_GetItem(m_hTreeView, &tvItem))
{
//if (tvItem.lParam != NULL)
// delete reinterpret_cast<CNode *>(tvItem.lParam);
}
/* This node may have its own children */
RecurseDeviceView(hItem);
}
}
void
CDeviceView::EmptyDeviceView()
{
HTREEITEM hItem;
// Check if there are any items in the tree
hItem = TreeView_GetRoot(m_hTreeView);
if (hItem == NULL) return;
// Free all the class nodes
//RecurseDeviceView(hItem);
// Delete all the items
(VOID)TreeView_DeleteAllItems(m_hTreeView);
}
CNode*
CDeviceView::GetClassNode(_In_ LPGUID ClassGuid)
{
POSITION Pos;
CNode *Node;
Pos = m_ClassNodeList.GetHeadPosition();
do
{
Node = m_ClassNodeList.GetNext(Pos);
if (IsEqualGUID(*Node->GetClassGuid(), *ClassGuid))
{
//ATLASSERT(Node->GetType() == NodeClass);
break;
}
Node = NULL;
} while (Pos != NULL);
return Node;
}
CNode*
CDeviceView::GetDeviceNode(_In_ DEVINST Device)
{
POSITION Pos;
CNode *Node;
Pos = m_DeviceNodeList.GetHeadPosition();
do
{
Node = m_DeviceNodeList.GetNext(Pos);
if (Node->GetDeviceInst() == Device)
{
//ATLASSERT(Node->GetType() == NodeDevice);
break;
}
Node = NULL;
} while (Pos != NULL);
return Node;
}
CNode* CDeviceView::GetNode(LPTV_ITEMW TvItem)
{
TvItem->mask = TVIF_PARAM;
if (TreeView_GetItem(m_hTreeView, TvItem))
{
return (CNode *)TvItem->lParam;
}
}
CNode* CDeviceView::GetSelectedNode()
{
TV_ITEM TvItem;
TvItem.hItem = TreeView_GetSelection(m_hTreeView);
return GetNode(&TvItem);
}
void
CDeviceView::EmptyLists()
{
POSITION Pos;
CNode *Node;
if (!m_ClassNodeList.IsEmpty())
{
Pos = m_ClassNodeList.GetHeadPosition();
do
{
Node = m_ClassNodeList.GetNext(Pos);
delete Node;
} while (Pos != NULL);
}
if (!m_DeviceNodeList.IsEmpty())
{
Pos = m_DeviceNodeList.GetHeadPosition();
do
{
Node = m_DeviceNodeList.GetNext(Pos);
delete Node;
} while (Pos != NULL);
}
}
bool
CDeviceView::RefreshDeviceList()
{
GUID ClassGuid;
CNode *Node;
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
BOOL Success;
ULONG ClassIndex = 0;
EmptyLists();
do
{
Success = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo);
if (Success)
{
/* Create a new class node */
Node = new CNode(&ClassGuid, &m_ImageListData);
if (Node->Setup())
{
m_ClassNodeList.AddTail(Node);
}
}
ClassIndex++;
} while (Success);
hDevInfo = SetupDiGetClassDevsW(NULL,
0,
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
return false;
}
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0;; i++)
{
Success = SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData);
if (Success == FALSE) break;
Node = new CNode(DeviceInfoData.DevInst, &m_ImageListData);
Node->Setup();
m_DeviceNodeList.AddTail(Node);
}
SetupDiDestroyDeviceInfoList(hDevInfo);
return TRUE;
}

View file

@ -0,0 +1,131 @@
#pragma once
#include "Node.h"
enum ViewType
{
DevicesByType,
DevicesByConnection,
ResourcesByType,
ResourcesByConnection
};
class CDeviceView
{
CAtlList<CNode *> m_ClassNodeList;
CAtlList<CNode *> m_DeviceNodeList;
SP_CLASSIMAGELIST_DATA m_ImageListData;
HWND m_hMainWnd;
HWND m_hTreeView;
HWND m_hPropertyDialog;
HWND m_hShortcutMenu;
ViewType m_ViewType;
HTREEITEM m_hTreeRoot;
DEVINST m_RootDevInst;
bool m_ShowHidden;
int m_RootClassImage;
public:
CDeviceView(
HWND hMainWnd
);
~CDeviceView(void);
bool Initialize();
bool Uninitialize();
VOID Size(
_In_ int x,
_In_ int y,
_In_ int cx,
_In_ int cy
);
VOID Refresh(
_In_ ViewType Type,
_In_ bool ScanForChanges,
_In_ bool UpdateView
);
VOID DisplayPropertySheet();
VOID SetFocus();
//VOID SetDeviceListType(ListDevices List)
//{
// m_ListDevices = List;
//}
VOID ShowHiddenDevices(_In_ bool ShowHidden)
{
m_ShowHidden = ShowHidden;
}
ViewType GetCurrentView() { return m_ViewType; }
bool HasProperties(_In_ LPTV_ITEMW TvItem);
//bool SelDeviceIsHidden();
bool CanDisable(_In_ LPTV_ITEMW TvItem);
bool IsDisabled(_In_ LPTV_ITEMW TvItem);
bool SelDeviceIsStarted();
bool SelDeviceIsInstalled();
private:
bool AddRootDevice();
bool RefreshDeviceList();
static unsigned int __stdcall RefreshThread(
void *Param
);
bool ListDevicesByConnection(
);
bool ListDevicesByType(
);
bool GetNextClass(
_In_ ULONG ClassIndex,
_Out_ LPGUID ClassGuid,
_Out_ HDEVINFO *hDevInfo
);
VOID RecurseChildDevices(
_In_ DEVINST ParentDevice,
_In_ HTREEITEM hParentTreeItem
);
bool GetChildDevice(
_In_ DEVINST ParentDevInst,
_Out_ PDEVINST DevInst
);
bool GetSiblingDevice(
_In_ DEVINST PrevDevice,
_Out_ PDEVINST DevInst
);
HTREEITEM InsertIntoTreeView(
_In_ HTREEITEM hParent,
_In_ CNode *Node
);
VOID RecurseDeviceView(
_In_ HTREEITEM hParentItem
);
VOID EmptyDeviceView(
);
CNode* GetNode(_In_ LPTV_ITEMW TvItem);
CNode* GetSelectedNode();
CNode* GetClassNode(_In_ LPGUID ClassGuid);
CNode* GetDeviceNode(_In_ DEVINST Device);
void EmptyLists();
};

View file

@ -0,0 +1,764 @@
/*
* PROJECT: ReactOS Device Manager
* LICENSE: GPL - See COPYING in the top level directory
* FILE: dll/win32/devmgr/devmgr/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 "devmgmt.h"
#include "MainWindow.h"
/* DATA *****************************************************/
#define BTN_PROPERTIES 0
#define BTN_SCAN_HARDWARE 1
#define BTN_SEPERATOR -1
#define BTN_ENABLE_DRV 2
#define BTN_DISABLE_DRV 3
#define BTN_UPDATE_DRV 4
#define BTN_UNINSTALL_DRV 5
// menu hints
static const MENU_HINT MainMenuHintTable[] =
{
// File Menu
{ IDC_EXIT, IDS_HINT_EXIT },
// Action Menu
{ IDC_UPDATE_DRV, NULL },
{ IDC_DISABLE_DRV, NULL },
{ IDC_UNINSTALL_DRV, NULL },
{ IDC_SCAN_HARDWARE, IDS_HINT_REFRESH },
{ IDC_ADD_HARDWARE, NULL },
{ IDC_PROPERTIES, IDS_HINT_PROP},
// 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_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 },
{ 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 }
};
/* PUBLIC METHODS **********************************************/
CMainWindow::CMainWindow(void) :
m_ToolbarhImageList(NULL),
m_hMainWnd(NULL),
m_hStatusBar(NULL),
m_hToolBar(NULL),
m_CmdShow(0)
{
m_szMainWndClass = L"DevMgmtWndClass";
}
CMainWindow::~CMainWindow(void)
{
// Destroy any previous list
if (m_ToolbarhImageList) ImageList_Destroy(m_ToolbarhImageList);
}
bool
CMainWindow::Initialize(LPCTSTR lpCaption,
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_hInstance;
wc.hIcon = LoadIcon(g_hInstance, 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,
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,
500,
500,
NULL,
NULL,
g_hInstance,
this);
}
// Return creation result
return !!(m_hMainWnd);
}
void
CMainWindow::Uninitialize()
{
// Unregister the window class
UnregisterClassW(m_szMainWndClass, g_hInstance);
}
int
CMainWindow::Run()
{
MSG Msg;
// Pump the message queue
while (GetMessageW(&Msg, NULL, 0, 0 ) != 0)
{
TranslateMessage(&Msg);
DispatchMessageW(&Msg);
}
return 0;
}
/* PRIVATE METHODS **********************************************/
bool
CMainWindow::MainWndMenuHint(WORD CmdId,
const MENU_HINT *HintArray,
DWORD HintsCount,
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_hInstance,
HintId);
return Found;
}
bool
CMainWindow::RefreshView(ViewType Type)
{
UINT CheckId;
BOOL bSuccess;
// Refreshed the cached view
m_DeviceView->Refresh(Type, FALSE, 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
bSuccess = CheckMenuRadioItem(m_hMenu,
IDC_DEVBYTYPE,
IDC_RESBYCONN,
CheckId,
MF_BYCOMMAND);
return TRUE;
}
bool
CMainWindow::ScanForHardwareChanges()
{
// Refresh the cache and and display
m_DeviceView->Refresh(m_DeviceView->GetCurrentView(),
true,
true);
return true;
}
bool
CMainWindow::CreateToolBar()
{
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;
// Create the toolbar window
m_hToolBar = CreateWindowExW(dwExStyles,
TOOLBARCLASSNAME,
NULL,
dwStyles,
0, 0, 0, 0,
m_hMainWnd,
(HMENU)IDC_TOOLBAR,
g_hInstance,
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_hInstance;
TbAddBitmap.nID = IDB_TOOLBAR;
Index = 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
CMainWindow::CreateStatusBar()
{
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_hInstance,
NULL);
if (m_hStatusBar)
{
// Set the width
bRet = (SendMessageW(m_hStatusBar,
SB_SETPARTS,
sizeof(StatWidths) / sizeof(int),
(LPARAM)StatWidths) != 0);
}
return bRet;
}
void CMainWindow::UpdateContext(_In_ LPTV_ITEMW TvItem)
{
WORD State;
// properties button
if (m_DeviceView->HasProperties(TvItem))
{
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 (m_DeviceView->IsDisabled(TvItem))
{
State = TBSTATE_ENABLED;
}
else
{
State = TBSTATE_HIDDEN;
}
SendMessageW(m_hToolBar, TB_SETSTATE, IDC_ENABLE_DRV, MAKELPARAM(State, 0));
// disable driver button
if (m_DeviceView->CanDisable(TvItem) && !m_DeviceView->IsDisabled(TvItem))
{
State = TBSTATE_ENABLED;
}
else
{
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)
{
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
CMainWindow::OnCreate(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
ScanForHardwareChanges();
// Display the window according to the user request
ShowWindow(hwnd, m_CmdShow);
RetCode = 0;
}
}
return RetCode;
}
LRESULT
CMainWindow::OnSize()
{
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->Size(0,
iToolHeight,
rcClient.right,
lvHeight);
return 0;
}
LRESULT
CMainWindow::OnNotify(LPARAM lParam)
{
LPNMHDR NmHdr = (LPNMHDR)lParam;
switch (NmHdr->code)
{
case TVN_SELCHANGED:
{
LPNMTREEVIEW NmTreeView = (LPNMTREEVIEW)lParam;
UpdateContext(&NmTreeView->itemNew);
break;
}
case TVN_DELETEITEMW:
{
LPNMTREEVIEW NmTreeView = (LPNMTREEVIEW)lParam;
NmTreeView->action = NmTreeView->action;
break;
}
case NM_DBLCLK:
{
m_DeviceView->DisplayPropertySheet();
break;
}
case NM_RETURN:
{
m_DeviceView->DisplayPropertySheet();
break;
}
}
return 0;
}
LRESULT
CMainWindow::OnContext(LPARAM lParam)
{
return 0;
}
LRESULT
CMainWindow::OnCommand(WPARAM wParam,
LPARAM lParam)
{
LRESULT RetCode = 0;
WORD Msg;
// Get the message
Msg = LOWORD(wParam);
switch (Msg)
{
case IDC_PROPERTIES:
{
m_DeviceView->DisplayPropertySheet();
break;
}
case IDC_SCAN_HARDWARE:
{
ScanForHardwareChanges();
break;
}
case IDC_DEVBYTYPE:
{
RefreshView(DevicesByType);
break;
}
case IDC_DEVBYCONN:
{
RefreshView(DevicesByConnection);
break;
}
case IDC_SHOWHIDDEN:
{
UINT CurCheckState, NewCheckState;
// Get the current state
CurCheckState = GetMenuState(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND);
if (CurCheckState == MF_CHECKED)
{
// Inform the device view of the change
m_DeviceView->ShowHiddenDevices(false);
NewCheckState = MF_UNCHECKED;
}
else if (CurCheckState == MF_UNCHECKED)
{
m_DeviceView->ShowHiddenDevices(true);
NewCheckState = MF_CHECKED;
}
else
{
ATLASSERT(FALSE);
break;
}
// Set the new check state
CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | NewCheckState);
// Refresh the device view
m_DeviceView->Refresh(m_DeviceView->GetCurrentView(),
false,
true);
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;
}
LRESULT
CMainWindow::OnDestroy()
{
// 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
CMainWindow::MainWndProc(HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
CMainWindow *pThis;
LRESULT RetCode = 0;
// Get the object pointer from window context
pThis = (CMainWindow *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (pThis == 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
pThis = (CMainWindow *)((LPCREATESTRUCT)lParam)->lpCreateParams;
// Store the pointer in the window's global user data
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
// Call the create handler
RetCode = pThis->OnCreate(hwnd);
break;
}
case WM_SIZE:
{
RetCode = pThis->OnSize();
break;
}
case WM_NOTIFY:
{
RetCode = pThis->OnNotify(lParam);
break;
}
case WM_CONTEXTMENU:
{
RetCode = pThis->OnContext(lParam);
break;
}
case WM_MENUSELECT:
{
if (pThis->m_hStatusBar != NULL)
{
if (!pThis->MainWndMenuHint(LOWORD(wParam),
MainMenuHintTable,
sizeof(MainMenuHintTable) / sizeof(MainMenuHintTable[0]),
IDS_HINT_BLANK))
{
pThis->MainWndMenuHint(LOWORD(wParam),
SystemMenuHintTable,
sizeof(SystemMenuHintTable) / sizeof(SystemMenuHintTable[0]),
IDS_HINT_BLANK);
}
}
break;
}
case WM_COMMAND:
{
// Handle the command message
RetCode = pThis->OnCommand(wParam, lParam);
if (RetCode == -1)
{
// Hand it off to the default message handler
goto HandleDefaultMessage;
}
}
case WM_CLOSE:
{
// Destroy the main window
DestroyWindow(hwnd);
}
break;
case WM_DESTROY:
{
// Call the destroy handler
RetCode = pThis->OnDestroy();
break;
}
default:
{
HandleDefaultMessage:
RetCode = DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
}
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;
}

View file

@ -0,0 +1,70 @@
#pragma once
#include "DeviceView.h"
typedef struct _MENU_HINT
{
WORD CmdId;
UINT HintId;
} MENU_HINT, *PMENU_HINT;
class CMainWindow
{
CAtlStringW m_szMainWndClass;
CDeviceView *m_DeviceView;
HWND m_hMainWnd;
HWND m_hStatusBar;
HWND m_hToolBar;
HIMAGELIST m_ToolbarhImageList;
HMENU m_hMenu;
int m_CmdShow;
public:
CMainWindow(void);
~CMainWindow(void);
bool Initialize(LPCTSTR lpCaption, int nCmdShow);
int Run();
void Uninitialize();
private:
static LRESULT CALLBACK MainWndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
);
LRESULT OnCreate(HWND hwnd);
LRESULT OnDestroy();
LRESULT OnSize();
LRESULT OnNotify(LPARAM lParam);
LRESULT OnContext(LPARAM lParam);
LRESULT OnCommand(WPARAM wParam, LPARAM lParam);
bool CreateToolBar();
bool CreateStatusBar();
void UpdateContext(_In_ LPTV_ITEMW TvItem);
bool StatusBarLoadString(
HWND hStatusBar,
INT PartId,
HINSTANCE hInstance,
UINT uID
);
bool MainWndMenuHint(
WORD CmdId,
const MENU_HINT *HintArray,
DWORD HintsCount,
UINT DefHintId
);
bool RefreshView(
ViewType Type
);
bool ScanForHardwareChanges(
);
};

View file

@ -0,0 +1,375 @@
/*
* PROJECT: ReactOS Device Manager
* LICENSE: GPL - See COPYING in the top level directory
* FILE: dll/win32/devmgr/devmgr/node.cpp
* PURPOSE: Object for each device in the tree
* COPYRIGHT: Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
*
*/
#include "stdafx.h"
#include "devmgmt.h"
#include "Node.h"
/* PUBLIC METHODS *******************************************/
CNode::CNode(_In_ LPGUID ClassGuid,
_In_ PSP_CLASSIMAGELIST_DATA ImageListData) :
m_ImageListData(ImageListData),
m_NodeType(NodeClass),
m_DevInst(0),
m_DeviceId(NULL),
m_ClassImage(0),
m_Status(0),
m_ProblemNumber(0),
m_OverlayImage(0)
{
m_DisplayName[0] = UNICODE_NULL;
CopyMemory(&m_ClassGuid, ClassGuid, sizeof(GUID));
}
CNode::CNode(_In_opt_ DEVINST Device,
_In_ PSP_CLASSIMAGELIST_DATA ImageListData) :
m_ImageListData(ImageListData),
m_NodeType(NodeDevice),
m_DevInst(Device),
m_DeviceId(NULL),
m_ClassImage(0),
m_Status(0),
m_ProblemNumber(0),
m_OverlayImage(0)
{
m_DisplayName[0] = UNICODE_NULL;
CopyMemory(&m_ClassGuid, &GUID_NULL, sizeof(GUID));
}
CNode::~CNode()
{
Cleanup();
}
bool
CNode::Setup()
{
// TODO: Make this polymorphic
if (m_NodeType == NodeClass)
{
return SetupClassNode();
}
else if (m_NodeType == NodeDevice)
{
return SetupDeviceNode();
}
return FALSE;
}
bool
CNode::HasProperties()
{
return (m_DeviceId != NULL);
}
bool
CNode::IsHidden()
{
return ((m_Status & DN_NO_SHOW_IN_DM) != 0);
}
bool
CNode::CanDisable()
{
return (m_NodeType == NodeDevice && ((m_Status & DN_DISABLEABLE) != 0));
}
bool
CNode::IsDisabled()
{
return ((m_ProblemNumber & (CM_PROB_DISABLED | CM_PROB_HARDWARE_DISABLED)) != 0);
}
bool
CNode::IsStarted()
{
return ((m_Status & DN_STARTED) != 0);
}
bool
CNode::IsInstalled()
{
return ((m_Status & DN_HAS_PROBLEM) != 0 ||
(m_Status & (DN_DRIVER_LOADED | DN_STARTED)) != 0);
}
/* PRIVATE METHODS ******************************************/
bool
CNode::SetupClassNode()
{
DWORD RequiredSize, Type, Size;
DWORD Success;
HKEY hKey;
// Open the registry key for this class
hKey = SetupDiOpenClassRegKeyExW(&m_ClassGuid,
MAXIMUM_ALLOWED,
DIOCR_INSTALLER,
NULL,
0);
if (hKey != INVALID_HANDLE_VALUE)
{
Size = DISPLAY_NAME_LEN;
Type = REG_SZ;
// Lookup the class description (win7+)
Success = RegQueryValueExW(hKey,
L"ClassDesc",
NULL,
&Type,
(LPBYTE)m_DisplayName,
&Size);
if (Success == ERROR_SUCCESS)
{
// Check if the string starts with an @
if (m_DisplayName[0] == L'@')
{
// The description is located in a module resource
Success = ConvertResourceDescriptorToString(m_DisplayName, DISPLAY_NAME_LEN);
}
}
else if (Success == ERROR_FILE_NOT_FOUND)
{
// WinXP stores the description in the default value
Success = RegQueryValueExW(hKey,
NULL,
NULL,
&Type,
(LPBYTE)m_DisplayName,
&Size);
}
// Close the registry key
RegCloseKey(hKey);
}
else
{
Success = GetLastError();
}
// Check if we failed to get the class description
if (Success != ERROR_SUCCESS)
{
// Use the class name as the description
RequiredSize = DISPLAY_NAME_LEN;
(VOID)SetupDiClassNameFromGuidW(&m_ClassGuid,
m_DisplayName,
RequiredSize,
&RequiredSize);
}
// Get the image index for this class
(VOID)SetupDiGetClassImageIndex(m_ImageListData,
&m_ClassGuid,
&m_ClassImage);
return true;
}
bool
CNode::SetupDeviceNode()
{
WCHAR ClassGuidString[MAX_GUID_STRING_LEN];
ULONG ulLength;
CONFIGRET cr;
// ATLASSERT(m_DeviceId == NULL);
// Get the length of the device id string
cr = CM_Get_Device_ID_Size(&ulLength, m_DevInst, 0);
if (cr == CR_SUCCESS)
{
// We alloc heap here because this will be stored in the lParam of the TV
m_DeviceId = (LPWSTR)HeapAlloc(GetProcessHeap(),
0,
(ulLength + 1) * sizeof(WCHAR));
if (m_DeviceId)
{
// Now get the actual device id
cr = CM_Get_Device_IDW(m_DevInst,
m_DeviceId,
ulLength + 1,
0);
if (cr != CR_SUCCESS)
{
HeapFree(GetProcessHeap(), 0, m_DeviceId);
m_DeviceId = NULL;
}
}
}
// Make sure we got the string
if (m_DeviceId == NULL)
return false;
// Get the current status of the device
cr = CM_Get_DevNode_Status_Ex(&m_Status,
&m_ProblemNumber,
m_DevInst,
0,
NULL);
if (cr != CR_SUCCESS)
{
HeapFree(GetProcessHeap(), 0, m_DeviceId);
m_DeviceId = NULL;
return false;
}
// Check if the device has a problem
if (m_Status & DN_HAS_PROBLEM)
{
m_OverlayImage = 1;
}
// The disabled overlay takes precidence over the problem overlay
if (m_ProblemNumber & (CM_PROB_DISABLED | CM_PROB_HARDWARE_DISABLED))
{
m_OverlayImage = 2;
}
// Get the class guid for this device
ulLength = MAX_GUID_STRING_LEN * sizeof(WCHAR);
cr = CM_Get_DevNode_Registry_PropertyW(m_DevInst,
CM_DRP_CLASSGUID,
NULL,
ClassGuidString,
&ulLength,
0);
if (cr == CR_SUCCESS)
{
// Convert the string to a proper guid
CLSIDFromString(ClassGuidString, &m_ClassGuid);
}
else
{
// It's a device with no driver
m_ClassGuid = GUID_DEVCLASS_UNKNOWN;
}
// Get the image for the class this device is in
SetupDiGetClassImageIndex(m_ImageListData,
&m_ClassGuid,
&m_ClassImage);
// Get the description for the device
ulLength = DISPLAY_NAME_LEN * sizeof(WCHAR);
cr = CM_Get_DevNode_Registry_PropertyW(m_DevInst,
CM_DRP_FRIENDLYNAME,
NULL,
m_DisplayName,
&ulLength,
0);
if (cr != CR_SUCCESS)
{
ulLength = DISPLAY_NAME_LEN * sizeof(WCHAR);
cr = CM_Get_DevNode_Registry_PropertyW(m_DevInst,
CM_DRP_DEVICEDESC,
NULL,
m_DisplayName,
&ulLength,
0);
}
// Cleanup if something failed
if (cr != CR_SUCCESS)
{
HeapFree(GetProcessHeap(), 0, m_DeviceId);
m_DeviceId = NULL;
}
return (cr == CR_SUCCESS ? true : false);
}
void
CNode::Cleanup()
{
if (m_DeviceId)
{
HeapFree(GetProcessHeap(), 0, m_DeviceId);
m_DeviceId = NULL;
}
}
DWORD
CNode::ConvertResourceDescriptorToString(
_Inout_z_ LPWSTR ResourceDescriptor,
_In_ DWORD ResourceDescriptorSize
)
{
WCHAR ModulePath[MAX_PATH];
WCHAR ResString[256];
INT ResourceId;
HMODULE hModule;
LPWSTR ptr;
DWORD Size;
DWORD dwError;
// First check for a semi colon */
ptr = wcschr(ResourceDescriptor, L';');
if (ptr)
{
// This must be an inf based descriptor, the desc is after the semi colon
wcscpy_s(ResourceDescriptor, ResourceDescriptorSize, ++ptr);
dwError = ERROR_SUCCESS;
}
else
{
// This must be a dll resource based descriptor. Find the comma
ptr = wcschr(ResourceDescriptor, L',');
if (ptr == NULL) return ERROR_INVALID_DATA;
// Terminate the string where the comma was
*ptr = UNICODE_NULL;
// Expand any environment strings
Size = ExpandEnvironmentStringsW(&ResourceDescriptor[1], ModulePath, MAX_PATH);
if (Size > MAX_PATH) return ERROR_BUFFER_OVERFLOW;
if (Size == 0) return GetLastError();
// Put the comma back and move past it
*ptr = L',';
ptr++;
// Load the dll
hModule = LoadLibraryExW(ModulePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
if (hModule == NULL) return GetLastError();
// Convert the resource id to a number
ResourceId = _wtoi(ptr);
// If the number is negative, make it positive
if (ResourceId < 0) ResourceId = -ResourceId;
// Load the string from the dll
if (LoadStringW(hModule, ResourceId, ResString, 256))
{
wcscpy_s(ResourceDescriptor, ResourceDescriptorSize, ResString);
dwError = ERROR_SUCCESS;
}
else
{
dwError = GetLastError();
}
// Free the library
FreeLibrary(hModule);
}
return dwError;
}

View file

@ -0,0 +1,78 @@
#pragma once
#define DISPLAY_NAME_LEN 256
#define ROOT_NAME_SIZE MAX_COMPUTERNAME_LENGTH + 1
enum NodeType
{
NodeClass,
NodeDevice
};
typedef ULONG Actions;
#define Update 0x01
#define Enable 0x02
#define Disable 0x04
#define Uninstall 0x08
class CNode
{
private:
PSP_CLASSIMAGELIST_DATA m_ImageListData;
NodeType m_NodeType;
DEVINST m_DevInst;
Actions m_Actions;
LPWSTR m_DeviceId;
WCHAR m_DisplayName[DISPLAY_NAME_LEN];
GUID m_ClassGuid;
INT m_ClassImage;
ULONG m_Status;
ULONG m_ProblemNumber;
INT m_OverlayImage;
public:
CNode(
_In_ LPGUID ClassGuid,
_In_ PSP_CLASSIMAGELIST_DATA ImageListData
);
CNode(
_In_ DEVINST Device,
_In_ PSP_CLASSIMAGELIST_DATA ImageListData
);
~CNode();
bool Setup();
LPGUID GetClassGuid() { return &m_ClassGuid; }
DEVINST GetDeviceInst() { return m_DevInst; }
LPWSTR GetDisplayName() { return m_DisplayName; }
INT GetClassImage() { return m_ClassImage; }
INT GetOverlayImage() { return m_OverlayImage; }
LPWSTR GetDeviceId() { return m_DeviceId; }
Actions GetActions() { return m_Actions; }
bool HasProblem() { return !!(m_ProblemNumber); }
bool HasProperties();
bool IsHidden();
bool CanDisable();
bool IsDisabled();
bool IsStarted();
bool IsInstalled();
bool CanInstall() { return TRUE; } // unimplemented
bool CanUninstall() { return TRUE; } // unimplemented
private:
bool SetupClassNode();
bool SetupDeviceNode();
void Cleanup();
DWORD ConvertResourceDescriptorToString(
_Inout_z_ LPWSTR ResourceDescriptor,
_In_ DWORD ResourceDescriptorSize
);
};

View file

@ -0,0 +1,63 @@
#define IDC_STATIC -1
#define IDI_MAIN_ICON 20
#define IDB_ROOT_IMAGE 21
#define IDB_TOOLBAR 22
/* windows */
#define IDC_TREEVIEW 50
#define IDC_TOOLBAR 51
#define IDC_STATUSBAR 52
#define IDR_MAINMENU 53
#define IDR_POPUP 54
/* Actions */
#define IDC_PROPERTIES 100
#define IDC_SCAN_HARDWARE 101
#define IDC_ENABLE_DRV 102
#define IDC_DISABLE_DRV 103
#define IDC_UPDATE_DRV 104
#define IDC_UNINSTALL_DRV 105
#define IDC_ADD_HARDWARE 106
#define IDC_ABOUT 107
#define IDC_EXIT 108
/* view menu */
#define IDC_DEVBYTYPE 200
#define IDC_DEVBYCONN 201
#define IDC_RESBYTYPE 202
#define IDC_RESBYCONN 203
#define IDC_SHOWHIDDEN 204
/* about box info */
#define IDD_ABOUTBOX 300
#define IDC_LICENSE_EDIT 301
#define IDS_APPNAME 302
#define IDS_LICENSE 303
/* tooltips */
#define IDS_TOOLTIP_PROP 6000
#define IDS_TOOLTIP_REFRESH 6001
#define IDS_TOOLTIP_HELP 6002
/* menu hints */
#define IDS_HINT_BLANK 20000
#define IDS_HINT_REFRESH 20002
#define IDS_HINT_PROP 20003
#define IDS_HINT_HELP 20004
#define IDS_HINT_ABOUT 20005
#define IDS_HINT_EXIT 20006
#define IDS_HINT_DEV_BY_TYPE 20020
#define IDS_HINT_DEV_BY_CONN 20021
#define IDS_HINT_RES_BY_TYPE 20022
#define IDS_HINT_RES_BY_CONN 20023
/* system menu hints */
#define IDS_HINT_SYS_RESTORE 21001
#define IDS_HINT_SYS_MOVE 21002
#define IDS_HINT_SYS_SIZE 21003
#define IDS_HINT_SYS_MINIMIZE 21004
#define IDS_HINT_SYS_MAXIMIZE 21005
#define IDS_HINT_SYS_CLOSE 21006

View file

@ -0,0 +1,9 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#pragma once
#include "resource.h"
extern HINSTANCE g_hInstance;
extern HANDLE ProcessHeap;

View file

@ -0,0 +1,72 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
IDR_MAINMENU MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", IDC_EXIT
END
POPUP "Action"
BEGIN
MENUITEM "Update driver software..." IDC_UPDATE_DRV
MENUITEM "Disable" IDC_DISABLE_DRV
MENUITEM "Uninstall" IDC_UNINSTALL_DRV
MENUITEM SEPARATOR
MENUITEM "Scan for hardware changes" IDC_SCAN_HARDWARE
MENUITEM "Add hardware" IDC_ADD_HARDWARE, GRAYED
MENUITEM SEPARATOR
MENUITEM "Properties", IDC_PROPERTIES
END
POPUP "View"
BEGIN
MENUITEM "Devices by type", IDC_DEVBYTYPE
MENUITEM "Devices by connection", IDC_DEVBYCONN
MENUITEM "Resources by type", IDC_RESBYTYPE, GRAYED
MENUITEM "Resources by connection", IDC_RESBYCONN, GRAYED
MENUITEM SEPARATOR
MENUITEM "Show hidden devices", IDC_SHOWHIDDEN
END
POPUP "Help"
BEGIN
MENUITEM "About", IDC_ABOUT
END
END
IDR_POPUP MENU
BEGIN
POPUP "popup"
BEGIN
MENUITEM "Properties", IDC_PROPERTIES, GRAYED
END
END
STRINGTABLE DISCARDABLE
BEGIN
IDS_TOOLTIP_PROP "Properties"
IDS_TOOLTIP_REFRESH "Scan for hardware changes"
IDS_TOOLTIP_HELP "Help"
END
/* Hints */
STRINGTABLE DISCARDABLE
BEGIN
IDS_APPNAME "ReactOS Device Manager"
IDS_HINT_BLANK " "
IDS_HINT_EXIT " Exits the program."
IDS_HINT_REFRESH " Scan for changed or new Plug and Play devices."
IDS_HINT_PROP " Open property dialog for the current selection."
IDS_HINT_HELP " Display help window."
IDS_HINT_ABOUT " About ReactOS Device Manager."
IDS_HINT_DEV_BY_TYPE "Displays devices by hardware type"
IDS_HINT_DEV_BY_CONN "Displays devices by connection"
IDS_HINT_RES_BY_TYPE "Diaplays resources by type"
IDS_HINT_RES_BY_CONN "Displays resources by connection type"
IDS_HINT_SYS_RESTORE " Restores this window to normal size."
IDS_HINT_SYS_MOVE " Moves this window."
IDS_HINT_SYS_SIZE " Resizes this window."
IDS_HINT_SYS_MINIMIZE " Collapses this window to an icon."
IDS_HINT_SYS_MAXIMIZE " Expands this window to fill this screen."
IDS_HINT_SYS_CLOSE " Closes this window."
END

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

@ -0,0 +1,80 @@
#include <windows.h>
#include "resource.h"
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDI_MAIN_ICON ICON "res/computer.ico"
IDB_ROOT_IMAGE BITMAP "res/root.bmp"
/* main toolbar icons */
IDB_TOOLBAR BITMAP DISCARDABLE "res/toolbar.bmp"
// UTF-8
#pragma code_page(65001)
#ifdef LANGUAGE_BG_BG
#include "lang/bg-BG.rc"
#endif
#ifdef LANGUAGE_DE_DE
#include "lang/de-DE.rc"
#endif
#ifdef LANGUAGE_EL_GR
#include "lang/el-GR.rc"
#endif
#ifdef LANGUAGE_EN_US
#include "lang/en-US.rc"
#endif
#ifdef LANGUAGE_ES_ES
#include "lang/es-ES.rc"
#endif
#ifdef LANGUAGE_FR_FR
#include "lang/fr-FR.rc"
#endif
#ifdef LANGUAGE_HE_IL
#include "lang/he-IL.rc"
#endif
#ifdef LANGUAGE_ID_ID
#include "lang/id-ID.rc"
#endif
#ifdef LANGUAGE_IT_IT
#include "lang/it-IT.rc"
#endif
#ifdef LANGUAGE_JA_JP
#include "lang/ja-JP.rc"
#endif
#ifdef LANGUAGE_KO_KR
#include "lang/ko-KR.rc"
#endif
#ifdef LANGUAGE_NB_NO
#include "lang/no-NO.rc"
#endif
#ifdef LANGUAGE_PL_PL
#include "lang/pl-PL.rc"
#endif
#ifdef LANGUAGE_PT_BR
#include "lang/pt-BR.rc"
#endif
#ifdef LANGUAGE_RO_RO
#include "lang/ro-RO.rc"
#endif
#ifdef LANGUAGE_RU_RU
#include "lang/ru-RU.rc"
#endif
#ifdef LANGUAGE_SK_SK
#include "lang/sk-SK.rc"
#endif
#ifdef LANGUAGE_SV_SE
#include "lang/sv-SE.rc"
#endif
#ifdef LANGUAGE_TH_TH
#include "lang/th-TH.rc"
#endif
#ifdef LANGUAGE_TR_TR
#include "lang/tr-TR.rc"
#endif
#ifdef LANGUAGE_UK_UA
#include "lang/uk-UA.rc"
#endif
#ifdef LANGUAGE_ZH_CN
#include "lang/zh-CN.rc"
#endif

View file

@ -0,0 +1,50 @@
#pragma once
#ifndef __REACTOS___
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <windowsx.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#include <commctrl.h>
#include <Uxtheme.h>
#include <Cfgmgr32.h>
#include <devguid.h>
#include <process.h>
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
#include <tchar.h>
#include <atlbase.h>
#include <atlstr.h>
#include <atlcoll.h>
#else
#include <tchar.h>
#include <windef.h>
#include <winbase.h>
#include <winreg.h>
#include <wingdi.h>
#include <winnls.h>
#include <wincon.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <process.h>
#include <string.h>
#include <wchar.h>
#include <setupapi.h>
#include <commctrl.h>
#include <cfgmgr32.h>
#include <Uxtheme.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlwin.h>
#include <atlstr.h>
#endif