Windows Power On Button

I have a headless computer running a custom service that I want to enable / disable using the power button instead of remotely connecting every time. The computer also performs other functions, so you cannot turn it off.

Is it possible to connect the system power button under Windows XP and above so that my program receives the event before . Windows fires shutdown / hibernation event (before PBT_APMQUERYSUSPEND

event dispatch )?

0


source to share


1 answer


It is indeed possible, but it is a bit hackish and requires two completely different implementations depending on the Windows version. For both methods, you need to set the power button so the computer can sleep in your power settings.

Windows XP and below:

You need to overwrite the main program window WndProc

. In IDEs that do not support this feature, this can be done using SetWindowLong

the user32 API in the API. In your custom function, WndProc

listen to the message WM_POWERBROADCAST (0x218)

. If you get a message with wParam PBT_APMQUERYSUSPEND (0x0)

, call the function you want and return BROADCAST_QUERY_DENY (0x424D5144)

instead of calling the base function WndProc

. Sample code:

//At program start
//GWL_WNDPROC = -4
oldWndProc = SetWindowLong(this.hWnd, GWL_WNDPROC, &MyWndProc)

//In MyWndProc(hWnd, wMsg, wParam, lParam)
//WM_POWERBROADCAST = 0x218
//PBT_APMQUERYSUSPEND = 0x0
//BROADCAST_QUERY_DENY = 0x424D5144
if wMsg = WM_POWERBROADCAST && wParam = PBT_APMQUERYSUSPEND (
    //CALL YOUR FUNCTION HERE!
    return BROADCAST_QUERY_DENY
)
return CallWindowProc(oldWndProc, hWnd, wMsg, wParam, lParam)

//Before exiting
SetWindowLong(Me.hWnd, GWL_WNDPROC, oldWndProc)

      



Windows Vista and up: (thanks to Remy Lebeau for getting me on the right track)

You need to override WndProc

as for XP, but also call SetThreadExecutionState

in the kernel32 API to disable standby and RegisterPowerSettingNotification

in the user32 API to listen for extended power notifications. You will listen, in particular, to the notification GUID_SYSTEM_AWAYMODE

that is sent when the system is asked to sleep, but cannot. To easily convert a string to a well-formed one LPCGUID

, you can use UuidFromStringA

rpcrt4.dll in the API. Sample code:

typedef struct UUID{
    int d1, d2, d3, d4
} LPCGUID;

//At program start
//GWL_WNDPROC = -4
//ES_CONTINUOUS = 0x80000000
//ES_SYSTEM_REQUIRED = 0x1
//ES_AWAYMODE_REQUIRED = 0x40
//GUID_SYSTEM_AWAYMODE = "98a7f580-01f7-48aa-9c0f-44352c29e5C0"
LPCGUID uid;
oldWndProc = SetWindowLong(this.hWnd, GWL_WNDPROC, &MyWndProc)
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED)
UuidFromStringA(*(GUID_SYSTEM_AWAYMODE), uid)
ps = RegisterPowerSettingNotification(this.hWnd, uid, 0)

//In MyWndProc(hWnd, wMsg, wParam, lParam)
//WM_POWERBROADCAST = 0x218
//PBT_POWERSETTINGCHANGE = 0x8013
if wMsg = WM_POWERBROADCAST && wParam = PBT_POWERSETTINGCHANGE (
    //CALL YOUR FUNCTION HERE!
    //You can additionally extract data from the lParam to verify
    //this is the notification you're waiting for (see below)
)
return CallWindowProc(oldWndProc, hWnd, wMsg, wParam, lParam)

//Before exiting
SetWindowLong(Me.hWnd, GWL_WNDPROC, oldWndProc)
UnregisterPowerSettingNotification(ps)

      

This method has the side effect of disabling your physical screen (not a problem on a headless machine) and also possibly blocking the session. Make sure you turn off the password prompt after sleep to avoid this. There is some additional useful information about RegisterPowerSettingNotification

here that shows how to extract information from lParam

into your function WndProc

if you would like more information on this notification. Good luck;)

+2


source







All Articles