- Add basic functionality for enabling and disabling devices. Make it accessible via the toolbar and main menu
- Implement checking whether a device has a problem and if a device can be uninstalled
- Implement getting, setting and removing device flags in the install params
- Fix creating and destroying the (currently empty) context menu

svn path=/trunk/; revision=68265
This commit is contained in:
Ged Murphy 2015-06-25 18:59:23 +00:00
parent 32e831b904
commit b9e36d1c46
5 changed files with 260 additions and 13 deletions

View file

@ -22,10 +22,12 @@ CDeviceNode::CDeviceNode(
m_ProblemNumber(0), m_ProblemNumber(0),
m_OverlayImage(0) m_OverlayImage(0)
{ {
ZeroMemory(&m_DevinfoData, sizeof(SP_DEVINFO_DATA));
} }
CDeviceNode::~CDeviceNode() CDeviceNode::~CDeviceNode()
{ {
SetupDiDestroyDeviceInfoList(m_hDevInfo);
} }
bool bool
@ -37,6 +39,7 @@ CDeviceNode::SetupNode()
// ATLASSERT(m_DeviceId == NULL); // ATLASSERT(m_DeviceId == NULL);
// Get the length of the device id string // Get the length of the device id string
cr = CM_Get_Device_ID_Size(&ulLength, m_DevInst, 0); cr = CM_Get_Device_ID_Size(&ulLength, m_DevInst, 0);
if (cr == CR_SUCCESS) if (cr == CR_SUCCESS)
@ -64,6 +67,23 @@ CDeviceNode::SetupNode()
if (m_DeviceId == NULL) if (m_DeviceId == NULL)
return false; return false;
//SP_DEVINFO_DATA DevinfoData;
m_hDevInfo = SetupDiCreateDeviceInfoListExW(NULL,
NULL,
NULL,
NULL);
if (m_hDevInfo != INVALID_HANDLE_VALUE)
{
m_DevinfoData.cbSize = sizeof(SP_DEVINFO_DATA);
SetupDiOpenDeviceInfoW(m_hDevInfo,
m_DeviceId,
NULL,
0,
&m_DevinfoData);
}
// Get the current status of the device // Get the current status of the device
cr = CM_Get_DevNode_Status_Ex(&m_Status, cr = CM_Get_DevNode_Status_Ex(&m_Status,
&m_ProblemNumber, &m_ProblemNumber,
@ -145,6 +165,22 @@ CDeviceNode::SetupNode()
return (cr == CR_SUCCESS ? true : false); return (cr == CR_SUCCESS ? true : false);
} }
bool
CDeviceNode::HasProblem()
{
CONFIGRET cr;
cr = CM_Get_DevNode_Status_Ex(&m_Status,
&m_ProblemNumber,
m_DevInst,
0,
NULL);
if (cr == CR_SUCCESS)
{
return ((m_Status & (DN_HAS_PROBLEM | DN_PRIVATE_PROBLEM)) != 0);
}
return false;
}
bool bool
CDeviceNode::IsHidden() CDeviceNode::IsHidden()
@ -231,3 +267,154 @@ CDeviceNode::IsInstalled()
return false; return false;
} }
bool
CDeviceNode::CanUninstall()
{
CONFIGRET cr;
cr = CM_Get_DevNode_Status_Ex(&m_Status,
&m_ProblemNumber,
m_DevInst,
0,
NULL);
if (cr == CR_SUCCESS)
{
return ((m_Status & DN_DISABLEABLE) != 0 &&
(m_Status & DN_ROOT_ENUMERATED) == 0);
}
return false;
}
bool
CDeviceNode::EnableDevice(
_In_ bool Enable,
_Out_ bool &NeedsReboot
)
{
bool Ret = false;
bool Canceled = false;
SetFlags(DI_NODI_DEFAULTACTION, 0);
SP_PROPCHANGE_PARAMS pcp;
pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
pcp.StateChange = (Enable ? DICS_ENABLE : DICS_DISABLE);
pcp.HwProfile = 0;
// check both scopes to make sure we can make the change
for (int i = 0; i < 2; i++)
{
// Check globally first, then check config specific
pcp.Scope = (i == 0) ? DICS_FLAG_GLOBAL : DICS_FLAG_CONFIGSPECIFIC;
if (SetupDiSetClassInstallParamsW(m_hDevInfo,
&m_DevinfoData,
&pcp.ClassInstallHeader,
sizeof(SP_PROPCHANGE_PARAMS)))
{
SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
m_hDevInfo,
&m_DevinfoData);
}
if (GetLastError() == ERROR_CANCELLED)
{
Canceled = true;
break;
}
}
if (Canceled == false)
{
pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
if (SetupDiSetClassInstallParamsW(m_hDevInfo,
&m_DevinfoData,
&pcp.ClassInstallHeader,
sizeof(SP_PROPCHANGE_PARAMS)))
{
SetupDiChangeState(m_hDevInfo, &m_DevinfoData);
}
if (Enable)
{
pcp.Scope = DICS_FLAG_GLOBAL;
if (SetupDiSetClassInstallParamsW(m_hDevInfo,
&m_DevinfoData,
&pcp.ClassInstallHeader,
sizeof(SP_PROPCHANGE_PARAMS)))
{
SetupDiChangeState(m_hDevInfo, &m_DevinfoData);
}
}
SetFlags(DI_PROPERTIES_CHANGE, 0);
NeedsReboot = ((GetFlags() & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
}
RemoveFlags(DI_NODI_DEFAULTACTION, 0);
return true;
}
DWORD
CDeviceNode::GetFlags(
)
{
SP_DEVINSTALL_PARAMS DevInstallParams;
DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
if (SetupDiGetDeviceInstallParamsW(m_hDevInfo,
&m_DevinfoData,
&DevInstallParams))
{
return DevInstallParams.Flags;
}
return 0;
}
bool
CDeviceNode::SetFlags(
_In_ DWORD Flags,
_In_ DWORD FlagsEx
)
{
SP_DEVINSTALL_PARAMS DevInstallParams;
DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
if (SetupDiGetDeviceInstallParamsW(m_hDevInfo,
&m_DevinfoData,
&DevInstallParams))
{
DevInstallParams.Flags |= Flags;
DevInstallParams.FlagsEx |= FlagsEx;
return SetupDiSetDeviceInstallParamsW(m_hDevInfo,
&m_DevinfoData,
&DevInstallParams);
}
return false;
}
bool
CDeviceNode::RemoveFlags(
_In_ DWORD Flags,
_In_ DWORD FlagsEx
)
{
SP_DEVINSTALL_PARAMS DevInstallParams;
DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
if (SetupDiGetDeviceInstallParamsW(m_hDevInfo,
&m_DevinfoData,
&DevInstallParams))
{
DevInstallParams.Flags &= ~Flags;
DevInstallParams.FlagsEx &= ~FlagsEx;
return SetupDiSetDeviceInstallParamsW(m_hDevInfo,
&m_DevinfoData,
&DevInstallParams);
}
return false;
}

View file

@ -4,6 +4,8 @@
class CDeviceNode : public CNode class CDeviceNode : public CNode
{ {
private: private:
SP_DEVINFO_DATA m_DevinfoData;
HDEVINFO m_hDevInfo;
DEVINST m_DevInst; DEVINST m_DevInst;
ULONG m_Status; ULONG m_Status;
ULONG m_ProblemNumber; ULONG m_ProblemNumber;
@ -22,13 +24,31 @@ public:
DEVINST GetDeviceInst() { return m_DevInst; } DEVINST GetDeviceInst() { return m_DevInst; }
int GetOverlayImage() { return m_OverlayImage; } int GetOverlayImage() { return m_OverlayImage; }
bool HasProblem() { return !!(m_ProblemNumber); } bool HasProblem();
bool IsHidden(); bool IsHidden();
bool CanDisable(); bool CanDisable();
bool IsDisabled(); bool IsDisabled();
bool IsStarted(); bool IsStarted();
bool IsInstalled(); bool IsInstalled();
bool CanInstall() { return TRUE; } // unimplemented bool CanUninstall();
bool CanUninstall() { return TRUE; } // unimplemented
bool EnableDevice(
_In_ bool Enable,
_Out_ bool &NeedsReboot
);
private:
bool SetFlags(
_In_ DWORD Flags,
_In_ DWORD FlagsEx
);
bool RemoveFlags(
_In_ DWORD Flags,
_In_ DWORD FlagsEx
);
DWORD GetFlags(
);
}; };

View file

@ -92,8 +92,7 @@ CDeviceView::Initialize()
} }
// Create the context menu and make properties the default item // Create the context menu and make properties the default item
m_hMenu = LoadMenuW(g_hInstance, MAKEINTRESOURCEW(IDR_POPUP)); m_hContextMenu = CreatePopupMenu();
m_hContextMenu = GetSubMenu(m_hMenu, 0);
SetMenuDefaultItem(m_hContextMenu, IDC_PROPERTIES, FALSE); SetMenuDefaultItem(m_hContextMenu, IDC_PROPERTIES, FALSE);
return !!(m_hTreeView); return !!(m_hTreeView);
@ -110,7 +109,7 @@ CDeviceView::Uninitialize()
ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA)); ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA));
} }
DestroyMenu(m_hMenu); DestroyMenu(m_hContextMenu);
return true; return true;
} }
@ -167,6 +166,18 @@ CDeviceView::OnContextMenu(
ScreenToClient(m_hTreeView, &pt) && ScreenToClient(m_hTreeView, &pt) &&
PtInRect(&rc, pt)) PtInRect(&rc, pt))
{ {
CNode *Node = GetSelectedNode();
if (Node && Node->HasProperties())
{
}
INT xPos = GET_X_LPARAM(lParam); INT xPos = GET_X_LPARAM(lParam);
INT yPos = GET_Y_LPARAM(lParam); INT yPos = GET_Y_LPARAM(lParam);
@ -291,6 +302,24 @@ CDeviceView::CanDisable(
return false; return false;
} }
bool
CDeviceView::EnableSelectedDevice(
_In_ bool Enable,
_Out_ bool &NeedsReboot
)
{
CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetSelectedNode());
if (Node)
{
if (Node->EnableDevice(Enable, NeedsReboot))
{
Refresh(m_ViewType, true, true);
return true;
}
}
return false;
}
// PRIVATE METHODS *******************************************/ // PRIVATE METHODS *******************************************/
@ -362,10 +391,10 @@ CDeviceView::GetNextClass(
0); 0);
if (cr != CR_SUCCESS) return false; if (cr != CR_SUCCESS) return false;
// Check for devices without a class // Check if this is the unknown class
if (IsEqualGUID(*ClassGuid, GUID_DEVCLASS_UNKNOWN)) if (IsEqualGUID(*ClassGuid, GUID_DEVCLASS_UNKNOWN))
{ {
// Get device info for all devices for all classes // Get device info for all devices
*hDevInfo = SetupDiGetClassDevsW(NULL, *hDevInfo = SetupDiGetClassDevsW(NULL,
NULL, NULL,
NULL, NULL,
@ -378,7 +407,6 @@ CDeviceView::GetNextClass(
NULL, NULL,
NULL, NULL,
DIGCF_PRESENT); DIGCF_PRESENT);
} }
return (hDevInfo != INVALID_HANDLE_VALUE); return (hDevInfo != INVALID_HANDLE_VALUE);

View file

@ -78,6 +78,12 @@ public:
bool IsDisabled( bool IsDisabled(
_In_ LPTV_ITEMW TvItem _In_ LPTV_ITEMW TvItem
); );
bool EnableSelectedDevice(
_In_ bool Enable,
_Out_ bool &NeedsReboot
);
bool SelDeviceIsStarted(); bool SelDeviceIsStarted();
bool SelDeviceIsInstalled(); bool SelDeviceIsInstalled();

View file

@ -507,7 +507,7 @@ CMainWindow::OnNotify(LPARAM lParam)
{ {
LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam; LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam;
UINT_PTR idButton = (UINT)lpttt->hdr.idFrom; UINT_PTR idButton = lpttt->hdr.idFrom;
switch (idButton) switch (idButton)
{ {
case IDC_PROPERTIES: case IDC_PROPERTIES:
@ -568,13 +568,19 @@ CMainWindow::OnCommand(WPARAM wParam,
case IDC_ENABLE_DRV: case IDC_ENABLE_DRV:
{ {
MessageBox(m_hMainWnd, L"Not yet implemented", L"Enable Driver", MB_OK); bool NeedsReboot;
if (m_DeviceView->EnableSelectedDevice(true, NeedsReboot) &&
NeedsReboot)
{
MessageBox(m_hMainWnd, L"Rebooting", L"Enable", MB_OK);
}
break; break;
} }
case IDC_DISABLE_DRV: case IDC_DISABLE_DRV:
{ {
MessageBox(m_hMainWnd, L"Not yet implemented", L"Disable Driver", MB_OK); bool NeedsReboot;
m_DeviceView->EnableSelectedDevice(false, NeedsReboot);
break; break;
} }