종료 통화를 차단하기 위해 setConsoleHandler ()를 사용하는 방법

StackOverflow https://stackoverflow.com/questions/533491

  •  22-08-2019
  •  | 
  •  

문제

나는 내가 사용해야한다는 것을 안다 setconsolehandler() 콘솔 폐쇄 이벤트를 관리하려면

나는 그것을 차단하는 방법을 모른다 CTRL_CLOSE_EVENT. 그 이벤트를 잡으면 거짓/진실을 반환하려고 시도했지만 성공하지 못했습니다.

여기에 내가 지금까지 가지고있는 것이 있습니다 (Anton Gogolev 감사합니다!)

[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);

public delegate bool HandlerRoutine(CtrlTypes CtrlType);

public enum CtrlTypes{
    CTRL_C_EVENT = 0,
    CTRL_BREAK_EVENT,
    CTRL_CLOSE_EVENT,
    CTRL_LOGOFF_EVENT = 5,
    CTRL_SHUTDOWN_EVENT
}

private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{ 
    if(ctrlType == CtrlTypes.CTRL_CLOSE_EVENT)
        return false;// I have tried true and false and viceversa with the return   
                     // true/false but I cant seem to get it right.
    return true;
}


//and then I use this to call it
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);

또한 콘솔이 닫히는 지 모니터링하기 위해 새 스레드를 실행하고 기본 스레드가 무언가를하는 중에 닫히는 것을 차단할 수 있습니까?

도움이 되었습니까?

해결책

문서 SetConsoleCtrlHandler() 말 :

시스템은 CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT 및 CTRL_SHUTDOWN_EVENT 신호를 생성하여 사용자가 콘솔을 닫거나 로그 오프하거나 시스템을 종료하여 프로세스가 종료되기 전에 정리할 수있는 기회를 제공합니다.

이는 CTRL+C 또는 CTRL+브레이크 이벤트를 처리 할 때와 달리 프로세스가 닫기, 로그 오프 또는 종료를 취소 할 수있는 기회를 얻지 못한다는 것을 의미합니다.

다른 팁

실제로 당신은 그것을 차단할 수 있습니다 (나는 이것을 Windows XP에서 최소한 재현했습니다). 예를 들어, 핸들러에 수면이있는 끝없는 루프가있는 경우,이 프로세스가 영원히 종료되는 것을 막을 수 있습니다 (또는 적어도 오랫동안 또는 사용자가 작업 관리자를 통해 프로세스를 죽일 때까지).

실제로 스레드를 시작 해야하는 경우 대기 조건을 사용할 수 있습니다 (AutoResetEvent C#)에서 스레드를 시작하고 (대부분의 경우 새 스레드가 필요하지는 않지만) 스레드가 완료되면 대기 조건에 알립니다. 그러나 대부분의 경우 핸들러에서 청소를하는 것만으로도 충분합니다.

최악의 경우 영원히 기다렸다면 프로세스가 계속 실행되며 로그인하면 (적어도 Windows XP에서) 다시 볼 수 있습니다. 그러나 로그 아웃 화면으로 이동하기 전에 데스크탑이 약 20 초 동안 일시 중지됩니다 (응용 프로그램이 종료 될 때까지 기다렸다가) 로그 아웃 화면에서 다시 일시 정지합니다 (두 번째로 시도하는 동안 가정). . 물론, 나는 영원히 기다리는 것에 대해 강력하게 조언합니다. 장기적인 물건의 경우 실제로 서비스에 넣어야합니다.

콘솔 클로즈 요청에 여전히 깔끔하게 순종하는 동안 응용 프로그램이 닫히지 못하게 할 수있는 '해킹'을 발견했습니다. 특히, 이것은 콘솔을 '추가'로 만든 GUI 애플리케이션에 적합하다고 생각합니다. MSDN 문서에서 CTRL 핸들러를 새 스레드 프로세스에서 처리기를 호출하기 위해 생성됩니다. 그러므로 내 해결책은 기본 핸들러가 ExitProcess를 호출하기 전에 공격 스레드를 죽이는 것입니다. 핸들러 루틴 (C ++의 코드)에서 :

// Detach Console:
FreeConsole();
// Prevent closing:
ExitThread(0);
return TRUE; // Not reached

편집하다: 이것은 내가 생각하는 것처럼 몇 가지 문제를 일으킨 것 같습니다. allocconsole ()에 대한 후속 호출은 무기한으로 매달려 있으므로 스레드를 빠져 나가는 것이 제대로 정리되지 않는다고 생각합니다.

편집 2 :

위에서 설명하기 위해 프로그램을 계속 운영하는 데 직접적인 문제가 없었습니다. 그러나 우리는 Kernel32가 만든 스레드를 강력하게 종료 했으므로 Kernel32 내부의 모든 자원이 불확실한 상태에있을 수 있습니다. 프로그램이 계속 실행될 때 예상치 못한 문제가 발생할 수 있습니다.

대부분, 이러한 문제는 콘솔 API와 관련이있을 것이라고 생각합니다. 언급했듯이 AllocConsole 이 시점에서 작동하지 않으면 (응용 프로그램이 걸려) 프로그램이 새 콘솔을 열 수 없습니다. 다른 콘솔 기능도 실패 할 가능성이 높습니다. 기본적으로, 그 시점에서 어떤 식 으로든 (직접 또는 간접적으로) Kernel32에 전화를 걸면 정의되지 않은 동작이 적용되지만 실제로는 콘솔 기능 이외의 문제가 없다고 생각합니다.

내 결론은 가능하다면이 방법을 피해야한다는 것입니다. 그러나 조기 종료가 더 나쁘면, 이것은 비상 사태로 생각할 수 있으며, 드물고주의해서 사용해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top