I want to be able to 1. detect (and, if needed 2. abort) OS shutdown from my application, preferably by using the Windows API.
I know that it is possible to abort shutdown manually using the command shutdown -a In the worst case, I could ShellExecute this, but I was wondering if there was a better way to prevent the shutdown programatically.
Maybe it would be enough to be notified programatically that the OS is about to shut down - how to do this?
From MSDN:
The WM_QUERYENDSESSION message is sent when the user chooses to end the session or when an application calls one of the system shutdown functions. If any application returns zero, the session is not ended. The system stops sending WM_QUERYENDSESSION messages as soon as one application returns zero.
So, my application's WindowProc now processes the WM_QUERYENDSESSION message and returns 0.
Didn't expect it to be this simple; as a bonus, it also works on Windows 2000.
In regards to 'simply' returning 0 to block a shutdown, it isn't as simple as that if you want to do it in the proper way. Especially on Vista. For example please also read http://msdn.microsoft.com/en-us/library/ms700677(VS.85).aspx
Related
I have an application that is running on Windows, in the user's session, that I don't want the user to be able to close by accident.
One way the user can close it is by having unsaved data (e.g. in notepad) and start the process of logging off. Notepad rejects the WM_QUERYSESSION message; Windows prompts the user that there is unsaved data; and the user gets to cancel the logoff.
Other applications (including mine), get the WM_QUERYSESSION, respond with TRUE, then get WM_ENDSESSION, and quit. Importantly, they quit before Windows has even decided to prompt the user about unsaved data in notepad.
If the user cancels the logoff, the end result is that the user's session continues without all the processes that honoured the end session messages.
What I'm trying to find a way of doing is keeping my process running until we're past the point that the user could cancel the logoff. Looking at the microsoft docs on this, I don't see an obvious way of doing that - each process goes through its own WM_QUERYSESSION > WM_ENDSESSION, and the docs are explicit that this happens for each application independently.
I don't want to reply to WM_QUERYSESSION with FALSE, as I don't want to block the logoff myself, just stay running if something else blocks it.
Are there any other ways of finding out when Windows has decided that all the WM_QUERYSESSION messages were replied to with TRUE, and the logoff is inevitable?
(I think this is a Windows question, rather than a question specific to the language I'm using, but in case it matters, it's PureBasic. Any Win32 API approach should be workable though.)
If any app returns FALSE to WM_QUERYENDSESSION, apps that had already returned TRUE will receive WM_ENDSESSION with wParam=FALSE to indicate shutdown has been canceled.
If all apps return TRUE to WM_QUERYENDSESSION, only then will they receive WM_ENDSESSION with wParam=TRUE to indicate shutdown is proceeding.
See Application Shutdown Changes in Windows Vista and Restart Manager: Guidelines for Applications for more details of how WM_QUERYENDSESSION and WM_ENDSESSION work.
Is your app paying attention to the wParam value given by WM_ENDSESSION? Or does it just blindly exit unconditionally when it receives WM_ENDSESSION? Not all apps pay attention like they should be. Make sure yours does.
Update: Per the WM_QUERYENDSESSION documentation, and the Logging Off documentation:
When an application returns TRUE for WM_QUERYENDSESSION, it receives the WM_ENDSESSION message and it is terminated, regardless of how the other applications respond to the WM_QUERYENDSESSION message.
So, there is really nothing your app can do here. Once it responds TRUE to WM_QUERYENDSESSION, that is it, game over. Your app will receive WM_ENDSESSION and be forcibly terminated if it does not exit within a few seconds, regardless of how other apps respond to the shutdown.
So, the only way I can think of to really detect when the session is actually ending is to use a service instead, as a service can receive SERVICE_CONTROL_SHUTDOWN and SERVICE_CONTROL_SESSIONCHANGE notifications.
Is it possible to intercept WM_ENDSESSION message to prevent another application from receiving it?
I'd like to command that application to perform an additional action before Windows reboots or shuts down, and it's not possible to configure the application that way.
The application is screen recorder software, and it just throws away the video when Windows shuts down. I need to prevent that and save the video.
Is it possible to intercept WM_ENDSESSION message to prevent another application from receiving it?
Technically yes, using a message hook from SetWindowsHookEx(). Depending on the hook used, you can sometimes modify (not discard) messages to look like another messages, such as WM_NULL. However, in the case of WM_ENDSESSION, it is just a notification, not a request, so Windows is still going to continue shutting down no matter what applications do with that message.
I'd like to command that application to perform an additional action before Windows reboots or shuts down, and it's not possible to configure the application that way.
The application is screen recorder software, and it just throws away the video when Windows shuts down. I need to prevent that and save the video.
So, you don't actually want to avoid WM_ENDSESSION, you just want to delay the other app from processing it until after your action is performed first.
The best option would be to simply contact the recorder author and request a feature be added to save the video on system shutdown.
Beyond that, MSDN says the following:
Application Shutdown Changes in Windows Vista
By default, applications without any visible top-level windows will be given 5 seconds to handle WM_ENDSESSION before being terminated.
If your application may need more than 5 seconds to complete its shutdown processing in response to WM_ENDSESSION, it should call ShutdownBlockReasonCreate() in its WM_QUERYENDSESSION handler, and promptly respond TRUE to WM_QUERYENDSESSION so as not to block shutdown. It should then perform all shutdown processing in its WM_ENDSESSION handler.
This way, Windows will treat your application as if it had visible top-level windows and will give it 30 seconds to handle WM_ENDSESSION.
So, you could try using a message hook to intercept WM_QUERYENDSESSION and have it call ShutdownBlockReasonCreate() and return immediately, then intercept WM_ENDSESSION to invoke the video saving action and call ShutdownBlockReasonDestroy() when it is finished. Assuming, of course, that the recorder is throwing the video away in reply to WM_ENDSESSION and not WM_QUERYENDSESSION.
See MSDN for more info about how these two messages are handled by Windows:
Shutdown Changes for Windows Vista
If a system is trying to shut down, an app can block this shutdown by overriding OnQueryEndSession() and returning FALSE. Surely that means WM_ENDSESSION is the only definitive message to respond to regarding shutdown.
On the other hand, the top answer to this question quotes no less than Raymond Chen as saying that responding to WM_ENDSESSION is essentially pointless. So this is confusing.
Is there some kind of "best practice" principles to apply in deciding which of these messages (if any) one should respond to for doing what kinds of application shutdown work?
In particular, if neither message is handled, will a shutdown process cause an application to be closed as if the user had closed the application manually (e.g. click on red X close button)?
This article from Microsoft gives a very comprehensive discussion of end-of-session best practice both pre- and post-Vista. The article makes it quite clear that one should assume that if one receives a WM_QUERYENDSESSION then shutdown will occur at some point.
As soon as all applications have responded to the WM_ENDSESSION message, or been forced to terminate within 5 seconds of receiving the WM_ENDSESSION message, Windows may shut down at any time. This may limit what can be done in response to WM_ENDSESSION.
If an application requires more time to clean itself up:
If your application may need more than 5 seconds to complete its shutdown processing in response to WM_ENDSESSION, it should call ShutdownBlockReasonCreate() in its WM_QUERYENDSESSION handler, and promptly respond TRUE to WM_QUERYENDSESSION so as not to block shutdown. It should then perform all shutdown processing in its WM_ENDSESSION handler.
Windows will apparently not send any additional messages to your application to allow it to exit "gracefully" (e.g. WM_CLOSE). Rather, it will simply call TerminateProcess. If you want a graceful close, you have to build it yourself within the above constraints.
You do need to close down your application in WM_ENDSESSION, at least if you want to support the Restart Manager API. I think both MSDN and Raymond are wrong here. (Maybe it changed recently, or they overlooked the Restart Manager?)
The Restart Manager API is used by installers to close and restart exes which have files locked that they need to replace. To support being restarted by it, you call RegisterApplicationRestart and then need to have a window which handles WM_QUERYENDSESSION and WM_ENDSESSION.
If you don't shut down your app in the WM_ENDSESSION handler than it will simply keep running and block the Restart Manager, and in turn the installers trying to use it.
I found this out the hard way. MSDN explicitly says you don't need to call PostQuitMessage, but if I don't do that then my process keep running.
I suspect the documentation didn't realise the Restart Manager is different, and less forceful, compared to what happens when the entire OS shuts down.
(Edit: I should add, this was with a simple ATL COM EXE server, but as far as I can tell there was nothing about that complicating things, and Windows simply wasn't triggering a WM_QUIT to the message loop unless I did it myself.)
I want to stop the shutdown / log off API which appears when you have programs open to confirm a shutdown/logoff.
I have an application already that send a reason to the API.
I know this is bad practice but I really need to override / cancel the shutdown with out displaying the API after 5 seconds.
is there any way to hack this or run a custom shutdown script to override the shutdown.
thanks in advance
it doesnt matter about holding it for5 seconds just catching it if it is pressed once. I can do that but vista shows a API screen after 5 seconds which All i want is vista not to show that.
vista shows that because I prevent it from shutting down.
You may want to look at this:
http://msdn.microsoft.com/en-us/library/aa376871(VS.85).aspx
When I did this functionality I had to do everything in unmanaged C++ as I had problems trying to set the priviledge by using Interop.
You need this flag: EWX_FORCE in ExitWindowsEx.
I'm working on a C++ Windows application, that runs as a process but not a windowed application (does not have WndProc). It has it's own message loop, which is used to process a quit message, and that's how we safely exit the application from within it's self.
What I want to do is somehow send a message to the process from another process, in order to tell the process to exit safely.
In Linux, we would do this by trapping signals, but I'm not sure how it's done on Windows.
PostThreadMessage can post messages to threads without requiring a window proc.
In the first process, do a GetCurrentThreadId to get a system wide id for the current thread. And somehow get that id to the second app.
In the second app, OpenThread will convert to a thread handle, that you can then use with PostThreadMessage.
Do note that if your 'windowprocless' application ever pops up a message box, the message box enters its own modal message loop, which will silently destroy any thread messages. If any kind of window is ever created on the thread you would be far better off creating an invisible message window that messages can be sent to to control the app.
Do you have the control over both processes i.e., do you have the code of both processes? If yes I suggest to expose a API to exit safely.