Иногда разработчикам необходимо создать приложение, которое может управлять своим состоянием при попытке закрытия, например, переходить в системный трей, если закрытие происходит по действию пользователя, но закрываться, если это происходит из-за выключения системы. В данной статье мы рассмотрим, как это можно реализовать на примере приложения на Delphi.
Проблема
Разработчик столкнулся с проблемой, что его приложение, предназначенное для работы в системном трее, не закрывалось, когда пользователь выбирал команду "Закрыть" в меню "Пуск" (WM_CLOSE) и вместо этого переходило в трей. Однако, при выключении системы приложение оставалось в трее и не закрывалось в Windows 7, в отличие от Windows XP, где оно не переходило в трей и закрывалось корректно.
Решение
Чтобы решить эту проблему, необходимо использовать события OnClose вместо OnCloseQuery. В OnCloseQuery происходит проверка WM_QUERYENDSESSION, которая связана с закрытием системы, в то время как OnClose не связана с этим сообщением и будет вызываться только при закрытии формы пользователем. В таком случае, для перехода в трей можно использовать следующий код:
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caNone;
Visible := False;
end;
Этот код делает главную форму невидимой, что эквивалентно переходу в трей, когда пользователь пытается закрыть форму.
Альтернативный подход
В качестве альтернативного подхода можно перехватить сообщение WM_QUERYENDSESSION напрямую, чтобы определить, вызывается ли OnCloseQuery из-за закрытия системы. Это позволит определить, нужно ли переходить в трей или закрыть приложение. Пример перехвата сообщений:
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
// ваша логика для перехода в трей ...
end;
end;
Важно отметить, что начиная с Windows Vista, приложения больше не могут отменять закрытие системы через WM_QUERYENDSESSION, поэтому в этих версиях Windows приложение будет закрыто принудительно.
Заключение
Для управления закрытием приложения в системном трее и определения источника закрытия в Windows, разработчикам следует использовать события OnClose для перехода в трей при закрытии формы пользователем и перехват сообщений WM_QUERYENDSESSION для определения и обработки закрытия системы. Это позволит приложению корректно реагировать на попытки закрытия и переходить в трей или закрываться в зависимости от ситуации.
Управление переходом приложения в системный трей при попытке его закрытия пользователем и определение источника закрытия, чтобы отличать закрытие, инициированное пользователем, от закрытия при выключении системы в операционной сист
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS