问题
I'm having Tray application.
Onj FormCloseQuery I check if program should goto tray and instead of closing it I put it in tray (CanClose := False)
But if Windows tries to close my application because of Windows shutdown I want not to move my app into tray but to close it.
Win7 terminates my app, but XP doesn't close because my app remains in Tray.
How can I detect if Windows is some "shutting down" mode or not?
Thanks!
回答1:
Your problems stem from the use of OnCloseQuery
which is the wrong event to be using. Remy's answer explains how to workaround Windows shutdown being blocked by the default VCL end session message handling. And this in turn is caused by setting CanClose
to False
in the OnCloseQuery
event.
That workaround will get the job done but there's a much simpler way to deal with this.
Instead of stopping the form from closing, let it go ahead and close. Remove your OnCloseQuery
event altogether. Replace it with an OnClose
event.
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caNone;
Visible := False;
end;
This rather trivial bit of code is enough to make your app minimize to the tray when the main form is closed.
回答2:
If the OnCloseQuery
event is triggered in response to a WM_QUERYENDSESSION
message, setting CanClose=False
will cause the message to return FALSE
.
On XP and earlier, that will cancel Windows shutdown. Up to that point, any app that had received a WM_QUERYENDSESSION
message will receive a WM_ENDSESSION
message with its wParam
value set to FALSE
telling those apps NOT to terminate themselves. This is why your app goes to the Tray and does not exit during Windows shutdown.
Microsoft changed this behavior in Windows Vista so apps cannot cancel Windows shutdown via WM_QUERYENDSESSION
anymore. That is why Windows Vista and later will terminate your app. There is a whole new API introduced if an app needs to stop Windows shutdown on purpose.
This is documented on MSDN:
Application Shutdown Changes in Windows Vista
To do what you are asking, you must intercept the WM_QUERYENDSESSION
message directly so you can determine if OnCloseQuery
is being called due to Windows shutdown or not. For example:
type
TForm1 = class(TForm)
private
procedure WMQueryEndSession(var Message: TWMQueryEndSession); message WM_QUERYENDSESSION;
procedure WMEndSession(var Message: TWMEndSession); message WM_ENDSESSION;
end;
var
ShuttingDown: Boolean = False;
procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
ShuttingDown := True;
inherited;
end;
procedure TForm1.WMEndSession(var Message: TWMEndSession);
begin
ShuttingDown := Message.EndSession;
inherited;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := ShuttingDown;
if not ShuttingDown then
begin
// your Tray logic here ...
end;
end;
来源:https://stackoverflow.com/questions/10745151/detect-if-windows-closing-or-application-tries-to-close-from-system-menu-wm-clo