2014-08-27 2 views
5

Windows에서 내 응용 프로그램이 종료되지 않도록하려고합니다. 응용 프로그램이 Windows 8에서 실행 중이고 XE6로 작성되었습니다. 다음 코드를 시도했지만 완전히 무시 된 것 같습니다. 테스트하기 위해 작업 관리자를 통해 단순히 "끝 작업"을 보냅니다. 내가 필요로하는 것은 내 응용 프로그램이 Windows 셧다운의 작업 관리자가 응용 프로그램을 닫을 때 수행 한 작업을 마치게하는 방법입니다. 정상 닫기는 문제가 아니며 FormCloseQuery 이벤트에 의해 처리됩니다. 그러나 내가 일할 수없는 다른 두 가지 방법. Windows XP가 시작될 때까지는 wm_endsession과 wm_queryendsession을 잡아내는 것이 쉬워 질 때까지는 Vista에서 시작하여 ShutDownBlockReasonCreate를 사용해야합니다. 그러면 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; 

업데이트

true로 메시지 결과를 변경하고 잠을 제거하는 것은 아무 것도 변경되지 않습니다.

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

[Windows 일시 중지 방법] (http://stackoverflow.com/a/18347424/576719)을 참조하십시오. –

+1

기능이 "사기성"이라고 말할 수는 없습니다. 'ShutDownBlockReasonCreate'의 반환 값을 확인하고, false를 반환하면'GetLastError'를 사용하여 실패한 이유를 찾습니다. 왜 반환 값을 확인하지 않아도 API가 작동하지 않는다고 말할 수는 없습니다. –

+0

버튼에서 호출하면이 함수가 true를 반환합니다. 그 값을 확인하기 전에 응용 프로그램이 종료되기 때문에 WMQueryEndSession에서 결과를 확인할 수 없습니다. – GuidoG

답변

8

당신이 WM_QUERYENDSESSION에 응답 FALSE을 반환해야 종료를 차단하기 위해 documentation에 따르면.

또한이 메시지 처리기에서 작업하지 않아야합니다. 다른 곳에서 일해야합니다. 이 메시지에 적시에 응답하지 않으면 시스템이 사용자를 기다리지 않습니다.

  • 작업을 시작하기 전에 ShutdownBlockReasonCreate으로 전화하십시오.
  • 작업 반품 동안 FALSEWM_QUERYENDSESSION에서. 이 메시지를 처리하는 동안 작업하지 마십시오. 즉시 반환하십시오.
  • 작업이 완료되면 ShutdownBlockReasonDestroy을 호출하십시오.

WM_QUERYENDSESSION의 핸들러는 다음과 같이 할 수 있습니다

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

그리고 작업이 작업이 끝나면 작업, ShutdownBlockReasonDestroy 시작하기 전에 ShutdownBlockReasonCreate를 호출하고 있는지 확인 할 필요가 수행하는 다음 코드

Working 위에서 사용 된 속성은 작업 중에 True으로 평가됩니다.

작업이 주 스레드를 막는 경우 문제가 발생합니다. 주 스레드가 응답해야합니다. 그렇지 않으면 시스템이 사용자를 기다리지 않습니다. 작업을 스레드에 넣는 것이 종종 좋은 방법입니다. 기본 창이 보이지 않으면 시스템 종료를 차단할 수 없습니다. 자세한 내용은 여기에서 설명합니다. http://msdn.microsoft.com/en-us/library/ms700677.aspx

전송되는 경우까지 WM_ENDSESSION을 보내면 너무 늦었습니다. 시스템은 어떤 상황이 될지 궁금해합니다.

테스트하려면 간단히 작업 관리자를 통해 "끝 작업"을 보냅니다.

셧다운 차단과 관련이 없습니다. 종료 차단을 테스트하는 방법은 로그 오프하는 것입니다. 사용자가 자신의 프로세스를 죽이라 고 주장한다면 그것에 대해 할 수있는 일은 거의 없습니다. Sertac의 대답은 이것을 자세히 다룹니다.

마지막으로 API 호출의 반환 값을 무시하는 것은 매우 형편 없습니다. 그러지 마.

+0

또한 "응용 프로그램이 WM_QUERYENDSESSION 또는 WM_ENDSESSION에 응답하여 시간 초과되면 Windows가 종료합니다." 따라서 "절전 (45000); // 여기에서 작업하십시오"는이 시간 초과가 발생합니다. http://msdn.microsoft.com/en-us/library/ms700677(v=vs.85).aspx –

+0

나는 TRUE를 되 돌리려고했지만 아무런 차이가 없다. 또한 sleep 명령 없이는 여전히 작동하지 않습니다. TRUE를 되 돌리고 ShutDownBlockReasonDestroy를 생략하면 작동하지 않습니다. 내가 생각할 수있는 모든 조합을 시도했는데 다른 코드가 Google을 사용하여 시도했지만 아무 것도 작동하지 않는 것 같습니다. 실제 예제가 있습니까 – GuidoG

+0

샘플 코드가 없지만이 API를 성공적으로 사용했습니다. 분명히 그들은 날조가 아니며 왜 그들이 당신이 생각하는지 이해할 수 없습니다. ms가 작동하지 않는 API를 추가합니까? –

6

코드를 테스트하지 않으므로 코드가 완전히 무시 된 것 같습니다. 당신은 작업 관리자을 통해 "end task"를 보내고 있습니다. 게시 한 코드는 시스템이 종료 될 때만 유효합니다.

Windows 8과 다른 점은 작업 관리자의 작동 방식 인 것 같습니다. Windows 8 이전에 작업 관리자의 종료 작업은 먼저 응용 프로그램을 정상적으로 닫으려고합니다 (WM_CLOSE을 보냄). OnCloseQuery으로 처리합니다. 그러나 응용 프로그램이 닫기를 거부하면 작업 관리자는 강제로 프로세스를 종료하도록 제안합니다. 이것은, 당신은 처리 할 수 ​​없습니다. 작업 관리자에서 "프로세스 끝내기"를 선택하는 경우와 동일합니다.

Windows 8 작업 관리자는 응용 프로그램을 강제 종료하기위한 추가 대화 상자를 제공하지 않지만 응용 프로그램이 닫기를 거부하면 즉시 진행합니다.