Search code examples
c++wmidevice-driverdevice-managersetupapi

How to know if a device has been explicitly been disabled by user?


Using device manager a user can explicitly enable/disable a device, as can be seen in the following image.

enter image description here

For a given device I want to know if it's currently in a user disabled/enabled state.

I have tried the following approaches

  1. CM_Get_DevNode_Status(&status, &problem, data.DevInst, 0); I was hoping that presence of DN_STARTED, or DN_DRIVER_LOADED would tell me that. But these can be zero even when a driver is being loaded/unloaded by the OS, when the device connects/disconnects. For example, a device which is enabled, and for which driver is loaded. DN_STARTED will be 1, but when we disconnect device it is set to zero before the device's entry is removed from device manager.
  2. SetupDiGetDeviceRegistryProperty(..., SPDRP_INSTALL_STATE, ...) I though a state of CM_INSTALL_STATE_INSTALLED should mean that the device is enabled. But the function returns this state even for disabled devices.
  3. Using WMI I was able to get the required information, but I used wmi in PowerShell. I do not want to use wmi, as it is quite difficult to implement in native c++. I used the following query.

    Select Name, Availability, ConfigManagerErrorCode, ConfigManagerUserConfig from Win32_PnPEntity where Name = 'NVIDIA Quadro M1000M'

ConfigManagerErrorCode in above query, if set to 22, means that device has been disabled, 21 means that windows is removing the device

I am looking for a non wmi solution.


Solution

  • The information can be obtained from a device's problem code. There are two ways which I could find to get it.

    1. Use SetupDiGetDeviceProperty() to query DEVPKEY_Device_ProblemCode.
    2. Use CM_Get_DevNode_Status() the problem code will be present in the second argument after the call.

    A problem code of 22 (CM_PROB_DISABLED) means that the device has been explicitly disabled by a user by either using device manager, or other such utility.

    Sample code

    #include "stdafx.h"
    #include <Windows.h>
    #include <SetupAPI.h>
    #include <Cfgmgr32.h>
    #include <devguid.h>
    #include <initguid.h>
    #include "devpkey.h"
    #include <algorithm>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        HDEVINFO hDevInfo = ::SetupDiGetClassDevs(&GUID_DEVCLASS_DISPLAY, NULL, NULL, 0); //only getting for GPUs on the machine
    
        if (INVALID_HANDLE_VALUE != hDevInfo)
        {
            SP_DEVINFO_DATA data;
            data.cbSize = (DWORD)sizeof(data);
    
            for (unsigned int nIndex = 0; ::SetupDiEnumDeviceInfo(hDevInfo, nIndex, &data); nIndex++)
            {
                ULONG status = 0, problem = 0;
                CONFIGRET cr = ::CM_Get_DevNode_Status(&status, &problem, data.DevInst, 0); //after the call 'problem' variable will have the problem code
                if (CR_SUCCESS == cr)
                {
                    cout << " problem " << problem <<endl;
                    if(problem == CM_PROB_DISABLED)
                    { /*Do Something*/ }
    
                    DEVPROPTYPE propertyType;
                    const DWORD propertyBufferSize = 100;
                    BYTE propertyBuffer[propertyBufferSize];
                    std::fill(begin(propertyBuffer), end(propertyBuffer), BYTE(0));
                    DWORD requiredSize = 0;
    
                    if (SetupDiGetDeviceProperty(hDevInfo, &data, &DEVPKEY_Device_ProblemCode, &propertyType, propertyBuffer, propertyBufferSize, &requiredSize, 0)) //after the call 'propertyBuffer' will have error codes
                    {
                        unsigned long deviceProblemCode = *((unsigned long*)propertyBuffer);
                        cout << " deviceProblemCode " << deviceProblemCode << endl;
                    if(problem == CM_PROB_DISABLED)
                    { /*Do Something*/ }
    
                    }
                }
            }
        }
        return 0;
    }
    

    Sample Output

    problem 0
    deviceProblemCode 0
    problem 22
    deviceProblemCode 22
    

    In the question it can be seen that Intel(R) HD Graphics 530 was enabled, and NVIDIA Quadro M1000M was disabled. Hence in the output we got a problem code of 0, and a problem code of 22 (CM_PROB_DISABLED).