Sending system to sleep right after logging off users on a Windows system

363 Views Asked by At

I have a service application that runs in conjunction with a user-mode module. The software allows to perform a specialized power operation at which the user-mode code first logs ff the Windows user and right after that the service application puts system into sleep mode.

This scenario works fine on some systems, but on others the sleep operation fails. At times the sleep succeeds, but then when I wake up the system and try to perform it again, the sleep API (SetSuspendState) hangs up and never returns, while the system remains operational.

While doing tests, I put a hard-coded delay (with a Sleep(5000) API) that seemed to resolve the issue on most systems, but I'm still getting the same result on others. In this case, I'd hate introducing a longer delay since it doesn't really solve the issue, or answers the question why it was happening in the first place. Plus, I'm sure there's a "slow" system out there for which, even 10 seconds will not be enough...

So, does anyone have any idea how to fix these failures in the sleep API?

PS. I run my tests on the latest version of Windows 7.

3

There are 3 best solutions below

0
On

Make use of SystemEvents Class.. I hope it works for you..

Microsoft.Win32.SystemEvents.SessionEnded+=
                       new SessionEndedEventHandler(SystemEvents_SessionEnded);

and handler method ..

private void SystemEvents_SessionEnded(object sender, SessionEndedEventArgs e)
{
    if (e.Reason == SessionEndReasons.Logoff)
    {
        //this may sleep the system even when user logs off manually.
        Application.SetSuspendState(PowerState.Suspend, true, true);
    }
}

you need to import using Microsoft.Win32; namespace

1
On

It may be that there's something blocking the system from sleeping. Drivers can prohibit a system from sleeping and some systems are simply not capable of sleeping.

When you hit the situation where SetSuspendState doesn't behave run "powercfg -energy" and "powercfg -requests". That utility is very handy in diagnosing sleep issues so you should also check out "powercfg /?" to see all of it's special powers.

0
On

I have to post this as an answer to my own question because this solution worked for me. It is a kinda cumbersome approach so I'd appreciate if someone can post a different solution.

So in a nutshell, before logging off users one needs to collect their session IDs. Then issue an API for the user account(s) to log off, while in the meantime one needs to listen and wait for the WTS_SESSION_LOGOFF notification from another thread and continue doing so until sessions (collected previously) are logged off.

But that is not all. For some unknown reason (which I was not able to find documentation for) after that we need to wait for a session that has WTSConnected state and has no user name. Only then we can call SetSuspendState for sleep or hibernation.