WM_POWERBROADCAST (RegisterPowerSettingNotification) & WTSSESSION_CHANGE (WTSRegisterSessionNotification)

Put simple Tips and Tricks that are not entire Tutorials in this forum
Marium0505
Posts: 40
Joined: 11 May 2020, 20:45

WM_POWERBROADCAST (RegisterPowerSettingNotification) & WTSSESSION_CHANGE (WTSRegisterSessionNotification)

18 Sep 2023, 13:51

First off, not sure if this should be placed here, Tutorials (v2) or Scripts and Functions (v2)
, mods/admins can (obviously) move the thread if this wasn't the best place.

I wanted to make do something when my computer is locked/unlocked and/or when my monitor turns itself off (power saving) to do stuff when I've left my computer.
Both of which is documented for v1, but doesn't seem to be documented for v2 yet, so here's the fruits of my hours of researching, trial & and error.

WM_POWERBROADCAST & RegisterPowerSettingNotification

The below can be used to detect when your monitor goes into power saving mode.
viewtopic.php?t=17457 was of great help, as was Snipper - Extension - OCR by FanaticGuru , especially the especially the CLSIDFromString function.

Tested on Windows 10 Pro, on AHK v2.0.6.

Code: Select all

CLSIDFromString(IID) {
    CLSID := Buffer(16)
    if res := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", CLSID, "UInt")
        throw Error("CLSIDFromString failed. Error: " . Format("{:#x}", res))
    Return CLSID
}

WM_POWERBROADCAST := 0x218
if !hPowerNotify := DllCall('RegisterPowerSettingNotification', 'Ptr', A_ScriptHwnd, 'Ptr', CLSIDFromString(GUID_CONSOLE_DISPLAY_STATE_ := "{6FE69556-704A-47A0-8F24-C28D936FDA47}"), 'UInt', 0, 'Ptr')
    throw OSError(A_LastError, -1, 'RegisterPowerSettingNotification')

Sleep(1) ; a notification is always emitted immediately after registering for it for some reason. this prevents seeing it
OnMessage(WM_POWERBROADCAST, _WM_POWERBROADCAST)

_WM_POWERBROADCAST(wParam, lParam, msg, hwnd) {
    Critical(1000)
    static PBT_POWERSETTINGCHANGE := 0x8013
    if (wParam = PBT_POWERSETTINGCHANGE) {
        monitorStatus := NumGet(lParam, 20, 'UChar') ; 0 (off) or 1 (on). 
    }
    return true
}
Relevant Links:
WM_POWERBROADCAST message (Microsoft Learn)
RegisterPowerSettingNotification function (winuser.h) (Microsoft Learn)
Registering for Power Events (Microsoft Learn)



WTSSESSION_CHANGE & WTSRegisterSessionNotification

The below can be used to trigger stuff when computer is locked, unlocked, logged off, or logged on. Obviously requires that the script is running when the event is happening.
In case you didn't know: when you have enabled screensaver, the computer isn't actually locked until the computer the screensaver closes (ie. when you move the mouse or use the keyboard and the lock screen appears.

Code: Select all

onMessage(WM_WTSSESSION_CHANGE := 0x02B1, WTSSESSION_CHANGE)
dllCall("Wtsapi32.dll\WTSRegisterSessionNotification", "uint", a_scriptHwnd, "uint", NOTIFY_FOR_ALL_SESSIONS := 1)


WTSSESSION_CHANGE(wParam, lParam, msg, hwnd) {
    Critical(1000)
    static WTS_SESSION_LOCK := "0x7", WTS_SESSION_UNLOCK := "0x8", WM_WTSSESSION_CHANGE := "0x02B1", WTS_SESSION_LOGON := "0x5", WTS_SESSION_LOGOFF := "0x6"
    
    switch wParam {
        case WTS_SESSION_LOCK:
            action := "locked"
        case WTS_SESSION_UNLOCK:
            action := "unlocked"
        case WTS_SESSION_LOGON:
            action := "logon"
        case WTS_SESSION_LOGOFF:
            action := "logoff"            
        default:
            action := "undefined"
    }

    return true
}
Relevant Links:
WTSRegisterSessionNotification function (wtsapi32.h)
(Microsoft Learn)

WM_WTSSESSION_CHANGE message

I originally wanted to detect when my screensaver started (which is neither when the screen turns off or when the computer is locked), but suddenly the screensaver stopped showing up, so temporarily disabled it. Will test further when I get it working again. If there isn't a event specifically for screensaver, it should be, after some testing, be possible to detect the screensaver by using SetWinEventHook, and checking if the process name of the hwnd ends with .scr. That worked when I previewed the screensaver, so I see no reason why it shouldn't work on the "real thing" as well. The method is quite hacky though. And potentially a bit resource having as you need to all windows rather than a specific as the window doesn't exist yet.
bonobo
Posts: 76
Joined: 03 Sep 2023, 20:13

Re: WM_POWERBROADCAST (RegisterPowerSettingNotification) & WTSSESSION_CHANGE (WTSRegisterSessionNotification)

19 Sep 2023, 20:09

Thank you so much for this.

Can I ask what the purpose of Critical(1000) is? Is it there because if the function was interrupted by a hotkey thread, the power status might become out of date by the time the thread resumes?
Marium0505
Posts: 40
Joined: 11 May 2020, 20:45

Re: WM_POWERBROADCAST (RegisterPowerSettingNotification) & WTSSESSION_CHANGE (WTSRegisterSessionNotification)

21 Sep 2023, 10:15

bonobo wrote:
19 Sep 2023, 20:09
Thank you so much for this.

Can I ask what the purpose of Critical(1000) is? Is it there because if the function was interrupted by a hotkey thread, the power status might become out of date by the time the thread resumes?

I added it based on:
bonobo
Posts: 76
Joined: 03 Sep 2023, 20:13

Re: WM_POWERBROADCAST (RegisterPowerSettingNotification) & WTSSESSION_CHANGE (WTSRegisterSessionNotification)

21 Sep 2023, 11:51

Marium0505 wrote:
21 Sep 2023, 10:15
bonobo wrote:
19 Sep 2023, 20:09
Thank you so much for this.

Can I ask what the purpose of Critical(1000) is? Is it there because if the function was interrupted by a hotkey thread, the power status might become out of date by the time the thread resumes?

I added it based on:

Thank you!
tamo
Posts: 11
Joined: 11 Jul 2019, 04:23

Re: WM_POWERBROADCAST (RegisterPowerSettingNotification) & WTSSESSION_CHANGE (WTSRegisterSessionNotification)

30 Nov 2023, 22:27

Marium0505 wrote: I wanted to make do something when my computer is locked/unlocked and/or when my monitor turns itself off (power saving) to do stuff when I've left my computer.
Both of which is documented for v1, but doesn't seem to be documented for v2 yet, so here's the fruits of my hours of researching, trial & and error.

WM_POWERBROADCAST & RegisterPowerSettingNotification

The below can be used to detect when your monitor goes into power saving mode.
Thank you for the clean and readable snippet!
I made a workaround for Rapid HPD problem using your notification technique.
https://tamo.tdiary.net/20231130.html
It saves me a lot. Thank you!

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 6 guests