2014-08-27 4 views
5

Я пытаюсь запретить моему приложению закрывать окна. Приложение работает на окнах 8 и написано на XE6. Я пробовал следующий код, но он, кажется, полностью игнорируется. Чтобы проверить это, я просто посылаю ему «конечную задачу» через диспетчер задач. Что мне нужно - это позволить моему приложению завершить то, что он делает, когда приложение закрывается пользователем, диспетчером задач при выключении Windows. Нормальное закрытие не является проблемой, это связано с событием FormCloseQuery. Но другие 2 метода, с которыми я не могу работать. До Windows XP это было легко, поймав wm_endsession и wm_queryendsession, начиная с vista вам нужно использовать ShutDownBlockReasonCreate, который возвращает true, но, похоже, не работает.Delphi предотвращает закрытие приложения

procedure WMQueryEndSession(var Msg : TWMQueryEndSession); message WM_QUERYENDSESSION; 
procedure WMEndSession(var Msg: TWMEndSession); message WM_ENDSESSION; 

function ShutdownBlockReasonCreate(hWnd: HWND; Reason: LPCWSTR): Bool; stdcall; external user32; 
function ShutdownBlockReasonDestroy(hWnd: HWND): Bool; stdcall; external user32; 


procedure TForm1.WMEndSession(var Msg: TWMEndSession); 
begin 
    inherited; 

    Msg.Result := lresult(False); 
    ShutdownBlockReasonCreate(Handle, 'please wait while muting...'); 
    Sleep(45000); // do your work here 
    ShutdownBlockReasonDestroy(Handle); 
end; 

procedure TForm1.WMQueryEndSession(var Msg: TWMQueryEndSession); 
begin 
    inherited; 
    Msg.Result := lresult(False); 
    ShutdownBlockReasonCreate(Handle, 'please wait while muting...'); 
    Sleep(45000); // do your work here 
    ShutdownBlockReasonDestroy(Handle); 
end; 

Update

Изменение результата сообщение для истинны и удаления сна ничего не меняет.

procedure TForm1.WMEndSession(var Msg: TWMEndSession); 
begin 
    inherited; 
    Msg.Result := lresult(True); 
    ShutdownBlockReasonDestroy(Application.MainForm.Handle); 
    ShutdownBlockReasonCreate(Application.MainForm.Handle, 'please wait while muting...'); 
end; 

procedure TForm1.WMQueryEndSession(var Msg: TWMQueryEndSession); 
begin 
    inherited; 
    Msg.Result := lresult(True); 
    ShutdownBlockReasonDestroy(Application.MainForm.Handle); 
    ShutdownBlockReasonCreate(Application.MainForm.Handle, 'please wait while muting...'); 
end; 
+1

См. [Как приостановить выключение окон] (http://stackoverflow.com/a/18347424/576719). –

+1

Вы не можете сказать, что функции являются «обманом». Проверьте возвращаемое значение 'ShutDownBlockReasonCreate', и если он возвращает false, используйте' GetLastError', чтобы узнать, почему это не удалось. Вы не можете сказать, что «API не работает», когда вы не утруждаете себя проверкой возвращаемых значений, чтобы узнать, почему это не так. –

+0

Функция возвращает true, если я вызываю ее с помощью кнопки, я не могу проверить результат в WMQueryEndSession, потому что приложение отключается, прежде чем я могу проверить его значение. – GuidoG

ответ

8

Согласно documentation блокировать отключение вы должны вернуть FALSE в ответ на WM_QUERYENDSESSION.

Кроме того, вы не должны работать в этом обработчике сообщений. Работа должна происходить в другом месте. Если вы не ответите на это сообщение своевременно, система не будет ждать вас.

  • Звоните ShutdownBlockReasonCreate, прежде чем приступить к работе.
  • Во время рабочей обратной связи FALSE от WM_QUERYENDSESSION. Не работайте при обращении с этим сообщением. Вернитесь немедленно.
  • Когда работа выполнена, звоните ShutdownBlockReasonDestroy.

Обработчик WM_QUERYENDSESSION может выглядеть следующим образом:

procedure TMainForm.WMQueryEndSession(var Msg: TWMQueryEndSession); 
begin 
    if Working then 
    Msg.Result := 0 
    else 
    inherited; 
end; 

А затем код, который выполняет работу нужно вызвать ShutdownBlockReasonCreate перед началом работы, ShutdownBlockReasonDestroy, когда заканчивается работа, и убедитесь, что Working свойство, используемое выше, оценивается как True во время работы.

Если ваша работа блокирует основной поток, тогда у вас проблемы. Основной поток должен реагировать, иначе система не будет ждать вас. Помещение работы в поток часто является способом продвижения вперед. Если ваше главное окно не отображается, вы не сможете заблокировать выключение. Подробности здесь объясняются: http://msdn.microsoft.com/en-us/library/ms700677.aspx

Если вы дошли до отправки WM_ENDSESSION, то уже слишком поздно. Система идет вниз, что может.

Чтобы проверить это, я просто посылаю ему «конечную задачу» через диспетчер задач.

Это не имеет никакого отношения к блокировке выключения. То, как вы проверяете блокировку выключения, - это выход из системы. Если пользователь настаивает на убийстве вашего процесса, мало что можно сделать. Ответ Сертака подробно описывает это.

И, наконец, игнорирование возвращаемых значений вызовов API также очень плохое. Не делай этого.

+0

Кроме того, «Если приложение истечет время ответа на WM_QUERYENDSESSION или WM_ENDSESSION, Windows завершит его». Таким образом, ваш «Сон (45000); // сделайте свою работу здесь» приведет к этому таймауту. http://msdn.microsoft.com/en-us/library/ms700677(v=vs.85).aspx –

+0

Я попытался вернуть TRUE, но это не имеет значения. Также без команды сна он все еще не работает. RETurning TRUE и ommying ShutDownBlockReasonDestroy не работает. Я пробовал почти каждую комбинацию, о которой я могу думать, пробовал разные коды, найденные с помощью Google, ничего не работает. У вас есть рабочий пример, возможно, – GuidoG

+0

У меня нет образца кода, но я успешно использовал эти API. Ясно, что они не мистификация, и я не понимаю, почему вы так думаете. Вы что, добавляете API, которые не работают? –

6

Ваш код, кажется, полностью игнорируется, потому что вы его не тестируете. Вы отправили «конечную задачу» через диспетчер задач, код, который вы опубликовали, эффективен только тогда, когда система выключается.

В отличие от Windows 8, как работает менеджер задач. Перед Windows 8 задача из диспетчера задач сначала попробует закрыть приложение изящно (отправляет WM_CLOSE), это вы обрабатываете с помощью OnCloseQuery. Но когда приложение отрицает закрытие, диспетчер задач предложит окончательно завершить процесс. Это невозможно. То же самое, если вы выберете «конечный процесс» из диспетчера задач.

Диспетчер задач Windows 8 не предлагает дополнительного диалогового окна для принудительного закрытия приложения, но сразу же делает это, когда приложение отказывает в закрытии.

Смежные вопросы