Windows - Power management tab

Started by Pierre Bellisle, June 10, 2015, 09:29:48 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Pierre Bellisle

Hey,

In Windows "Device Manager" looking at the device properties,
some devices have a "Power management" tab. Under this tab a checkbox named
"Allow the computer to turn off this device to save power" can be found.

I'd like to change this option programmatically.
Seems that WMI should be able to do it.

Using José utility "WMi wrappers generator" TB_WMIGN I did produce some PBCC 4.04 code
that can read the "\root\WMI\MSPower_DeviceEnable" vEnable device status.

I tried to flip some device state with no success, any idea?

Thanks

Pierre
#COMPILE EXE '#CC 4.04#
#DIM ALL
#INCLUDE "Win32Api.inc"

UNION VARIANTDATA 'Thank to José Roca
  bVal      AS BYTE            'VT_UI1
  iVal      AS INTEGER         'VT_I2
  lVal      AS LONG            'VT_I4
  fltVal    AS SINGLE          'VT_R4
  dblVal    AS DOUBLE          'VT_R8
  boolVal   AS INTEGER         'VT_BOOL
  scode     AS LONG            'VT_ERROR
  cyVal     AS LONG            'VT_CY
  date      AS DOUBLE          'VT_DATE
  bstrVal   AS LONG            'VT_BSTR
  punkVal   AS DWORD           'VT_UNKNOWN
  pdispVal  AS DWORD           'VT_DISPATCH
  parray    AS DWORD           'VT_ARRAY|*
  pbVal     AS BYTE POINTER    'VT_BYREF|VT_UI1
  piVal     AS INTEGER POINTER 'VT_BYREF|VT_I2
  plVal     AS LONG POINTER    'VT_BYREF|VT_I4
  pfltVal   AS SINGLE POINTER  'VT_BYREF|VT_R4
  pdblVal   AS DOUBLE POINTER  'VT_BYREF|VT_R8
  pboolVal  AS INTEGER POINTER 'VT_BYREF|VT_BOOL
  pscode    AS LONG POINTER    'VT_BYREF|VT_ERROR
  pcyVal    AS LONG POINTER    'VT_BYREF|VT_CY
  pdate     AS DOUBLE POINTER  'VT_BYREF|VT_DATE
  pbstrVal  AS LONG POINTER    'VT_BYREF|VT_BSTR
  ppunkVal  AS DWORD POINTER   'VT_BYREF|VT_UNKNOWN
  ppdispVal AS DWORD POINTER   'VT_BYREF|VT_DISPATCH
  psArray   AS DWORD POINTER   'VT_ARRAY|*
  pVariant  AS DWORD POINTER   'VT_BYREF|VT_VARIANT
  pByRef    AS DWORD           'Generic ByRef
END UNION

'For backwards compatibility, size = 16 bytes
TYPE VARIANTAPIjr DWORD FILL
  vt         AS WORD 'VARTYPE
  wReserved1 AS WORD
  wReserved2 AS WORD
  wReserved3 AS WORD
  vd         AS VARIANTDATA 'VARIANTDATA_UNION
END TYPE

DECLARE FUNCTION CreateBindCtx LIB "OLE32.DLL" ALIAS "CreateBindCtx" _
(BYVAL reserved AS DWORD, BYREF ppbc AS ANY) AS LONG

DECLARE FUNCTION MkParseDisplayNameEx LIB "URLMON.DLL" ALIAS "MkParseDisplayNameEx" _
(BYVAL pbc AS DWORD, BYVAL szUserName AS STRING, _
BYREF pcchEaten AS DWORD, BYREF ppmk AS DWORD) AS LONG
'_____________________________________________________________________________

FUNCTION WmiRelease(BYVAL pthis AS DWORD POINTER) AS DWORD
LOCAL DWRESULT AS DWORD

IF pthis THEN
   CALL DWORD @@pthis[2] USING WmiRelease(pthis) TO DWRESULT
   FUNCTION = DWRESULT
END IF

END FUNCTION
'_____________________________________________________________________________

FUNCTION WmiEnum_Next(BYVAL pthis AS DWORD POINTER, BYVAL celt AS DWORD, _
                      BYVAL rgelt AS DWORD, BYREF pceltFetched AS DWORD) AS LONG
LOCAL HRESULT AS LONG

IF pthis THEN
   CALL DWORD @@pthis[3] USING WmiEnum_Next(pthis, celt, rgelt, pceltFetched) TO HRESULT
   FUNCTION = HRESULT
END IF

END FUNCTION
'_____________________________________________________________________________

FUNCTION WmiEnum_NextItem(BYVAL pthis AS DWORD POINTER, BYREF elt AS VARIANT) AS LONG
LOCAL HRESULT AS LONG

IF pthis THEN
   CALL DWORD @@pthis[3] USING WmiEnum_Next(pthis, 1, VARPTR(elt), BYVAL %NULL) TO HRESULT
   FUNCTION = HRESULT
END IF

END FUNCTION
'_____________________________________________________________________________

FUNCTION WmiMoniker_BindToObject(BYVAL pthis AS DWORD POINTER, BYVAL pbc AS DWORD, _
BYVAL pmkToLeft AS DWORD, BYREF riidResult AS GUID, BYREF ppvResult AS DWORD) AS LONG

LOCAL HRESULT AS LONG

IF pthis THEN
   CALL DWORD @@pthis[8] USING WmiMoniker_BindToObject(pthis, pbc, pmkToLeft, _
                                                       riidResult, ppvResult) TO HRESULT
   FUNCTION = HRESULT
END IF

END FUNCTION
'_____________________________________________________________________________

FUNCTION WmiGetObject(BYVAL strDisplayName AS STRING, BYREF vObj AS VARIANT) AS LONG
LOCAL hr            AS LONG  'HRESULT
LOCAL pbc           AS DWORD 'Pointer to the new bind context
LOCAL pmk           AS DWORD 'IMoniker interface pointer
LOCAL pObj          AS DWORD 'Interface pointer
LOCAL pcchEaten     AS DWORD 'Number of characters successfully parsed
LOCAL IID_IDispatch AS GUID  'IDispatch inyterface identifier
LOCAL pvObj         AS VARIANTAPIjr POINTER 'Pointer to a VARIANTAPI structure

IID_IDispatch = GUID$("{00020400-0000-0000-c000-000000000046}")

hr = CreateBindCtx(0, pbc) 'Creates a new bind context.
IF hr = %S_OK AND pbc <> 0 THEN
   'Converts a string into a moniker that identifies the object named by the string.
   strDisplayName = UCODE$(strDisplayName & $NUL)
   hr             = MkParseDisplayNameEx(pbc, strDisplayName, pcchEaten, pmk)
   IF hr = %S_OK AND pmk <> 0 THEN
     'Uses the moniker to bind to the object it identifies.
     'The binding process involves finding the object, putting it into the running
     'state if necessary, and supplying the caller with a pointer to a specified
     'interface on the identified object.
     hr = WmiMoniker_BindToObject(pmk, pbc, %NULL, IID_IDispatch, pObj)
     IF hr = %S_OK THEN
       'Makes a dispatch variant containing the reference to the object.
       'Note: No need to call AddRef because IMoniker_BindToObject has
       'already called it. Just don't release pObj here.
        vObj               = EMPTY        'Make sure is empty to avoid memory leaks
        pvObj              = VARPTR(vObj) 'Get the VARIANT address
        @pvObj.vt          = %VT_DISPATCH 'Mark it as containing a dispatch variable
        @pvObj.vd.pdispVal = pObj         'Set the dispatch pointer address
     END IF
     WmiRelease(pmk)
   END IF
   WmiRelease(pbc)
END IF

FUNCTION = hr

END FUNCTION
'_____________________________________________________________________________

FUNCTION Wmi_NewEnum(BYVAL pthis AS DWORD POINTER, BYREF ppenum AS DWORD) AS LONG
LOCAL HRESULT AS LONG

IF pthis THEN
   CALL DWORD @@pthis[7] USING Wmi_NewEnum(pthis, ppenum) TO HRESULT
   FUNCTION = HRESULT
END IF

END FUNCTION
'_____________________________________________________________________________

SUB MKVTBOOL(BYREF vVar AS VARIANT, BYVAL fBool AS INTEGER)
LOCAL pv AS VARIANTAPIjr POINTER 'Pointer to a VARIANTAPI structure

vVar   = EMPTY           'Make sure is empty to avoid memory leaks
pv     = VARPTR(vVar)    'Get the VARIANT address
@pv.vt = %VT_BOOL        'Mark it as containing a boolean value
IF fBool THEN fBool = -1 'Make sure is 0 or -1
@pv.vd.boolVal = fBool   'Set the boolean value

END SUB
'_____________________________________________________________________________

SUB WMI_MSPower_DeviceEnable(OPTIONAL BYVAL strComputer AS STRING)
LOCAL hr        AS LONG     'HRESULT
LOCAL oServices AS DISPATCH 'Services object
LOCAL vServices AS VARIANT  'Services object reference
LOCAL oItems    AS DISPATCH 'Generic collection object
LOCAL vItems    AS VARIANT  'Generic collection object reference
LOCAL oItem     AS DISPATCH 'Generic item object
LOCAL vItem     AS VARIANT  'Generic item object reference
LOCAL penum     AS DWORD    'Generic collection's enumerator reference
LOCAL vCount    AS VARIANT  'Number of items in the collection
LOCAL vQuery    AS VARIANT  'Query string
LOCAL vRes      AS VARIANT  'General purpose variant
LOCAL i         AS LONG     'Loop counter
LOCAL zBuffer   AS ASCIIZ * 512

'Variants to store the property values
LOCAL vActive AS VARIANT       'Boolean value
LOCAL vEnable AS VARIANT       'Boolean value
LOCAL vInstanceName AS VARIANT 'String

'Connect to WMI using a moniker
IF LEN(strComputer) = 0 THEN strComputer = "."
hr = WmiGetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
                   strComputer & "\root\WMI", vServices)
IF hr <> %S_OK THEN GOTO Terminate
SET oServices = vServices
vServices = EMPTY
IF ISFALSE ISOBJECT(oServices) THEN GOTO Terminate

'Execute a query to get a reference to the collection of objects
vQuery = "SELECT * FROM MSPower_DeviceEnable"
OBJECT CALL oServices.ExecQuery(vQuery) TO vItems

IF ISTRUE OBJRESULT THEN GOTO Terminate
SET oItems = vItems
vItems = EMPTY
IF ISFALSE ISOBJECT(oItems) THEN GOTO Terminate

'Retrieve the number of items in the collection
OBJECT GET oItems.Count TO vCount

'Retrieve a reference to the collection's enumerator
hr = Wmi_NewEnum(OBJPTR(oItems), penum)
IF hr <> %S_OK OR penum = %NULL THEN GOTO Terminate

'Iterate through the collection of objects.
FOR i = 1 TO VARIANT#(vCount)

   'Retrieve a reference to the next object in the collection
   hr = WmiEnum_NextItem(penum, vItem)
   IF hr <> %S_OK THEN EXIT FOR
   SET oItem = vItem
   vItem     = EMPTY
   IF ISFALSE ISOBJECT(oItem) THEN EXIT FOR

   'Retrieve the values of the properties

   OBJECT GET oItem.InstanceName TO vInstanceName
   zBuffer = VARIANT$(vInstanceName)
   CharToOem(zBuffer, zBuffer)
   PRINT "vInsName " & zBuffer

   OBJECT GET oItem.Enable TO vEnable
   PRINT "vEnable " & STR$(VARIANT#(vEnable) AND 1) 'It's read/write

   OBJECT GET oItem.Active TO vActive
   PRINT "vActive " & STR$(VARIANT#(vActive) AND 1) 'It's read-only

   IF zBuffer = "USB\VID_08E6&PID_3437\D2880DA3_0" THEN 'Replace with a valid device for your PC
     PRINT "Replace with a valid device for your PC"
     PRINT "Device found"
     IF(VARIANT#(vEnable) AND 1) = 0 THEN '0x180000
       COLOR 11
       PRINT "Allow the computer to turn off this device to save power: Yes"
       PRINT "Flipping it to No"
       MKVTBOOL(vEnable, %TRUE)
     ELSE '0x18FFFF
       COLOR 12
       PRINT "Allow the computer to turn off this device to save power: No"
       PRINT "Flipping it to Yes"
       MKVTBOOL(vEnable, %FALSE)
     END IF
     PRINT "Run again to see change..."
     COLOR 7
     'Need "Run as Admin"
     OBJECT LET oItem.Enable = vEnable
     OBJECT CALL oItem.Put_
   END IF

   PRINT

   SET oItem = NOTHING 'Release the object
NEXT

WmiRelease(penum) 'Release the collection enumerator
IF ISOBJECT(oItems) THEN SET oItems = NOTHING ''Release the collection object

Terminate:
IF ISOBJECT(oServices) THEN SET oServices = NOTHING 'Release the Services object

END SUB
'_____________________________________________________________________________

FUNCTION PBMAIN

WMI_MSPower_DeviceEnable

MOUSE ON : MOUSE 3, UP : PRINT : PRINT "Strike any key or click..." : WAITKEY$

END FUNCTION
'_____________________________________________________________________________
'

José Roca

I don't find documentation about this class in MSDN. What I have found are some scripts and they call the Put method after changing the Enable value.

Pierre Bellisle

#2
Yep,
works like a charm now.

Above code updated. Need to be "Run as Admin".
To try, put a valid device name for your PC.

Thank...   

Pierre