Page 1 of 1

disable/enable a device in device manager (Win10)

Posted: Fri Dec 18, 2020 2:23 am
by Balmung
Anyone a idea how to enable and disable a device in the device manager with PureBasic?

I have two special devices for the same USB hardware that i need to disable when i did not use it and of course than enable to use them (unplug is no option). I want to make this with a little Tool over a Tray Icon Menu beside the windows clock (bottom right).

The Hardware-IDs are always the same and known, if that helps.

I also found this older code that sounds like what i need but the needed header files are offline (404 at the download link).

viewtopic.php?f=5&t=65328

And also no example on RSBasics WinAPI side.

---------------

Edit: found this older code: viewtopic.php?f=13&t=50669

Also i found this side, it says you should use cfgmgr32.dll instead, so i changed my code to this:

https://docs.microsoft.com/en-us/window ... ble-device

Code: Select all

EnableExplicit

Define *F1, *F2, *F3
Define devhandle.l, id.s

If OpenLibrary(1,"cfgmgr32.dll")
  *F1 = GetFunction(1, "CM_Locate_DevNodeW")
  *F2 = GetFunction(1, "CM_Disable_DevNode")
  *F3 = GetFunction(1, "CM_Enable_DevNode")
  
  ;look in registry HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum
  ;to find Identifiers for PCI/USB ... Devices
  id.s = "USB\VID_045E&PID_0659&MI_03\8&23fc3de6&0&0003" ;sample USB id
  
  Debug CallFunctionFast(*F1, @devhandle, @id, 0)
  
  Debug CallFunctionFast(*F2 ,devhandle, 0) ;disable device
  ;Debug CallFunctionFast(*F3 ,devhandle, 0) ;enable device
  
  CloseLibrary(1)
EndIf
Edit 2: works now, you need Admin Rights for *F2/*F3.

Re: disable/enable a device in device manager?

Posted: Fri Dec 18, 2020 10:48 am
by BarryG
I can't test it, but did you try your code running with admin rights? A limited-rights app wouldn't be able to disable/enable devices.

Re: disable/enable a device in device manager?

Posted: Fri Dec 18, 2020 8:05 pm
by Balmung
Yes, makes badly no different.

Re: disable/enable a device in device manager?

Posted: Fri Dec 18, 2020 8:38 pm
by spikey
Result 30 = CR_INVALID_DEVICE_ID, 5 = CR_INVALID_DEVNODE, unsurprising after a CR_INVALID_DEVICE_ID.
In this case because you are presenting a Unicode string argument to an ASCII function - PB uses Unicode for strings since 5.50.

Try CM_Locate_DevNodeW instead of CM_Locate_DevNodeA, I think that should fix it:

Code: Select all

*F1 = GetFunction(1, "CM_Locate_DevNodeW")

Re: disable/enable a device in device manager?

Posted: Fri Dec 18, 2020 8:46 pm
by Balmung
Funny that i found out what the Error Codes mean at the same time you post it. Line 4508+ (https://github.com/tpn/winsdk-10/blob/m ... cfgmgr32.h)

And it works perfect now (i get 0 0 back), many thanks, now i can make a real program out of it. :D

I must say as i start searching for it i never expected it would be that easy, that is really not much code.

Btw, forgetting to run with Admin rights give you a 0 (CR_SUCCESS) and 51 (Hex 33 = CR_ACCESS_DENIED) back.

Re: disable/enable a device in device manager?

Posted: Sat Dec 19, 2020 3:09 pm
by spikey
Balmung wrote:And it works perfect now (i get 0 0 back), many thanks, now i can make a real program out of it. :D
You're welcome!
Balmung wrote:Btw, forgetting to run with Admin rights give you a 0 (CR_SUCCESS) and 51 (Hex 33 = CR_ACCESS_DENIED) back.
That's to be expected, everyone needs to be able to locate and query devices; otherwise you wouldn't be able to use any attached devices at all. Administrator equivalent status is required to modify the hardware configuration, however, so that action gets denied.

Re: disable/enable a device in device manager (Win10)

Posted: Sun Dec 20, 2020 12:29 am
by Balmung
Yes, it was more to post this for others that find this thread.

I struggle now to check if a device is enabled or disabled. :?:

Edit: found CM_Get_DevNode_Status https://docs.microsoft.com/en-us/window ... ode_status

Code: Select all

CM_Get_DevNode_Status(
    _Out_ PULONG        pulStatus,
    _Out_ PULONG        pulProblemNumber,
    _In_  DEVINST       dnDevInst,
    _In_  ULONG         ulFlags
    );
But it only give you a "Address of a location to receive status bit flags" and i don't know how i should use it. It is always the same when the device is off (25175040) and gives always the same other number when it is on (25174026). The second variable (also "Address of location...") pulProblemNumber gives always 22 when off and 0 when on, maybe i could also use this.

Or how must i use that right?

Edit2: Ok, the 22 matches the (Code 22) in the property window of the disabled device in the device manager. It seams i can really use this.

Re: disable/enable a device in device manager (Win10)

Posted: Mon Dec 21, 2020 3:45 pm
by spikey
If you're going to work with this sort of stuff much you will find downloading the Win 10 SDK helps (it's fairly large though - 4Gb of disk space once installed). Have a look at: https://developer.microsoft.com/en-us/w ... ws-10-sdk/

I'm not really sure how you are getting a result if you don't understand how the function works! Post your code so that we can see what you've done.

pulStatus and pulProblemNumber are _Out_ values. It's a method of returning multiple values from a single function call, otherwise things would get complicated.
This means that you supply a pointer to a variable as an argument to the function and the function sets the value of this variable before it returns. The target variable must be the size expected by the function. In this case 'pul' means 'pointer to unsigned long'.
As PB doesn't have specific unsigned variable types, use a long.

In this case three values are returned from one function call; the return value from the function is an error code if things go wrong and the values of pulStatus and pulProblemNumber.

The return value should be CR_SUCCESS, if it isn't the function call ran into trouble and the values of pulStatus and pulProblemNumber may be unreliable or invalid.
If it isn't CR_SUCCESS, the value describes the trouble. CR_ enumeration values are defined in 'cfgmgr32.h' in the 'Include' subfolder of the SDK.

pulStatus doesn't really make any sense as a single value, particularly in decimal format.
Its value is set at the bit level. This means that each individual bit in the value has its own meaning.
You need to examine all the bits to determine the full meaning (or at least all the bits that are relevant to your purpose anyway.)
Again the bit values are defined in 'cfg.h' in the SDK. You need to study this section carefully as the meaning of bits has changed in various versions of Windows.

If the bit DN_HAS_PROBLEM is set in pulStatus then pulProblemNumber will have been set by the function.

pulProblemNumber is a CM_PROB enumeration value as defined in 'cfg.h'
In this case 22 ($16 in hex) is CM_PROB_DISABLED.

The way to check for a device being disabled then is:
1) Check for CR_SUCCESS from CM_Get_DevNode_Status
2) Check if the bit DN_HAS_PROBLEM is set in pulStatus.
3) Check if the value of pulProblemNumber is CM_PROB_DISABLED.
If these three things are true then the device is disabled.

Checking if a device is enabled is more complex - just how 'enabled' will you require the result to be?
It's potentially more complicated than checking if DN_HAS_PROBLEM is not set and pulProblemNumber <> CM_PROB_DISABLED, depending on the specifics of the device in question. A device may not be fully operational even with these values, for example if a driver didn't load or a required service isn't running...

Re: disable/enable a device in device manager (Win10)

Posted: Mon Dec 21, 2020 6:11 pm
by Balmung
Thx for explaining.

Code: Select all

#define DN_ROOT_ENUMERATED (0x00000001) // Was enumerated by ROOT
#define DN_DRIVER_LOADED   (0x00000002) // Has Register_Device_Driver
#define DN_ENUM_LOADED     (0x00000004) // Has Register_Enumerator
#define DN_STARTED         (0x00000008) // Is currently configured
#define DN_MANUAL          (0x00000010) // Manually installed
#define DN_NEED_TO_ENUM    (0x00000020) // May need reenumeration
#define DN_NOT_FIRST_TIME  (0x00000040) // Has received a config
#define DN_HARDWARE_ENUM   (0x00000080) // Enum generates hardware ID
#define DN_LIAR            (0x00000100) // Lied about can reconfig once
#define DN_HAS_MARK        (0x00000200) // Not CM_Create_DevInst lately
#define DN_HAS_PROBLEM     (0x00000400) // Need device installer
#define DN_FILTERED        (0x00000800) // Is filtered
#define DN_MOVED           (0x00001000) // Has been moved
#define DN_DISABLEABLE     (0x00002000) // Can be disabled
#define DN_REMOVABLE       (0x00004000) // Can be removed
#define DN_PRIVATE_PROBLEM (0x00008000) // Has a private problem
#define DN_MF_PARENT       (0x00010000) // Multi function parent
#define DN_MF_CHILD        (0x00020000) // Multi function child
#define DN_WILL_BE_REMOVED (0x00040000) // DevInst is being removed
[/size]
That are the bits.

Code: Select all

#define CM_PROB_NOT_CONFIGURED             (0x00000001)   // no config for device
#define CM_PROB_DEVLOADER_FAILED           (0x00000002)   // service load failed
#define CM_PROB_OUT_OF_MEMORY              (0x00000003)   // out of memory
#define CM_PROB_ENTRY_IS_WRONG_TYPE        (0x00000004)   //
#define CM_PROB_LACKED_ARBITRATOR          (0x00000005)   //
#define CM_PROB_BOOT_CONFIG_CONFLICT       (0x00000006)   // boot config conflict
#define CM_PROB_FAILED_FILTER              (0x00000007)   //
#define CM_PROB_DEVLOADER_NOT_FOUND        (0x00000008)   // Devloader not found
#define CM_PROB_INVALID_DATA               (0x00000009)   // Invalid ID
#define CM_PROB_FAILED_START               (0x0000000A)   //
#define CM_PROB_LIAR                       (0x0000000B)   //
#define CM_PROB_NORMAL_CONFLICT            (0x0000000C)   // config conflict
#define CM_PROB_NOT_VERIFIED               (0x0000000D)   //
#define CM_PROB_NEED_RESTART               (0x0000000E)   // requires restart
#define CM_PROB_REENUMERATION              (0x0000000F)   //
#define CM_PROB_PARTIAL_LOG_CONF           (0x00000010)   //
#define CM_PROB_UNKNOWN_RESOURCE           (0x00000011)   // unknown res type
#define CM_PROB_REINSTALL                  (0x00000012)   //
#define CM_PROB_REGISTRY                   (0x00000013)   //
#define CM_PROB_VXDLDR                     (0x00000014)   // WINDOWS 95 ONLY
#define CM_PROB_WILL_BE_REMOVED            (0x00000015)   // devinst will remove
#define CM_PROB_DISABLED                   (0x00000016)   // devinst is disabled
#define CM_PROB_DEVLOADER_NOT_READY        (0x00000017)   // Devloader not ready
#define CM_PROB_DEVICE_NOT_THERE           (0x00000018)   // device doesn't exist
#define CM_PROB_MOVED                      (0x00000019)   //
#define CM_PROB_TOO_EARLY                  (0x0000001A)   //
#define CM_PROB_NO_VALID_LOG_CONF          (0x0000001B)   // no valid log config
#define CM_PROB_FAILED_INSTALL             (0x0000001C)   // install failed
#define CM_PROB_HARDWARE_DISABLED          (0x0000001D)   // device disabled
#define CM_PROB_CANT_SHARE_IRQ             (0x0000001E)   // can't share IRQ
#define CM_PROB_FAILED_ADD                 (0x0000001F)   // driver failed add
#define CM_PROB_DISABLED_SERVICE           (0x00000020)   // service's Start = 4
#define CM_PROB_TRANSLATION_FAILED         (0x00000021)   // resource translation failed
#define CM_PROB_NO_SOFTCONFIG              (0x00000022)   // no soft config
#define CM_PROB_BIOS_TABLE                 (0x00000023)   // device missing in BIOS table
#define CM_PROB_IRQ_TRANSLATION_FAILED     (0x00000024)   // IRQ translator failed
#define CM_PROB_FAILED_DRIVER_ENTRY        (0x00000025)   // DriverEntry() failed.
#define CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD (0x00000026)   // Driver should have unloaded.
#define CM_PROB_DRIVER_FAILED_LOAD         (0x00000027)   // Driver load unsuccessful.
#define CM_PROB_DRIVER_SERVICE_KEY_INVALID (0x00000028)   // Error accessing driver's service key
#define CM_PROB_LEGACY_SERVICE_NO_DEVICES  (0x00000029)   // Loaded legacy service created no devices
#define CM_PROB_DUPLICATE_DEVICE           (0x0000002A)   // Two devices were discovered with the same name
#define CM_PROB_FAILED_POST_START          (0x0000002B)   // The drivers set the device state to failed
#define CM_PROB_HALTED                     (0x0000002C)   // This device was failed post start via usermode
#define CM_PROB_PHANTOM                    (0x0000002D)   // The devinst currently exists only in the registry
#define CM_PROB_SYSTEM_SHUTDOWN            (0x0000002E)   // The system is shutting down
#define CM_PROB_HELD_FOR_EJECT             (0x0000002F)   // The device is offline awaiting removal
#define CM_PROB_DRIVER_BLOCKED             (0x00000030)   // One or more drivers is blocked from loading
#define CM_PROB_REGISTRY_TOO_LARGE         (0x00000031)   // System hive has grown too large
#define CM_PROB_SETPROPERTIES_FAILED       (0x00000032)   // Failed to apply one or more registry properties  
#define CM_PROB_WAITING_ON_DEPENDENCY      (0x00000033)   // Device is stalled waiting on a dependency to start
#define CM_PROB_UNSIGNED_DRIVER            (0x00000034)   // Failed load driver due to unsigned image.
#define CM_PROB_USED_BY_DEBUGGER           (0x00000035)   // Device is being used by kernel debugger
#define CM_PROB_DEVICE_RESET               (0x00000036)   // Device is being reset
#define CM_PROB_CONSOLE_LOCKED             (0x00000037)   // Device is blocked while console is locked
#define CM_PROB_NEED_CLASS_CONFIG          (0x00000038)   // Device needs extended class configuration to start
[/size]

I used the other code and made that out of it 2 days ago, it is not finished yet because the procedure did nothing return yet:

Code: Select all

Procedure CheckDevice(id.s)
  
  Define *F1, *F2
  Define devhandle.l, Status.l, ProbNumb.l, CR
  
  If OpenLibrary(1,"cfgmgr32.dll")
    *F1 = GetFunction(1, "CM_Locate_DevNodeW")
    *F2 = GetFunction(1, "CM_Get_DevNode_Status")
    
    CR = CallFunctionFast(*F1, @devhandle, @id, 0)
    If CR = 0
      CR = CallFunctionFast(*F2, @Status, @ProbNumb, devhandle, 0)
      If CR > 0 : Debug "*F2 CR: "+Hex(CR) +" ("+Str(CR)+")" : EndIf
      Debug Status
      Debug ProbNumb ; <- give (Code 22) when disabled and 0 when enabled
    EndIf
    
    CloseLibrary(1)
  Else
    Debug "Can not open CfgMgr32.dll"
  EndIf
  
EndProcedure
That code should only check for the app if the device is disabled, so the app could use that info for his things like deactivate the "Start Device" or "Stop Device" button. It is not there to have the full control over the device or something, if there is an error a other official app that starts with the device, as soon it is enabled, show this.

So what i only need to know is simply said "Is the Device disabled or not?".

Die 22 ist übrigens kein Zufall, diese Codes stimmen mit den Error Codes im Geräte Manager überein: https://support.microsoft.com/de-de/hel ... in-windows

Re: disable/enable a device in device manager (Win10)

Posted: Wed Dec 23, 2020 8:11 pm
by spikey
Balmung wrote:Die 22 ist übrigens kein Zufall, diese Codes stimmen mit den Error Codes im Geräte Manager überein:
I know, I'm just checking. You didn't originally post the function call you were using and I was just making sure you've used it correctly. You have - the variables are the correct size and you passed pointers to them properly.
Balmung wrote:So what i only need to know is simply said "Is the Device disabled or not?".
As I said in my previous post, the way to check for a device being disabled is:
1) Check for CR_SUCCESS from CM_Get_DevNode_Status
2) Check if the bit DN_HAS_PROBLEM is set in pulStatus.
3) Check if the value of pulProblemNumber is CM_PROB_DISABLED.
If these three things are true then the device is disabled.
If you get CR_SUCCESS but DN_HAS_PROBLEM is not set in pulStatus and pulProblemNumber is not CM_PROB_DISABLED, then it's not disabled.

In your case you could do something like this:

Code: Select all

#DN_HAS_PROBLEM = $00000400
#CM_PROB_DISABLED = $00000016

; This line checks the Status value to see if the bit DN_HAS_PROBLEM is set.
If (Status & #DN_HAS_PROBLEM = #DN_HAS_PROBLEM)
  If ProbNumb = #CM_PROB_DISABLED
    Debug "Device is disabled."
  EndIf
  
Else
  Debug "Device is ok."
  
EndIf

Re: disable/enable a device in device manager (Win10)

Posted: Wed Dec 23, 2020 11:17 pm
by Balmung
Thanks, that helped to make my code better.