[DEVMGR]
authorGed Murphy <gedmurphy@reactos.org>
Thu, 25 Jun 2015 18:59:23 +0000 (18:59 +0000)
committerGed Murphy <gedmurphy@reactos.org>
Thu, 25 Jun 2015 18:59:23 +0000 (18:59 +0000)
- 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

reactos/dll/win32/devmgr/devmgmt/DeviceNode.cpp
reactos/dll/win32/devmgr/devmgmt/DeviceNode.h
reactos/dll/win32/devmgr/devmgmt/DeviceView.cpp
reactos/dll/win32/devmgr/devmgmt/DeviceView.h
reactos/dll/win32/devmgr/devmgmt/MainWindow.cpp

index 000da62..31f7d1e 100644 (file)
@@ -22,10 +22,12 @@ CDeviceNode::CDeviceNode(
     m_ProblemNumber(0),
     m_OverlayImage(0)
 {
+    ZeroMemory(&m_DevinfoData, sizeof(SP_DEVINFO_DATA));
 }
 
 CDeviceNode::~CDeviceNode()
 {
+    SetupDiDestroyDeviceInfoList(m_hDevInfo);
 }
 
 bool
@@ -37,6 +39,7 @@ CDeviceNode::SetupNode()
 
     //    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)
@@ -64,6 +67,23 @@ CDeviceNode::SetupNode()
     if (m_DeviceId == NULL)
         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
     cr = CM_Get_DevNode_Status_Ex(&m_Status,
                                   &m_ProblemNumber,
@@ -145,6 +165,22 @@ CDeviceNode::SetupNode()
     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
 CDeviceNode::IsHidden()
@@ -230,4 +266,155 @@ CDeviceNode::IsInstalled()
     }
 
     return false;
-}
\ No newline at end of file
+}
+
+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;
+}
+
+
index 2b0ad42..8e559d4 100644 (file)
@@ -4,6 +4,8 @@
 class CDeviceNode : public CNode
 {
 private:
+    SP_DEVINFO_DATA m_DevinfoData;
+    HDEVINFO m_hDevInfo;
     DEVINST m_DevInst;
     ULONG m_Status;
     ULONG m_ProblemNumber;
@@ -22,13 +24,31 @@ public:
     DEVINST GetDeviceInst() { return m_DevInst; }
     int GetOverlayImage() { return m_OverlayImage; }
 
-    bool HasProblem() { return !!(m_ProblemNumber); }
+    bool HasProblem();
     bool IsHidden();
     bool CanDisable();
     bool IsDisabled();
     bool IsStarted();
     bool IsInstalled();
-    bool CanInstall() { return TRUE; } // unimplemented
-    bool CanUninstall() { return TRUE; } // unimplemented
+    bool CanUninstall();
+
+    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(
+        );
 };
 
index 52dd464..e956eb5 100644 (file)
@@ -92,8 +92,7 @@ CDeviceView::Initialize()
     }
 
     // Create the context menu and make properties the default item
-    m_hMenu = LoadMenuW(g_hInstance, MAKEINTRESOURCEW(IDR_POPUP));
-    m_hContextMenu = GetSubMenu(m_hMenu, 0);
+    m_hContextMenu = CreatePopupMenu();
     SetMenuDefaultItem(m_hContextMenu, IDC_PROPERTIES, FALSE);
 
     return !!(m_hTreeView);
@@ -110,7 +109,7 @@ CDeviceView::Uninitialize()
         ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA));
     }
 
-    DestroyMenu(m_hMenu);
+    DestroyMenu(m_hContextMenu);
 
     return true;
 }
@@ -167,6 +166,18 @@ CDeviceView::OnContextMenu(
             ScreenToClient(m_hTreeView, &pt) &&
             PtInRect(&rc, pt))
         {
+
+            CNode *Node = GetSelectedNode();
+            if (Node && Node->HasProperties())
+            {
+
+            }
+
+
+
+
+
+
             INT xPos = GET_X_LPARAM(lParam);
             INT yPos = GET_Y_LPARAM(lParam);
 
@@ -291,6 +302,24 @@ CDeviceView::CanDisable(
     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 *******************************************/
 
@@ -362,10 +391,10 @@ CDeviceView::GetNextClass(
                               0);
     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))
     {
-        // Get device info for all devices for all classes
+        // Get device info for all devices
         *hDevInfo = SetupDiGetClassDevsW(NULL,
                                          NULL,
                                          NULL,
@@ -378,7 +407,6 @@ CDeviceView::GetNextClass(
                                          NULL,
                                          NULL,
                                          DIGCF_PRESENT);
-        
     }
 
     return (hDevInfo != INVALID_HANDLE_VALUE);
index 485386d..05aa8d7 100644 (file)
@@ -78,6 +78,12 @@ public:
     bool IsDisabled(
         _In_ LPTV_ITEMW TvItem
         );
+
+    bool EnableSelectedDevice(
+        _In_ bool Enable,
+        _Out_ bool &NeedsReboot
+        );
+
     bool SelDeviceIsStarted();
     bool SelDeviceIsInstalled();
 
index ab00b6f..d1fe131 100644 (file)
@@ -507,7 +507,7 @@ CMainWindow::OnNotify(LPARAM lParam)
         {
              LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam;
 
-            UINT_PTR idButton = (UINT)lpttt->hdr.idFrom;
+            UINT_PTR idButton = lpttt->hdr.idFrom;
             switch (idButton)
             {
                 case IDC_PROPERTIES:
@@ -568,13 +568,19 @@ CMainWindow::OnCommand(WPARAM wParam,
 
         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;
         }
 
         case IDC_DISABLE_DRV:
         {
-            MessageBox(m_hMainWnd, L"Not yet implemented", L"Disable Driver", MB_OK);
+            bool NeedsReboot;
+            m_DeviceView->EnableSelectedDevice(false, NeedsReboot);
             break;
         }