Apparently, PyWin32 doesn't wrap PowerRegisterForEffectivePowerModeNotifications (as a side note, a little while ago I added support for GetSystemPowerStatus: [GitHub]: mhammond/pywin32 - Add GetSystemPowerStatus wrapper).
The (an) alternative is using [Python.Docs]: ctypes - A foreign function library for Python (there's a lot of boilerplate code required).
code00.py:
#!/usr/bin/env python
import ctypes as cts
import ctypes.wintypes as wts
import enum
import sys
import time
HRESULT = cts.c_long
IntPtr = cts.POINTER(cts.c_int)
VoidPtrPtr = cts.POINTER(cts.c_void_p)
EffectivePowerModeCallback = cts.WINFUNCTYPE(None, cts.c_int, cts.c_void_p)
EFFECTIVE_POWER_MODE_V1 = 0x00000001
EFFECTIVE_POWER_MODE_V2 = 0x00000002
ERROR_SUCCESS = 0
class EffectivePowerMode(enum.IntEnum):
BatterySaver = 0
BetterBattery = enum.auto()
Balanced = enum.auto()
HighPerformance = enum.auto()
MaxPerformance = enum.auto()
GameMode = enum.auto()
MixedReality = enum.auto()
powerprof = cts.WinDLL("Powrprof.dll")
PowerRegisterForEffectivePowerModeNotifications = powerprof.PowerRegisterForEffectivePowerModeNotifications
PowerRegisterForEffectivePowerModeNotifications.argtypes = (wts.ULONG, EffectivePowerModeCallback, cts.c_void_p, VoidPtrPtr)
PowerRegisterForEffectivePowerModeNotifications.restype = HRESULT
PowerUnregisterFromEffectivePowerModeNotifications = powerprof.PowerUnregisterFromEffectivePowerModeNotifications
PowerUnregisterFromEffectivePowerModeNotifications.argtypes = (cts.c_void_p,)
PowerUnregisterFromEffectivePowerModeNotifications.restype = HRESULT
@EffectivePowerModeCallback
def cb(mode, ctx):
print("\n Callback: {:s} ({:d}), {:}".format(EffectivePowerMode(mode).name, mode, ctx))
if not ctx:
return
parg = cts.cast(ctx, IntPtr)
print(" Callback: {:} {:}".format(parg, parg.contents))
if mode == EffectivePowerMode.BetterBattery.value: # e.g.: Plug the power cable out
print(" Callback - signaling exit")
parg.contents.value = 0
def main(*argv):
ctx = cts.pointer(cts.c_int(3141593)) # Dummy initial value
print("Context ({:}) value: {:d}".format(ctx, ctx.contents.value))
handle = cts.c_void_p()
print("Handle: {:}".format(handle))
res = PowerRegisterForEffectivePowerModeNotifications(EFFECTIVE_POWER_MODE_V2, cb, ctx, cts.byref(handle))
print("Handle (after registration): {:}".format(handle))
if res != ERROR_SUCCESS:
print("PowerRegisterForEffectivePowerModeNotifications returned 0x{:08X}".format(res))
return -1
print("Waiting for BetterBattery to be activated...")
while True:
if ctx and ctx.contents.value == 0:
break
time.sleep(0.5)
PowerUnregisterFromEffectivePowerModeNotifications(handle)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.\n")
sys.exit(rc)
Output:
[cfati@CFATI-5510-0:e:\Work\Dev\StackExchange\StackOverflow\q075799861]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" ./code00.py
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec 6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] 064bit on win32
Context (<ctypes.wintypes.LP_c_long object at 0x000001C7731FCBC0>) value: 3141593
Handle: c_void_p(None)
Handle (after registration): c_void_p(1956130359280)
Waiting for BetterBattery to be activated...
Callback: MaxPerformance (4), 1956141584904
Callback: <ctypes.wintypes.LP_c_long object at 0x000001C7731FD440> c_long(3141593)
Callback: BetterBattery (1), 1956141584904
Callback: <ctypes.wintypes.LP_c_long object at 0x000001C7731FD440> c_long(3141593)
Callback - signaling exit
Done.
Needless to say that the program stopped when I plugged out the power cord on my laptop (don't try this on a regular PC).
Might also want to check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer) for a common pitfall when working with CTypes (calling functions).