Jump to content
c0d3r

Modern StandBy

Recommended Posts

Hi, All

 

Our client application used a timer (TTimer) to send a ping to our application server every 60 seconds. It seems that the timer being killed by Windows when entering the Modern Standby mode, and never being re-activated when exit.  The big problem is that Windows seems never send notification to all the applications when entering/exit from the modern standby mode.  any way we could restart the timer?  

 

BTW,  We did register power notification call back, like this:

 

var

   LParameters: DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS;

 

LParameters.ACallback := @DeviceNotifyCallbackRoutine;
LParameters.AContext := nil;

PowerRegisterSuspendResumeNotification(DEVICE_NOTIFY_CALLBACK, @LParameters, @FPowerNotify);

 

However, we never got any notifications from Windows,  no entry/no exit notifications at all.

 

Any help would be appreciated.  Thanks.

 

Regards,

William

Edited by c0d3r

Share this post


Link to post

Try using RegisterPowerSettingNotification in combination with GUID_MONITOR_POWER_ON power setting GUID

Share this post


Link to post
13 hours ago, Anders Melander said:

I think the timer is still alive. It just takes a (unusually long) while to fire after resume from standby.

 

See also: https://github.com/cyd01/KiTTY/issues/475

I thought so,  BUT  there is no new PING records in the server database after exit from the standby, so I think the timer is dead completely (I was at least waiting for 5+ minutes to check).

Edited by c0d3r

Share this post


Link to post
13 hours ago, dwrbudr said:

Try using RegisterPowerSettingNotification in combination with GUID_MONITOR_POWER_ON power setting GUID

Is this the new requirement for this?   The regular Windows sleeping/wake up don't need this GUID, which was working just fine.

Share this post


Link to post
45 minutes ago, c0d3r said:

there is no new PING records in the server database after exit from the standby

You are looking at the symptoms at the end of a long chain of circumstances. You need to look at the other end, which supposedly (assuming WM_TIMER is the problem) is closer to the source of the problem.

 

33 minutes ago, c0d3r said:

I think the timer is dead completely (I was at least waiting for 5+ minutes to check).

If standby killed WM_TIMER then millions of applications would break so I think it's very unlikely.

 

The bug in PuTTY wasn't that the timer didn't fire but that they assumed that it would fire with a certain time interval and WM_TIMER is never guaranteed to do that.

 

AFAIK WM_TIMER is a low priority message which is only synthesized when the message queue is polled and no higher priority messages are in the queue (or synthesized). I don't know your application but it could be that the queue is simply flooded with other stuff after resume from standby.

 

So instead of assuming that WM_TIMER doesn't work I recommend that you simply verify with a simple application that does nothing but write a time stamp to a TMemo every time a 1 second TTimer fires.

If that doesn't work then there's a problem with TTimer and we can start examining what that is.

  • Like 1

Share this post


Link to post
40 minutes ago, Anders Melander said:

So instead of assuming that WM_TIMER doesn't work I recommend that you simply verify with a simple application that does nothing but write a time stamp to a TMemo every time a 1 second TTimer fires.

If that doesn't work then there's a problem with TTimer and we can start examining what that is.

Good idea.  will do it and report back. 

Edited by c0d3r

Share this post


Link to post
On 2/16/2025 at 1:33 PM, Anders Melander said:

So instead of assuming that WM_TIMER doesn't work I recommend that you simply verify with a simple application that does nothing but write a time stamp to a TMemo every time a 1 second TTimer fires.

If that doesn't work then there's a problem with TTimer and we can start examining what that is.

Got the report back:  TTimer was suspended and never resumed after exit from Modern standby mode (S0).  It looks to me that all activities in the applications threads and windows message handlers were suspended, never being resumed.

Edited by c0d3r

Share this post


Link to post

Bummer.

I've just checked both my desktop (which is a *ehem* 15 years old home build) and my laptop which is the top Lenovo X1 model, 2 years old, and neither of them support S0.

This means that I unfortunately can't help debug the problem.

 

If anyone else wants to have a go at it, the command to check for S0 support is powercfg /a.

Note though that if Modern Standby isn't already enabled then it requires a complete OS reinstall to enable it. Yup, you read that right. Nice one, Microsoft.

  • Like 1

Share this post


Link to post
1 hour ago, c0d3r said:

It looks to me that all activities in the applications threads and windows message handlers were suspended, never being resumed.

That is highly unlikely. If that were true, then all applications would be dead upon wakeup.  I think you are misdiagnosing the problem.  But, as I don't have an S0-enabled computer, I can't help you diagnose that better.

 

Have you tried using the TApplication[Events].OnMessage event, and TApplication.HookMainWindow() and overriding the TForm.WndProc() method, to actually check that window messages are really no longer being processed?

 

In any case, an application can detect support for Modern Standby by checking the AoAc field returned by GetPwrCapabilities().  And register for notification of Modern Standby/Resume using RegisterSuspendResumeNotification().

Share this post


Link to post
39 minutes ago, Remy Lebeau said:

In any case, an application can detect support for Modern Standby by checking the AoAc field returned by GetPwrCapabilities().  And register for notification of Modern Standby/Resume using RegisterSuspendResumeNotification().

HI, Remy

 

As stated in my post #1,  we are using  PowerRegisterSuspendResumeNotification, call back routine, but we get ZERO notification when entry/exit from Modern Standby/Resume (regular Windows sleeping/wake up is working fine).  Any difference between  PowerRegisterSuspendResumeNotification  and your RegisterSuspendResumeNotification.  

 

As the sample code we use to test,  very simple,  a TTimer and a Memo field on a vcl form, and OnTimer event (every 1 second):

 

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Memo1.Lines.Add(TimeToStr(Now));
end;

 

 

NO output in the memo field after exit from Modern StandBy mode.

Share this post


Link to post
1 hour ago, Remy Lebeau said:

Have you tried using the TApplication[Events].OnMessage event, and TApplication.HookMainWindow() and overriding the TForm.WndProc() method, to actually check that window messages are really no longer being processed?

Yes. we did:  WM_KEYFIRST..WM_KEYLAST, WM_MOUSEFIRST..WM_MOUSELAST,  seems working.

Share this post


Link to post
56 minutes ago, c0d3r said:

Any difference between  PowerRegisterSuspendResumeNotification  and your RegisterSuspendResumeNotification.  

According to MSDN:

Quote

Similar to PowerRegisterSuspendResumeNotification, but [RegisterSuspendResumeNotification] operates in user mode and can take a window handle. 

Quote

As the sample code we use to test,  very simple,  a TTimer and a Memo field on a vcl form, and OnTimer event (every 1 second):

TTimer is based on a window-based WM_TIMER message. TTimer has an internal HWND that it receives WM_TIMER messages with. And TMemo is another window-based UI control. Are you ABSOLUTELY SURE that your app's message queue is not generating WM_TIMER messages? Never mind whether they are being DELIVERED to TTimer or TMemo - are they being GENERATED at all?  The TApplication[Events].OnMessage event should be able to very that, since it sees all messages coming out of the main thread's message queue.  Or even a tool like Spy++ or Winsight.  For all we know, your windows got recreated and that is why messages are being lost.  Who knows.  Did you try verifying that the TTimer's HWND and the TMemo's HWND are still the same before the Standby and after the Wakeup?

Quote

NO output in the memo field after exit from Modern StandBy mode.

You are looking at multiple things at one time which are acting on top of each other, and not verifying the behavior at the ROOT of the chain of actions.

Edited by Remy Lebeau

Share this post


Link to post
20 minutes ago, Remy Lebeau said:

For all we know, your windows got recreated and that is why messages are being lost.  Who knows.  Did you try verifying that the TTimer's HWND and the TMemo's HWND are still the same before the Standby and after the Wakeup?

We don't see why windows got recreated and how to check HWND values before standby and after the wakeup, because we never know when its entering modern standby mode and when its waken up.

Edited by c0d3r

Share this post


Link to post
2 hours ago, c0d3r said:

NO output in the memo field after exit from Modern StandBy mode.

In my case the timer continues to fire after sleep.

 

The following sleep states are available on this system:
    Standby (S0 Low Power Idle) Network Connected
    Hibernate
    Fast Startup

 

 

Share this post


Link to post
1 hour ago, c0d3r said:

We don't see why windows got recreated and how to check HWND values before standby and after the wakeup

A TTimer HWND shouldn't change, but any VCL UI control can recreate for any number of reasons. Can't rule anything out at this point.

Quote

because we never know when its entering modern standby mode and when its waken up.

So do it manually. Create a temporary button or something that you can trigger at will to log the current HWNDs, then invoke a standby+wakeup, then trigger the log again and compare the results.

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post
15 minutes ago, Remy Lebeau said:

Create a temporary button or something that you can trigger at will to log the current HWNDs, then invoke a standby+wakeup, then trigger the log again and compare the results.

Here's my logger I had suspected some issue with timer restarting I wrapped the timer event to disable the timer when in the event seemed to help and removed a show event on the logging form seemed to have fixed.

The following sleep states are available on this system: //Pats win 11 pro
    Standby (S0 Low Power Idle) Network Connected
    Hibernate
    Fast Startup

The following sleep states are not available on this system:
    Standby (S1)
	The system firmware does not support this standby state.
	This standby state is disabled when S0 low power idle is supported.

    Standby (S2)
	The system firmware does not support this standby state.
	This standby state is disabled when S0 low power idle is supported.

    Standby (S3)
	This standby state is disabled when S0 low power idle is supported.

    Hybrid Sleep
	Standby (S3) is not available.
	The hypervisor does not support this standby state.
	
//Events app1 sidebar	
memoShowMessages
h18.834 ZeroIndex 985940 Comp 199704
18.835 TSideBar on top//1
18.838 Shell_TrayWnd on top // closing logged on App1

18.858 Windows.UI.Core.CoreWindow on top//opening App1
18.861 LockScreenControllerProxyWindow on top
18.861 Shell_TrayWnd on top
18.864 TSideBar on top

//events Second running App sidebar
memoShowMessages
18.826 TSideBar on top
18.827 CabinetWClass on top
18.829 Shell_TrayWnd on top
18.834  on top
18.834 TSideBar on top  //1
18.838 Shell_TrayWnd on top// closing logged on App2
18.858  on top
18.859 Windows.UI.Core.CoreWindow on top//opening logged on App2
18.861 LockScreenControllerProxyWindow on top
18.861 Shell_TrayWnd on top
18.864 TSideBar on top

// made with this coding
var
  TopWinControl: HWND;

procedure TSideBar.TaskTimerTimer(Sender: TObject);
const
  MAX_VALUE = 255;
var
  pcClassName: Array [0 .. MAX_VALUE] Of Char;
  aClassName: string;
  Hnd: HWND;
begin
  TaskTimer.Enabled := False;
  Hnd := GetForegroundWindow;
  // shows apps being used.
  if Hnd <> TopWinControl then
  begin
    TopWinControl := Hnd;
    GetClassName(Hnd, pcClassName, MAX_VALUE);
    aClassName := Trim(pcClassName);
    label1.Caption := aClassName;
    memoShowMessages.Lines.add(format('%2.3f %s on top', [Time * 24, aClassName]));//Screen.Forms[0].Name]);
  end;
// show now can change bringtofront getfocus best not use here
 //boo 100xs Jumper.Show;  // not needed and perhaps fighting the debugger

  TaskTimer.Enabled := True;
end;

Needs to be 64 bit.

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×