ShutdownEx, I wouldn’t let you beat me!
The Problem
In my haste to leave the office I will often click shutdown on my laptop then shut the lid. The laptop will probably shutdown successfully 1 in 5 times for two main reasons:
- The laptop will hibernate or suspend before it can shutdown
- Windows will be waiting on applications to close that are waiting for save dialogs etc to be dismissed.
I have two possible solutions, create an application that modifies this behaviour or be more patient.
Software Solution
Lets face it I was never going to change so I started to put some thought in to an application to modify the behaviour and ShutdownEx was born. Not long ago I created a shutdown timer app so I had all the interop calls required to shutdown the machine and a quick search of MSDN turned up the WM_POWERBROADCAST message for intercepting suspends.
Armed with this I created a quick plan and requirement list in my mind:
- The app should be standalone, no install, no dependencies, just work.
- A simple Winform application, the main form would have a couple of options and a button to shutdown the system.
- When shutdown was invoked from it, it would listen for the WM_POWERBROADCAST message and stop it from suspending.
- If the system didn’t shutdown within a set time out, it would recall shutdown with the force shutdown flag.
Before even writing a line of code I spotted a major flaw with this. In order to wait for the timeout the application would have to ignore the first WM_QUERYENDSESSION message that came in, meaning it would always timeout and we would be forced to shutdown when the second message came. This introduces two massive problems
- We’re holding up shutdown meaning it will always take longer when we’re running. Not cool!
- When we have been forced to shutdown, a small window of opportunity will open up for the suspend event to come in.
The second problem is a deal breaker, the whole point of the application is to stop the suspend from taking place during shutdown.
Revised Solution and Compromising My Own Requirements
I came up with two more solutions. The first, and ultimately still flawed approach, keeping to the simple WinForm one executable approach. I could enumerate all process running in my session and keep polling till everything has closed then close gracefully myself allowing the shutdown to continue. While the majority of the time, I feel, it wouldn’t send out the force shutdown there is still a sizeable (measured in seconds) gap when the suspend event could still take place. Breaking one of the main requirements.
The second approach is to ditch the requirement of a standalone WinForm applications and go to a Windows Service. The Windows service will not need to end when the session does so I don’t have to worry holding up the shutdow. This, also, means I have a longer window of opportunity to block the suspend message. With the theory being when I go down, Windows will be taking its subsystems down and the message will be ignored anyway. The big downsides are I now have to install the service from an MSI and I’ve just added a new and very complex layer to my simple application.
Complexity from a service point of a view because I need to create a hidden Window so I can listen for Windows Messages. I will still need a UI for the user to shutdown with so I need to have comms between the service and UI, a named pipe more than likely. Throw in any permissions problems I might have when running as system and it’s now quite far from the quick app with lots of existing code samples I first thought of.
The worst part of it is, I’ve started it now and I have to finish to prove it can be done. Although, I will never be happy with the comprised requirements.
Also, I have a private SVN repo I work against but seriously considering moving to GitHub from the start of development, would you be interesting in seeing it take shape?
Assuming the the real issue is your clicking the shutdown button when really you should be just closing the lid and letting it go to sleep… then a simpler solution is: remove the Shut Down option from the Start Menu. Use the Group Policy editor: gpedit.msc – User Config/Admin Templates/Start Menu. You should still be able to shut down using the shutdown.exe /s command, so create a batch file to that for the times you really do want to shut down.
Duncan Smart
3 Feb 10 at 13:50 edit_comment_link(__('Edit', 'sandbox'), ' ', ''); ?>
Further to Duncan’s reply, what I’ve done in the past is:
- Create a Shortcut:
– File = “c:\windows\system32\shutdown.exe”
– Name = “Shutdown (Force)”
- Edit it so it passes the “/s /f” flags
- Change the icon.
– It’ll warn that there aren’t any icons in shutdown.exe, but then it’ll open up the icon viewer for “Shell32.dll”, this contains a ncie shutdown icon.
- Move this shortcut to your QuickLaunch toolbar.
- Now just use this instead of the “shutdown” on the StartMenu.
PS: And, change your “Close Lid” options in the Control Panel, so it doesn’t do anything.
RichS
26 Feb 10 at 11:55 edit_comment_link(__('Edit', 'sandbox'), ' ', ''); ?>