2012-05-24 3 views
9

У меня есть приложение для лотка.Обнаружение, если закрытие Windows или приложение пытается закрыть из системного меню (WM_CLOSE)

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

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

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

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

Спасибо!

+4

А вы пробовали улавливание [ 'WM_QUERYENDSESSION'] (http://msdn.microsoft.com/en-us/library/aa376890%28VS.85%29.aspx) сообщение? – RRUZ

+0

Я переместил свой комментарий на ответ. –

ответ

7

Неполадки, связанные с использованием OnCloseQuery, являются неправильным случаем использования. Ответ Remy объясняет, как обход Windows shutdown блокируется обработкой сообщений конечного сеанса по умолчанию VCL. И это в свою очередь вызвано установкой CanClose на False в событии OnCloseQuery.

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

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

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

+0

Это потому, что ваш код не использует событие OnCloseQuery.Вместо этого используется событие OnClose, которое не привязано к сообщению 'WM_QUERYENDSESSION', например' OnCloseQuery'. –

+0

@Remy Да, я немного медленный на поглощении, не я ?! Казалось бы, OnClose - правильное решение здесь. Нет смысла ввязываться в сообщения конечной сессии. –

+0

Мне нужны и WM_QUERYENDSESSION, и WM_ENDSESSION. Я уже использую OnCanCloseQuery для размещения программы в лотке при запуске WM_CLOSE. –

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:

Application Shutdown Changes in 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; 
+0

Спасибо за помощь Реми. Я ценю ваш быстрый ответ. –

+0

Дэвид, ваши решения и Реми идентичны. Все, что мне нужно, это сообщения - и когда система отправляет их. Вы оба помогаете мне, и я дал вам ПЛЮС, но Реми сделал это в форме ответа, поэтому я принял это как помощь. Но оба решения одинаковы. Идея (логика) почти идентична. –

+0

Нет, мой ответ совсем другой. Возможно, вы не обновили страницу. Вы говорите о моем комментарии. Я считаю, что код Реми в этом ответе намного сложнее, чем вам нужно. –