dummzeuch 1506 Posted May 22, 2019 Sometimes your program needs to block the screen saver from automatically kicking in. My use case was that the program was recording data and whenever the screen saver was active, the data was lost (No idea why, it probably had something to do with the way HID is implemented in Windows.) So I was looking for a way to fix that without forcing the user to turn off the screen saver. The methods that used to work under Windows XP no longer work in Windows 7 and later (I don’t care about Vista), so I googled and found this question on StackOverflow. The Windows API functions PowerCreateRequest + PowerSetRequest mentioned in the highest voted answer looked promising. Unfortunately they don’t seem bo be available in Delphi read on in my blog post 2 1 Share this post Link to post
dummzeuch 1506 Posted May 22, 2019 The code is now in dzlib (see blog post for links). 1 Share this post Link to post
Lars Fosdal 1792 Posted June 14, 2019 Our laptops are under company governance, so we can't prevent the session from locking as it is dictated by the policies. In addition, the idle time is really short. So - we wrote LockBlock which basically simulates toggling the numlock every 60 seconds. That prevented the auto locking, but it also prevented the screensaver from kicking in when the dektkop was locked, so I added handling of lock/unlock to disable the fake keystrokes when it was locked. Super simple UI: 60 second interval, starting at 8 in the morning, lasting for 8 hours - with an add an extra hour button for off work hours lock blocking. Project source attached. LockBlock.zip 2 Share this post Link to post
dummzeuch 1506 Posted June 14, 2019 I used a similar hack in an earlier version of my program: Wiggling the mouse pointer. While that worked fine under Windows XP, it doesn't under Windows 10 (no idea about Windows 7 and 8). That was the reason I researched how to do it "right". Toggling numlock all the time would drive me crazy. Share this post Link to post
Lykke 1 Posted June 15, 2019 I use this function for this: https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-setthreadexecutionstate 1 Share this post Link to post
FredS 138 Posted June 15, 2019 2 hours ago, Lykke said: setthreadexecutionstate Yes, that is what I used but it doesn't take care of the screen saver. Thanks to this blog post I updated to use PowerCfg when (OS>=Win7). 1 Share this post Link to post
Lars Fosdal 1792 Posted June 16, 2019 On 6/14/2019 at 5:09 PM, dummzeuch said: I used a similar hack in an earlier version of my program: Wiggling the mouse pointer. While that worked fine under Windows XP, it doesn't under Windows 10 (no idea about Windows 7 and 8). That was the reason I researched how to do it "right". Toggling numlock all the time would drive me crazy. It turns NumLock off/on/off (or on/off/on) within less than 30 ms every 60 seconds, so I don't think it will bother you much. Share this post Link to post
FredS 138 Posted June 16, 2019 12 minutes ago, Lars Fosdal said: NumLock off/on/off Sounds like an 'Awesome' feature while entering financial data into a spreadsheet 1 1 Share this post Link to post
Yaron 53 Posted September 25, 2019 (edited) This is a bit old, but I've been blocking the windows screen-saver for media playback in every version of windows since 1999. I'm actually handling several actions, first I capture the WM_POWERBROADCAST message in the form: procedure WMPOWERBROADCAST(var M : TMessage); message WM_POWERBROADCAST; const PBT_APMQUERYSUSPEND = $0000; PBT_APMQUERYSTANDBY = $0001; PBT_APMQUERYSUSPENDFAILED = $0002; PBT_APMQUERYSTANDBYFAILED = $0003; PBT_APMSUSPEND = $0004; PBT_APMSTANDBY = $0005; PBT_APMRESUMECRITICAL = $0006; PBT_APMRESUMESUSPEND = $0007; PBT_APMRESUMESTANDBY = $0008; PBT_APMBATTERYLOW = $0009; PBT_APMPOWERSTATUSCHANGE = $000A; PBT_APMOEMEVENT = $000B; PBT_APMRESUMEAUTOMATIC = $0012; begin Inherited; Case M.WParam of PBT_APMQUERYSUSPEND, PBT_APMSUSPEND : Begin If SystemSuspended = False then Begin SystemSuspended := True; End; End; PBT_APMRESUMEAUTOMATIC : Begin SystemSuspended := False; End; End; M.Result := Integer(True); end; Then on WinMsg (Application.OnMessage := WinMsg;) I do: procedure TMainForm.WinMsg(var Msg: TMsg; var Handled: Boolean); var ModWnd : HWnd; I : Integer; mPos : TPoint; begin If (Msg.Message = SC_SCREENSAVE) or (Msg.Message = SC_MONITORPOWER) then Begin Msg.wParam := 0; Msg.Message := SC_Move; Handled := True; End else If (Msg.Message = WM_SYSCOMMAND) then Begin Case Msg.WPARAM of SC_MONITORPOWER, SC_SCREENSAVE : Begin Msg.wParam := 0; Msg.Message := SC_Move; Handled := True; End; End; End; End; Then on WndProc ( procedure WndProc(var Msg : TMessage); override;) : Quote procedure TMainForm.WndProc(var Msg : TMessage); begin If Msg.Msg = WM_SYSCOMMAND then Begin {$IFDEF LOCAL} //If Msg.WParam and $FFF0 = SC_MAXIMIZE then ShowMessage('maximized'); {$ENDIF} If ((OPOTScreenSaver = True) and (plState <> stClosed) and (MainForm.WindowState = wsMaximized)) or (OPScreenSaverAW = True) then Begin Case Msg.WParam and $FFF0 of SC_SCREENSAVE, SC_MONITORPOWER : Begin Msg.Result := 0; End; else inherited WndProc(Msg); End; End Else inherited WndProc(Msg); End else If (Msg.Msg = SC_SCREENSAVE) or (Msg.Msg = SC_MONITORPOWER) then Begin Msg.Result := 0; End Else inherited WndProc(Msg); End; Hope this helps. Edited September 25, 2019 by Yaron Share this post Link to post
Remy Lebeau 1405 Posted September 25, 2019 (edited) 10 hours ago, Yaron said: This is a bit old, but I've been blocking the windows screen-saver for media playback in every version of windows since 1999. The *correct* way to block the screen saver on XP and later is to use SetThreadExecutionState() with the ES_DISPLAY_REQUIRED flag: Quote Multimedia applications, such as video players and presentation applications, must use ES_DISPLAY_REQUIRED when they display video for long periods of time without user input. Quote I'm actually handling several actions, first I capture the WM_POWERBROADCAST message in the form: PBT_APMQUERYSUSPEND is just a *request for permission* to suspend the system. The system is not actually suspended yet. So you should not be setting your SystemSuspended flag to True in reply to PBT_APMQUERYSUSPEND, only for PBT_APMSUSPEND. And then clearing the Flag in reply to PBT_APMRESUMESUSPEND and PBT_APMRESUMECRITICAL, not just for PBT_APMRESUMEAUTOMATIC. Quote Then on WinMsg (Application.OnMessage := WinMsg;) I do: SC_SCREENSAVE and SC_MONITORPOWER are not window messages, they are flags of WM_SYSCOMMAND, so your 1st "If" block will never evaluate as True. Quote Then on WndProc ( procedure WndProc(var Msg : TMessage); override;) : Same with the last "If" block here, too. Also, per the WM_SYSCOMMAND documentation: Quote If password protection is enabled by policy, the screen saver is started regardless of what an application does with the SC_SCREENSAVE notification even if fails to pass it to DefWindowProc. Edited September 25, 2019 by Remy Lebeau 2 Share this post Link to post
HolgerX 7 Posted September 26, 2019 11 hours ago, Remy Lebeau said: The *correct* way to block the screen saver on XP and later is to use SetThreadExecutionState() with the ES_DISPLAY_REQUIRED flag: Hmm.. and starting with W7 you have to use the function PowerCreateRequest(REASON_CONTEXT: TREASON_CONTEXT): THandle; stdcall; external 'kernel32.dll' name 'PowerCreateRequest'; function PowerSetRequest(PowerRequestHandle: THandle; PowerRequestType : TPowerRequestType): BOOL; stdcall; external 'kernel32.dll' name 'PowerSetRequest'; function PowerClearRequest(PowerRequestHandle: THandle; PowerRequestType : TPowerRequestType): BOOL; stdcall; external 'kernel32.dll' name 'PowerClearRequest'; 1 Share this post Link to post
Remy Lebeau 1405 Posted September 26, 2019 (edited) 14 hours ago, HolgerX said: and starting with W7 you have to use the function PowerCreateRequest(REASON_CONTEXT: TREASON_CONTEXT): THandle; stdcall; external 'kernel32.dll' name 'PowerCreateRequest'; function PowerSetRequest(PowerRequestHandle: THandle; PowerRequestType : TPowerRequestType): BOOL; stdcall; external 'kernel32.dll' name 'PowerSetRequest'; function PowerClearRequest(PowerRequestHandle: THandle; PowerRequestType : TPowerRequestType): BOOL; stdcall; external 'kernel32.dll' name 'PowerClearRequest'; If you do that, you will need to use the 'delayed' keyword on those function declarations if you want your app to run on pre-W7 systems. Then you can use the functions on W7+ only, and fall back to SetThreadExecutionState() on pre-W7 systems. If you really wanted to be slick, you could then use SetDliFailureHook2() to detect when the Power...() functions are not available at runtime and re-map them to custom functions that allocate a memory object and pass its details to SetThreadExecutionState() as needed. Then your code could call the Power...() functions unconditionally on all Windows versions. Edited September 26, 2019 by Remy Lebeau Share this post Link to post
HolgerX 7 Posted September 27, 2019 Right, I just wanted to give the declaration as a hint. 😉 Share this post Link to post
Der schöne Günther 316 Posted September 18, 2020 (edited) Your declaration of TPowerRequestType is missing a {$MinEnumSize 4} Not sure if the record should also be packed. Personally, I would add it, but the declaration from Winapi.Windows.pas is also omitting it. More Information here (German Language) Edited September 18, 2020 by Der schöne Günther 1 Share this post Link to post
Fr0sT.Brutal 900 Posted September 18, 2020 On 6/14/2019 at 2:27 PM, Lars Fosdal said: So - we wrote LockBlock which basically simulates toggling the numlock every 60 seconds. Why not ScrollLock that is useless for any other purpose? Share this post Link to post
Lars Fosdal 1792 Posted September 18, 2020 I can't remember why not - prolly because Numlock was the first to spring to mind. Anyways, I've been using this for years now, and never experienced any adverse side effects. Share this post Link to post
Uwe Raabe 2059 Posted September 18, 2020 1 hour ago, Der schöne Günther said: Not sure if the record should also be packed As all fields in that record are either 32 or 64 bit (depending on the target platform) it doesn't matter if the record were declared as packed or not. Share this post Link to post
Der schöne Günther 316 Posted September 18, 2020 I see. Still, I like to add things for clarity. It's Delphi, after all 😎 Maybe, one day, on another platform, there could be other alignments, and then it will matter. Share this post Link to post
Remy Lebeau 1405 Posted September 19, 2020 (edited) 19 hours ago, Der schöne Günther said: Not sure if the record should also be packed. Personally, I would add it, but the declaration from Winapi.Windows.pas is also omitting it. That is because Win32 structures do not use 1-byte alignment, they use 8-byte alignment. See What structure packing do the Windows SDK header files expect? Edited September 19, 2020 by Remy Lebeau 1 Share this post Link to post
David Heffernan 2347 Posted September 21, 2020 On 9/18/2020 at 7:36 AM, Der schöne Günther said: Not sure if the record should also be packed. Personally, I would add it, but the declaration from Winapi.Windows.pas is also omitting it. No it shouldn't be declared as packed. The structure, as is invariably the case for Windows structures, should be aligned. Share this post Link to post
David Heffernan 2347 Posted September 21, 2020 On 9/18/2020 at 9:03 AM, Uwe Raabe said: As all fields in that record are either 32 or 64 bit (depending on the target platform) it doesn't matter if the record were declared as packed or not. Packing does make a difference here. It may not change the layout, but it changes the alignment of the type. Share this post Link to post