Application.Run() never returns when windows is shutting down?

M

Markus Stoeger

Hi,

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?

thanks,
Max

using System;
using System.IO;
using System.Windows.Forms;

namespace TestNotifyIcon {
public class MyApp {
[STAThread]
private static void Main() {
NotifyIcon ni = new NotifyIcon();
Form f = new Form();
ni.Icon = f.Icon;
ni.Click += new EventHandler(ni_Click);
ni.Visible = true;

Application.Run();

// these last few lines of code don't get executed when windows
// shuts down or when the user logs off.
using (StreamWriter sw = new StreamWriter(@"c:\done.txt")) {
sw.Write("done");
}
}

private static void ni_Click(object sender, EventArgs e) {
Application.Exit();
}
}
}
 
T

Tom Spink

Markus said:
Hi,

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?

thanks,
Max
<snipeddy-doo-dah>

Hi Markus,

Try subscribing to the Application.ApplicationExit event, and see if that
gets fired. Also take a look at the Application.ThreadExit event, they may
be useful.
 
M

Markus Stoeger

Tom Spink wrote:

Hi Tom,
Try subscribing to the Application.ApplicationExit event, and see if that
gets fired. Also take a look at the Application.ThreadExit event, they may
be useful.

I already tried that.. doesn't work. The program gets killed before
these events are fired.

I also tried to implement the IMessageFilter interface, but I get no
useful "shutdown"-messages (like WM_QUERYENDSESSION or WM_ENDSESSION)
either.

Any other ideas? Seems too simple to be impossible...

thanks,
Max
 
G

Guest

I do this, but only under 98 (mine's a service under NT+). I use the
sessionEnding event - it seems to work on system shutdown, but doesn't if the
app is terminated using CTRL-Alt-Del.
 
P

Peter Duniho

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top