2009-06-11 24 views
14

Tôi biết rằng khi Windows tắt, nó sẽ gửi thông báo WM_QUERYENDSESSION cho mỗi ứng dụng. Điều này giúp dễ dàng phát hiện khi Windows tắt. Tuy nhiên, nó có thể biết nếu máy tính sẽ tắt nguồn hoặc là nó sẽ khởi động lại sau khi Windows đã tắt máy.Cách phát hiện xem Windows có tắt hay khởi động lại

Tôi không đặc biệt hy vọng, xem xét các tài liệu tại MSDN có này để nói về WM_QUERYENDSESSION: "... nó không phải là có thể để xác định sự kiện đang xảy ra", nhưng sự thông minh tích lũy của stackoverflow không bao giờ hết ngạc nhiên tôi.

Trả lời

5

Từ here:

Bạn có thể đọc các giá trị DWORD từ "HKCU \ Software \ Microsoft \ Windows \ CurrentVersion \ Explorer \ Shutdown Setting" để xác định những gì người dùng cuối cùng được lựa chọn từ Shut Down hộp thoại.

Một chút của giải pháp bùng binh, nhưng cần thực hiện thủ thuật.

+11

Đó là tất nhiên giả định rằng hệ thống hiện đang tắt vì người dùng hiện tại đã khởi chạy nó và đã làm như vậy trong Explorer. Nếu đây là một tắt chương trình, tắt máy từ một ứng dụng khác, hoặc tắt máy bởi một người dùng khác, bạn sẽ có lý do cho việc tắt máy trước đó. – MSalters

+5

-1 Vì câu trả lời không đầy đủ và cụ thể cho Windows Explorer. Nó cũng xuất hiện để được ** gỡ bỏ ** trong Windows 7. – unixman83

+1

Nó hoạt động tốt dưới WindowsXP nhưng không dưới Windows7 – conceptacid

5

Bí quyết thường hoạt động là bẫy WM_ENDSESSION và ghi nhật ký. Bây giờ theo dõi thời gian. Nếu hệ thống trở lại trong một khoảng cách hợp lý (nói 5 phút). Sau đó, đó là một khởi động lại, không phải là tắt máy.

Idea: Nếu hệ thống hoạt động trở lại trong vòng 5 phút, có phải nó thực sự vấn đề nếu người dùng nhấp 'tắt' hoặc 'reboot'?

Nếu bạn thực sự cần phải phát hiện một shutdown (và lý do duy nhất tôi nghĩ rằng bạn cần phải làm điều này là nếu bạn đang phụ thuộc vào một sự khác biệt phần mềm về hành vi che khuất giữa một shutdown vs khởi động lại), bạn có thể tra API hooking của ExitWindowsEx và các chức năng liên quan nhưng tôi không khuyên bạn nên sử dụng phương pháp này. Suy nghĩ lại nếu bạn thực sự cần phải phát hiện trực tiếp điều này.

+1

+1 cho đề xuất gợi ý API. Đề xuất kiểm tra thời gian là phỏng đoán thuần túy. –

+0

@Joe, Với quản lý nguồn ACPI hiện đại: Sleep, Hibernate, Wake On LAN, v.v. Định nghĩa khởi động lại (hoặc khởi động ấm) đang trở nên khó xác định. Những gì hầu hết mọi người có nghĩa là bằng cách khởi động lại (hoặc đủ gần) là hệ thống không ở trạng thái bình thường trong một khoảng thời gian * rất ngắn. – unixman83

6

Trong Windows 7 (và cũng có thể trong Vista/8/Server), bạn có thể sử dụng các sự kiện hệ thống để theo dõi xem Windows đang tắt (và tắt nguồn máy tính) hay chỉ khởi động lại. Mỗi lần tắt/khởi động lại (bằng bất kỳ phương tiện nào - nhấp vào nút trong menu Bắt đầu hoặc lập trình), Windows 7 viết một hoặc hai sự kiện trong Nhật ký hệ thống, nguồn USER32, ID sự kiện 1074. Bạn có thể xem các sự kiện này được ghi nếu bạn mở Trình xem sự kiện từ Công cụ quản trị (lọc Nhật ký hệ thống để chỉ xem ID 1074). Mô tả (tin nhắn) của các sự kiện này chứa kiểu tắt máy. Vì vậy, bạn có thể phân tích cú pháp mô tả về sự kiện gần đây nhất của loại này (sau khi tắt máy), tìm kiếm từ cần thiết (tắt máy, khởi động lại/khởi động lại).

Tôi không cố gắng xem kiểu tắt được viết trong trường hợp sử dụng nút nguồn để tắt Windows một cách duyên dáng (tôi thường tắt chức năng này), nhưng một số trang gợi ý rằng nó cho biết loại "tắt nguồn" thay vì "tắt máy" - vì vậy hãy kiểm tra, nếu bạn cần chắc chắn. Hoặc đơn giản là tìm kiểu "khởi động lại" - nếu nó không được tìm thấy, thì kiểu "tắt máy" được giả định.

Trong Windows XP, theo kinh nghiệm của tôi, sự kiện 1074 chỉ được ghi nếu tắt/khởi động lại được lập trình (ví dụ: trong khi cài đặt chương trình hoặc sử dụng tiện ích shutdown.exe). Vì vậy, nó không đăng ký tắt máy bắt đầu từ trình bao (Explorer), nhưng có lẽ bạn có thể kết hợp phương thức này với việc đọc giá trị từ sổ đăng ký như được đề xuất trong câu trả lời khác. Ngoài ra, hãy nhớ rằng trong WinXP thông điệp của sự kiện 1074 chứa từ "khởi động lại" bất kể loại tắt máy thực sự là gì, vì vậy bạn nên xem trường "Shutdown Type:", trạng thái sẽ "shutdown" hoặc "khởi động lại".

Liên quan đến điều này, ID sự kiện 1073 được ghi lại bất cứ khi nào Windows không tắt/khởi động lại vì lý do nào đó (ví dụ: nếu ứng dụng không cho phép tắt máy dưới dạng phản hồi với WM_QUERYENDSESSION). Trong trường hợp đó, thông báo cũng sẽ chứa các từ như "tắt máy", "khởi động lại" hoặc "tắt nguồn" - trong WinXP. Đối với Win7 loại sự kiện này ít hữu ích hơn trong trường hợp của chúng tôi, vì nó sẽ không tạo ra bất kỳ sự khác biệt nào giữa tắt máy và khởi động lại. Nhưng đối với WinXP - nếu bạn chỉ cần chặn việc tắt/khởi động lại, thực hiện một số thao tác, sau đó tiếp tục quá trình tắt hoặc khởi động lại tương ứng - nó sẽ hoạt động như mong đợi.

+1

Điều quan trọng cần lưu ý là EventLog hiển thị các thông điệp được bản địa hóa để các từ khóa như "tắt máy" hoặc "khởi động lại" sẽ khác nhau tùy thuộc vào nội địa hóa hệ điều hành. – tpx86

1

Giải pháp thử nghiệm có thể có cho Windows7 có thể như sau. (Tôi không chắc chắn nếu điều này hoạt động tốt với địa phương hóa khác, do đó tôi sẽ gọi nó là một workaround)

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(); 
     } 
    } 
} 
} 

Sau đây là một ví dụ về XML mà được ghi vào nhật ký sự kiện khi một máy tính được khởi động lại:

- <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> 
Các vấn đề liên quan