Вопрос по – Определить, закрывается ли Windows или пытается ли приложение закрыться из системного меню (WM_CLOSE)

11

У меня есть приложение для лотка.

Onj FormCloseQuery Я проверяю, должна ли программа идти в трей, и вместо того, чтобы закрывать ее, я помещаю ее в трей (CanClose: = False)

Но если Windows пытается закрыть мое приложение из-за выключения Windows, я хочу не перемещать мое приложение в трей, а закрывать его.

Win7 закрывает мое приложение, но XP не закрывается, потому что мое приложение остается в трее.

Как я могу определить, что Windows "выключается"? режим или нет?

Спасибо!

Я переместил свой комментарий в ответ. Remy Lebeau
Вы пытались поймать в ловушкуWM_QUERYENDSESSION сообщение? RRUZ

Ваш Ответ

2   ответа
13

ЕслиOnCloseQuery событие срабатывает в ответ наWM_QUERYENDSESSION сообщение, настройкаCanClose=False заставит сообщение вернутьсяFALSE.

На XP и более ранних версиях это отменяет завершение работы Windows. До этого момента любое приложение, которое получилоWM_QUERYENDSESSION сообщение получитWM_ENDSESSION сообщение с егоwParam значение установлено вFALSE рассказывая эти приложенияNOT прекратить себя. Вот почему ваше приложение отправляется в лоток и не закрывается при завершении работы Windows.

Microsoft изменила это поведение в Windows Vista, поэтому приложения не могут отменить завершение работы Windows с помощьюWM_QUERYENDSESSION больше. Вот почему Windows Vista и более поздние версии прекратят работу вашего приложения. Существует целый новый API, представленный, если приложение должно остановить работу Windows преднамеренно.

Это задокументировано в MSDN:

Изменения завершения работы приложения в Windows Vista

Чтобы сделать то, что вы просите, вы должны перехватитьWM_QUERYENDSESSION сообщение, чтобы вы могли определить, еслиOnCloseQuery вызывается из-за выключения Windows или нет. Например:

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;
Error: User Rate Limit Exceeded Ivan Mark
Error: User Rate Limit Exceeded Ivan Mark
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Ivan Mark
8

Ваши проблемы проистекают из использованияOnCloseQuery это неправильное событие для использования. В ответе Реми объясняется, как обойти закрытие Windows, блокируемое обработкой сообщений конца сеанса VCL по умолчанию. И это в свою очередь вызвано настройкойCanClose вFalse вOnCloseQuery событие.

Этот обходной путь выполнит работу, но есть гораздо более простой способ справиться с этим. Вместо того, чтобы мешать закрытию формы, позвольте ей идти вперед и закрываться. Удалить свойOnCloseQuery событие в целом. Замените егоOnClose событие.

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caNone;
  Visible := False;
end;

Этого довольно тривиального куска кода достаточно, чтобы сделать ваше приложениеminimize to the tray когда основная форма закрыта.

Error: User Rate Limit Exceeded Ivan Mark
Error: User Rate Limit ExceededOnCloseQueryError: User Rate Limit ExceededOnCloseError: User Rate Limit ExceededWM_QUERYENDSESSIONError: User Rate Limit ExceededOnCloseQueryError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded

Похожие вопросы