2009-06-11 34 views
14

Windows를 종료 할 때 각 응용 프로그램에 WM_QUERYENDSESSION 메시지를 보냅니다. 이렇게하면 Windows가 종료 될 때 쉽게 감지 할 수 있습니다. 그러나 컴퓨터가 전원이 꺼지거나 Windows가 종료 된 후 다시 시작되는지 여부를 알 수 있습니까?Windows 종료 또는 다시 시작 여부를 감지하는 방법

MSDN의 문서에서 WM_QUERYENDSESSION에 대해 "나는 어떤 이벤트가 발생했는지 확인할 수 없습니다."라고 말하면서 특별히 희망적이지는 않지만 stackoverflow의 누적 된 영리성은 결코 나를 놀라게하지 않습니다. here에서

답변

5

:

당신이 결정하는 "탐색기 \ 종료 설정 \ HKCU \ 소프트웨어 \ 마이크로 소프트 \ 윈도우 \ CurrentVersion" 에서 DWORD 값을 읽을 수있는 사용자 마지막으로 종료에서 선택 대화 상자.

로터리 솔루션의 비트,하지만 트릭을해야합니다.

+11

물론 현재 사용자가 시스템을 시작했기 때문에 시스템이 종료되었다고 가정하고 탐색기에서 시스템을 종료했다고 가정합니다. 프로그래밍 방식으로 종료하거나 다른 앱에서 종료하거나 다른 사용자가 종료 한 경우 이전에 종료 한 이유가 생깁니다. – MSalters

+5

-1 답변이 불완전하고 Windows 탐색기에 한정되어 있기 때문입니다. 또한 Windows 7에서 ** 제거 ** 된 것으로 보입니다. – unixman83

+1

WindowsXP에서는 잘 작동하지만 API hooking suggestion에 대해서는 Windows7 – conceptacid

5

일반적으로 작동하는 트릭은 WM_ENDSESSION을 트랩하고 로그하는 것입니다. 이제 시간을 추적하십시오. 시스템이 합리적인 범위 내에있는 경우 (예 : 5 분). 그런데 재부팅이 아니라 종료.

아이디어 : 시스템 5 분 이내에 다시 작동하는 경우 사용자가 '종료'또는 '재부팅'를 클릭 한 경우, 그것은 정말 문제가 무엇입니까?

정말로 종료를 감지해야하는 경우 (종료와 재부팅 사이의 모호한 동작 소프트웨어 차이에 따라 달라지는 경우에만이를 수행해야한다고 생각하는 유일한 이유) API hooking을 조사 할 수 있습니다. ExitWindowsEx 및 관련 기능을 권장하지만이 방법은 권장하지 않습니다. 이 사실을 직접 알아 내야 할 경우 다시 생각해보십시오.

+1

+1에서 작동하지 않습니다. 시간 확인 제안은 당연한 추측입니다. –

+0

@Joe, 최신 ACPI 전원 관리 기능 : 절전 모드, 최대 절전 모드, WOL (Wake On LAN) 등. 재부팅 (또는 웜 부팅)의 정의가 정의되기 어려워지고 있습니다. 대부분의 사람들은 재부팅 (또는 충분히 가까움)을 의미하는 것은 시스템이 매우 짧은 기간 * 동안 정상 상태가 아니 었음을 의미합니다. – unixman83

6

Windows 7 (및 아마도 Vista/8/Server에서도) 시스템 이벤트를 사용하여 Windows가 종료되는지 (컴퓨터 전원이 꺼져 있는지) 또는 다시 시작되는지 여부를 추적 할 수 있습니다. Windows 7은 종료/재부팅이 시작될 때마다 (시작 메뉴의 단추 또는 프로그래밍 방식으로 단추를 클릭 할 때마다) 시스템 로그, 소스 USER32, 이벤트 ID 1074에 하나 또는 두 개의 이벤트를 기록합니다. 관리 도구에서 이벤트 뷰어를 엽니 다 (시스템 로그를 필터링하여 ID 1074 만 표시). 이러한 이벤트의 설명 (메시지)에는 종료 유형이 들어 있습니다. 따라서이 유형의 가장 최근 이벤트 (종료가 시작된 후)의 설명을 구문 분석하여 필요한 단어 (종료, 재부팅/다시 시작)를 찾을 수 있습니다.

정상적으로 Windows를 종료하기 위해 전원 단추를 사용할 때 (일반적으로이 기능을 사용하지 않도록 설정) 이벤트에 기록 된 종료 유형을 보려고하지 않았지만 일부 사이트에서는 "전원 꺼짐"대신 "종료"- 당신이 확신 할 필요가 있다면 그것을 확인하십시오. 또는 단순히 "재부팅"유형을 찾으십시오. 발견되지 않으면 "종료"유형이 사용됩니다.

내 경험에 비추어 볼 때, 이벤트/1074는 프로그래밍 방식으로 (예 : 프로그램 설치 또는 shutdown.exe 유틸리티를 사용하여) 시스템 종료/재부팅을 수행 한 경우에만 기록됩니다. 따라서 셸 (Explorer)에서 시작된 종료를 등록하지는 않지만이 방법을 다른 대답에서 제안 된대로 레지스트리의 값을 읽는 것과 결합 할 수 있습니다. 또한 WinXP에서 이벤트 1074의 메시지에는 실제 종료 유형이 무엇이든 관계없이 "restart"라는 단어가 포함되어 있으므로 "Shutdown Type :"필드를 살펴보고 "shutdown"또는 "재부팅".

이와 관련하여 Windows가 어떤 이유 (예 : 응용 프로그램이 WM_QUERYENDSESSION에 대한 응답으로 종료를 허용하지 않는 경우)로 인해 시스템 종료/재부팅에 실패 할 때마다 이벤트 ID 1073이 기록됩니다. 이 경우 메시지에는 WinXP에서 "shutdown", "reboot"또는 "power off"와 같은 단어가 포함됩니다. Win7의 경우이 유형의 이벤트는 종료와 재부팅간에 차이를 만들지 않으므로 우리의 경우 덜 유용합니다. 그러나 WinXP의 경우 - 종료/재부팅을 가로 채기 만하면 일부 작업을 수행 한 다음 해당 종료 또는 재부팅 프로세스를 계속 진행하면 예상대로 작동합니다.

+1

"shutdown"또는 "reboot"과 같은 키워드가 운영 체제 현지화에 따라 다를 수 있으므로 EventLog에 현지화 된 메시지가 표시된다는 점에 유의해야합니다. – tpx86

1

Windows7의 가능한 실험 솔루션은 다음과 같습니다. 다음

using System.Diagnostics.Eventing.Reader; 

namespace MyApp 
{ 
public class RestartDetector : IDisposable 
{ 
    public delegate void OnShutdownRequsted(bool restart); 
    public OnShutdownRequsted onShutdownRequsted; 

    private EventLogWatcher watcher = null; 

    public RestartDetector() 
    { 
     try 
     { 
      EventLogQuery subscriptionQuery = new EventLogQuery(
       "System", PathType.LogName, "*[System[Provider[@Name='USER32'] and (EventID=1074)]]"); 

      watcher = new EventLogWatcher(subscriptionQuery); 

      // Make the watcher listen to the EventRecordWritten 
      // events. When this event happens, the callback method 
      // (EventLogEventRead) is called. 
      watcher.EventRecordWritten += 
       new EventHandler<EventRecordWrittenEventArgs>(
        EventLogEventRead); 

      // Activate the subscription 
      watcher.Enabled = true; 
     } 
     catch (EventLogReadingException e) 
     { 
     } 
    } 

    public void EventLogEventRead(object obj, EventRecordWrittenEventArgs arg) 
    { 
     bool restart = false; 
     try 
     { 
      // Make sure there was no error reading the event. 
      if (arg.EventRecord != null) 
      { 
       String[] xPathRefs = new String[1]; 
       xPathRefs[0] = "Event/EventData/Data"; 
       IEnumerable<String> xPathEnum = xPathRefs; 

       EventLogPropertySelector logPropertyContext = new EventLogPropertySelector(xPathEnum); 
       IList<object> logEventProps = ((EventLogRecord)arg.EventRecord).GetPropertyValues(logPropertyContext); 

       string[] eventData = (string[])logEventProps[0]; 

       foreach (string attribute in eventData) 
       { 
        if (attribute.Contains("restart")) { restart = true; break; } 
       } 
      } 
     } 
     catch (Exception e) 
     { 
     } 
     finally 
     { 
      if (onShutdownRequsted != null) { onShutdownRequsted(restart); } 
     } 
    } 

    public void Dispose() 
    { 
     // Stop listening to events 
     if (watcher != null) 
     { 
      watcher.Enabled = false; 
      watcher.Dispose(); 
     } 
    } 
} 
} 

는 PC를 다시 시작할 때 이벤트 로그에 기록됩니다 XML의 예입니다 (이것은 다른 언어 버전에서 잘 동작하는 지 여부 그래서 저는 내가 그것을 해결 방법을 부를 것이다, 잘 모르겠어요) :

- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event"> 
- <System> 
    <Provider Name="USER32" /> 
    <EventID Qualifiers="32768">1074</EventID> 
    <Level>4</Level> 
    <Task>0</Task> 
    <Keywords>0x80000000000000</Keywords> 
    <TimeCreated SystemTime="2015-12-15T11:10:43.000000000Z" /> 
    <EventRecordID>90416</EventRecordID> 
    <Channel>System</Channel> 
    <Computer>WIN7PC</Computer> 
    <Security UserID="S-1-5-21-1257383181-1549154685-2724014583-1000" /> 
    </System> 
- <EventData> 
    <Data>C:\Windows\system32\winlogon.exe (WIN7PC)</Data> 
    <Data>WIN7PC</Data> 
    <Data>No title for this reason could be found</Data> 
    <Data>0x500ff</Data> 
    <Data>restart</Data> 
    <Data /> 
    <Data>WIN7PC\WIN7PCUser</Data> 
<Binary>FF00050000000000000000000000000000000000000000000000000000000000</Binary> 
    </EventData> 
    </Event> 
관련 문제