Markus Stoeger said:
I have a problem with Application.Run() when Windows is shutting down.
Please have a look at the copy&paste example program below.
The application has no forms. It has only got a notify icon in the system
tray and it uses Application.Run() to keep the message loop running. When
the user clicks the icon, the application should shut down and exit. So
far that works fine.
The problem is: when the user logs out while the program is running, the
Application.Run() never returns. Windows just pulls the program out of RAM
and kills it.
How can I make the Application.Run() method return on Windows shutdown and
gracefully close the application?
My apologies for the very late reply. Perhaps no one even cares about the
answer at this point.
Still, I just came across the post and figured I
might as well put my two cents in, since I just ran into this myself.
Anyway, the short answer to your question is that you can't make the
Application.Run() method return on Windows shutdown.
In order to gracefully shutdown your application even when the user is
logging off (due to a shutdown or simply due to logging out), one has to add
a handler for the SessionEnded event (which corresponds to the WM_ENDSESSION
window message).
If one looks at the documentation for the WM_ENDSESSION message, one finds
this text:
the session can end any time after all applications have
returned from processing this message
(see
http://msdn.microsoft.com/library/en-us/shutdown/base/wm_endsession.asp
for the complete reference)
The upshot of this is that after your program returns from handling that
message (whether by the default window proc or by your own custom handler),
Windows is free to forceably terminate your program without warning (no
programs can be left running after the session has ended, and the docs give
no guarantee that the session will stay around long enough for your program
to exit normally).
Any processing you want to do before being terminated, you have to do when
the WM_ENDSESSION message is sent (in .NET, that's the SessionEnded event),
or possibly when the WM_QUERYENDSESSION message is sent (SessionEnding).
IMHO, this is very poorly documented, in spite of the fact that I suspect
lots of applications implicitly or explicitly assume that they will always
be terminated through the usual means (except when the user explicitly
forceably terminates the application, via Task Manager for example).
Lengthy, possibly uninteresting, musings follows... (the above is all you
really need to know)
My first reaction after figuring this out was "what the hell?" But after
thinking about it a little more, it makes sense to me. Applications are
sent a WM_QUERYENDSESSION message before Windows even decides to actually
end the session. At that point, applications have the opportunity to save
data, ask the user if they want to discard changes, etc. The application
can request that the session NOT be terminated by cancelling the event.
This is the point at which the OS is "being nice", and if the application
responds by telling the OS that it's okay to exit, the OS assumes it was
telling the truth.
So, the application gets one last message, once the OS has figured out
whether it's actually ending the session (note: an application that has not
cancelled the WM_QUERYENDSESSION message may still be terminated!), which is
the WM_ENDSESSION message. The OS makes sure that it doesn't have to wait
some indeterminate time for programs that lied and said they were ready to
exit by simply saying "I'm not guaranteeing you ANY time to exit
normally...you had your chance to clean up, I waited for you then, and I'm
not going to wait any longer once you tell me you're done".
This does make things harder on the application developer, but the big
advantage is that it makes the rules for shutting down VERY clear. Save
state if necessary when the WM_ENDSESSION message comes, at the latest, and
don't expect to be able to execute any more code after you return from
handling that message.
Anyway, no...this isn't the only way that Microsoft could have addressed
this issue, but I do see the benefit in the approach they took. Many
Windows applications are essentially stateless; that is, they do something
while you're logged in and running them, but you can safely terminate them,
gracefully or otherwise, at any time. For the subset (significant, to be
sure) of programs that are stateful, whether because they are document
based, or are trying to do something with the disk, or whatever, have
specific rules allowing them to have a say in how and when the OS shuts them
down, separate from the usual method of exiting. This allows the OS to
treat each application appropriately without having to wonder which ones
need special handling and which ones don't. Need special handling? Respond
to the ...ENDSESSION messages.
Still, I wish it were better documented (especially in the C# sections,
which don't even have the minimal reference to early termination that the
regular Platform SDK docs do). When I was first researching this, I saw
plenty of messages in various places by people who were puzzled by the
behavior, and not a lot of answers.
Pete