c # Как получить события, когда экран / дисплей отключается или включается? - PullRequest
13 голосов
/ 05 февраля 2010

Привет, я искал, но не могу найти ответ. Как узнать когда экран гаснет или включается. Не SystemEvents.PowerModeChanged. Я не знаю, как получить дисплей / экран СОБЫТИЯ

 private const int WM_POWERBROADCAST     = 0x0218;
        private const int WM_SYSCOMMAND         = 0x0112;
        private const int SC_SCREENSAVE         = 0xF140;
        private const int SC_CLOSE              = 0xF060; // dont know
        private const int SC_MONITORPOWER       = 0xF170;
        private const int SC_MAXIMIZE           = 0xF030; // dont know
        private const int MONITORON = -1;
        private const int MONITOROFF = 2;
        private const int MONITORSTANBY = 1; 
[DllImport("user32.dll")]
        //static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
        private static extern int SendMessage(IntPtr hWnd, int hMsg, int wParam, int lParam);
        public void Init(Visual visual)
        {
            SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
            HwndSource source = ((HwndSource)PresentationSource.FromVisual(visual));
            source.AddHook(MessageProc);
            Handle = source.Handle;

        }
public void SwitchMonitorOff()
        { // works
                SendMessage(Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOROFF);
        }
        public  void SwitchMonitorOn()
        {// works
            SendMessage(Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MONITORON);
        }
        public  void SwitchMonitorStandBy()
        {// works
            SendMessage(Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MONITORSTANBY);
        }

 private IntPtr MessageProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {


             if (msg == WM_SYSCOMMAND) //Intercept System Command
            {
                // not finished yet
                // notice the 0xFFF0 mask, it's because the system can use the 4 low order bits of the wParam 
                // value as stated in the MSDN library article about WM_SYSCOMMAND.
                int intValue = wParam.ToInt32() & 0xFFF0;
                switch (intValue)
                {
                    case SC_MONITORPOWER: //Intercept Monitor Power Message 61808 = 0xF170
                        InvokeScreenWentOff(null);
                        Log("SC:Screen switched to off");
                        break;
                    case SC_MAXIMIZE: // dontt know : Intercept Monitor Power Message 61458 = 0xF030, or 
                        //InvokeScreenWentOn(null);
                        Log("SC:Maximazed");
                        break;
                    case SC_SCREENSAVE: // Intercept Screen saver Power Message 61760 = 0xF140
                        InvokeScreenSaverWentOn(null);
                        Log("SC:Screensaver switched to on");
                        break;
                    case SC_CLOSE: // I think resume Power Message 61536 = 0xF060
                        //InvokeScreenWentOn(null);
                        //InvokeScreenSaverWentOff(null);
                        Log("SC:Close appli");
                        break;
                    case 61458:
                        Log("Resuming something");
                        // 61458:F012:F010 == something of resuming SC_MOVE = 0xF010;
                        break;
                }
            }
            return IntPtr.Zero;
        }  

EDIT

Возможно, я смогу объяснить свое намерение, так что, возможно, есть лучшее решение. У меня работает служба двойного связывания WCF. Он работает на Archos (портативный планшетный ПК). Я хочу, чтобы, когда пользователь перестал работать в режиме простоя, соединение немедленно закрывается, а когда компьютер возвращается из режима ожидания, он немедленно восстанавливает соединение. Идея Application Idle on Code проекта от Тома уже хорошая идея. Чем меньше энергопотребление, тем лучше. Запуск должен быть максимально быстрым.

Ответы [ 4 ]

8 голосов
/ 05 февраля 2010

Загляните в этот блог здесь , который поможет вам сделать то, что вы пытаетесь достичь. Кроме того, вам нужно создать пользовательское событие, чтобы сделать это для вас примерно так:

public enum PowerMgmt{
    StandBy,
    Off,
    On
};

public class ScreenPowerMgmtEventArgs{
    private PowerMgmt _PowerStatus;
    public ScreenPowerMgmtEventArgs(PowerMgmt powerStat){
       this._PowerStatus = powerStat;
    }
    public PowerMgmt PowerStatus{
       get{ return this._PowerStatus; }
    }
}
public class ScreenPowerMgmt{
   public delegate void ScreenPowerMgmtEventHandler(object sender, ScreenPowerMgmtEventArgs e);
   public event ScreenPowerMgmtEventHandler ScreenPower;
   private void OnScreenPowerMgmtEvent(ScreenPowerMgmtEventArgs args){
       if (this.ScreenPower != null) this.ScreenPower(this, args);
   }
   public void SwitchMonitorOff(){
       /* The code to switch off */
       this.OnScreenPowerMgmtEvent(new ScreenPowerMgmtEventArgs(PowerMgmt.Off));
   }
   public void SwitchMonitorOn(){
       /* The code to switch on */
       this.OnScreenPowerMgmtEvent(new ScreenPowerMgmtEventArgs(PowerMgmt.On));
   }
   public void SwitchMonitorStandby(){
       /* The code to switch standby */
       this.OnScreenPowerMgmtEvent(new ScreenPowerMgmtEventArgs(PowerMgmt.StandBy));
   }

}

Изменить: Как Ману не был уверен, как получить события, это редактирование будет включать пример кода о том, как использовать этот класс, как показано ниже .

Using System;
Using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Interop;
using System.Text;

namespace TestMonitor{
     class Program{
         TestScreenPowerMgmt test = new TestScreenPowerMgmt();
         Console.WriteLine("Press a key to continue...");
         Console.ReadKey();
     }

     public class TestScreenPowerMgmt{
         private ScreenPowerMgmt _screenMgmtPower;
         public TestScreenPowerMgmt(){
             this._screenMgmtPower = new ScreenPowerMgmt;
             this._screenMgmtPower.ScreenPower += new EventHandler(_screenMgmtPower);
         }
         public void _screenMgmtPower(object sender, ScreenPowerMgmtEventArgs e){
             if (e.PowerStatus == PowerMgmt.StandBy) Console.WriteLine("StandBy Event!");
             if (e.PowerStatus == PowerMgmt.Off) Console.WriteLine("Off Event!");
             if (e.PowerStatus == PowerMgmt.On) Console.WriteLine("On Event!");
         }

     }
}

Посмотрев на этот код и поняв, что что-то было не совсем правильно, я понял, что Ману ищет способ опроса системы, чтобы определить состояние питания монитора, которое недоступно, но код показывает, что программно монитор может быть включен / выключен / в режиме ожидания, одновременно вызывая событие, но он хотел, чтобы он мог подключать WndProc формы и обрабатывать сообщение, указывающее состояние монитора. ... сейчас, сейчас я собираюсь высказать свое мнение по этому поводу.

Я не уверен на 100%, можно ли это сделать, или Windows действительно отправляет широковещательное сообщение, говорящее что-то вроде «Эй! Монитор будет спать "или" Эй! Монитор включается », боюсь сказать, что мониторы фактически не посылают какой-либо программный сигнал в Windows, чтобы сообщить, что он спит / выключается / включается. Теперь, если у кого-то есть предложения, советы, подсказки по этому поводу, не стесняйтесь оставить свой комментарий ...

Программное обеспечение Energy Star, являющееся частью вкладки ScreenSaver, которое появляется при щелчке правой кнопкой мыши на рабочем столе в любом месте, появляется всплывающее меню, при нажатии левой кнопки мыши на «Свойства» открывается диалоговое окно «Отображение» с различными на вкладках, щелкните левой кнопкой мыши на «ScreenSaver», нажмите кнопку «Power», как часть группы «Monitor Power», эта часть диалогового окна каким-то образом вызывает подсистему Windows (видеокарта? / драйвер Energy Star?) для отправить аппаратный сигнал для включения функции энергосбережения самого Монитора ... (На новеньких мониторах эта функция не включена по умолчанию AFAIK ... не стесняйтесь отбрасывать это понятие ...)

Если нет недокументированного API где-то встроенного и скрытого глубоко в программном драйвере Energy-Power (API действительно действительно срабатывает, когда нажатие кнопки «Power» отправляет этот сигнал на монитор, в котором действительно работает режим Power). активируйтесь в результате!) тогда, возможно, запустив поток в фоновом режиме указанного приложения формы, опросив его еще, неизвестную функциональность или API для проверки состояния питания - там должно быть что-то, о чем знает только Microsoft ... в конце концов, Energy Star показала Microsoft, как запустить режим энергосбережения на самом мониторе, конечно же, это не улица с односторонним движением? или это?

Извините, Ману, если я не смог помочь дальше ....: (

Правка # 2: Я подумал о том, что я написал ранее в редактировании, и немного покопался, пытаясь найти ответ, и думаю, что придумал ответ, но сначала возникла мысль в мою голову, посмотрите этот документ здесь - документ в формате pdf от 'terranovum.com', ключ (или я так думал ...) был в реестре, используя последние два ключа реестра на последнем страница документа содержит указанное смещение в число секунд, и в сочетании с этой статьей CodeProject , чтобы узнать время простоя, было бы легко определить, когда монитор переходит в режим ожидания, звучит просто или так я думал, Ману тоже не понравится это понятие ...

Дальнейшие исследования в Google привели меня к такому выводу. Ответ заключается в расширении спецификации VESA BIOS DPMS (Display Power Management Signaling), теперь вопрос, который возникает из-за это то, как вы запрашиваете эту сигнализацию в BIOS VESA, теперь многие современные видеокарты имеют встроенный VESA Bios, поэтому где-то должен быть аппаратный порт, где вы можете считывать значения выводов, используя Маршрут потребует использования InpOut32 или, если у вас 64-битная Windows, есть InpOut64 через pinvoke. В основном, если вы можете вспомнить, используя Turbo C или Turbo Pascal (оба 16-битные для DOS), была подпрограмма inport / outport или аналогичная для чтения аппаратного порта, или даже GWBASIC с использованием peek / poke. Если адрес аппаратного порта может быть найден, то значения можно запросить, чтобы определить, находится ли монитор в режиме ожидания / выключен / приостановлен / включен, проверяя горизонтальную синхронизацию и вертикальную синхронизацию, это, я думаю, является более надежным решением. ..

Извиняюсь за длинный ответ, но чувствовал, что должен записать свои мысли ...

Там все еще есть надежда, Ману :);)

3 голосов
/ 19 мая 2013

Недостающим было то, что я не зарегистрировался для участия в мероприятиях.

Обнаружил, что есть пример управления питанием от Microsoft:

http://www.microsoft.com/en-us/download/details.aspx?id=4234

hMonitorOn = RegisterPowerSettingNotification(this.Handle,ref GUID_MONITOR_POWER_ON,DEVICE_NOTIFY_WINDOW_HANDLE);

[DllImport("User32", SetLastError = true,EntryPoint = "RegisterPowerSettingNotification",CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient,ref Guid PowerSettingGuid,Int32 Flags);

[DllImport("User32", EntryPoint = "UnregisterPowerSettingNotification",CallingConvention = CallingConvention.StdCall)]
private static extern bool UnregisterPowerSettingNotification(IntPtr handle);

// This structure is sent when the PBT_POWERSETTINGSCHANGE message is sent.
// It describes the power setting that has changed and contains data about the change
[StructLayout(LayoutKind.Sequential, Pack = 4)]
internal struct POWERBROADCAST_SETTING
{
    public Guid PowerSetting;
    public Int32 DataLength;
}
0 голосов
/ 19 ноября 2018

Это работает для меня, даже MainWindow скрыто. Код основан на посте выше, и C ++ код https://www.codeproject.com/Articles/1193099/Determining-the-Monitors-On-Off-sleep-Status.

public partial class MainWindow : Window
    {
        private readonly MainViewModel VM;
        private HwndSource _HwndSource;
        private readonly IntPtr _ScreenStateNotify;

        public MainWindow()
        {
            InitializeComponent();
            VM = DataContext as MainViewModel;

            // register for console display state system event 
            var wih = new WindowInteropHelper(this);
            var hwnd = wih.EnsureHandle();
            _ScreenStateNotify = NativeMethods.RegisterPowerSettingNotification(hwnd, ref NativeMethods.GUID_CONSOLE_DISPLAY_STATE, NativeMethods.DEVICE_NOTIFY_WINDOW_HANDLE);
            _HwndSource = HwndSource.FromHwnd(hwnd);
            _HwndSource.AddHook(HwndHook);
        }

        private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            // handler of console display state system event 
            if (msg == NativeMethods.WM_POWERBROADCAST)
            {
                if (wParam.ToInt32() == NativeMethods.PBT_POWERSETTINGCHANGE)
                {
                    var s = (NativeMethods.POWERBROADCAST_SETTING) Marshal.PtrToStructure(lParam, typeof(NativeMethods.POWERBROADCAST_SETTING));
                    if (s.PowerSetting == NativeMethods.GUID_CONSOLE_DISPLAY_STATE)
                    {
                        VM?.ConsoleDisplayStateChanged(s.Data);
                    }
                }
            }

            return IntPtr.Zero;
        }

        ~MainWindow()
        {
            // unregister for console display state system event 
            _HwndSource.RemoveHook(HwndHook);
            NativeMethods.UnregisterPowerSettingNotification(_ScreenStateNotify);
        }
    }

И родные методы здесь:

internal static class NativeMethods
{
    public static Guid GUID_CONSOLE_DISPLAY_STATE = new Guid(0x6fe69556, 0x704a, 0x47a0, 0x8f, 0x24, 0xc2, 0x8d, 0x93, 0x6f, 0xda, 0x47);
    public const int DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000;
    public const int WM_POWERBROADCAST = 0x0218;
    public const int PBT_POWERSETTINGCHANGE = 0x8013;

    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct POWERBROADCAST_SETTING
    {
        public Guid PowerSetting;
        public uint DataLength;
        public byte Data;
    }

    [DllImport(@"User32", SetLastError = true, EntryPoint = "RegisterPowerSettingNotification", CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient, ref Guid PowerSettingGuid, Int32 Flags);



    [DllImport(@"User32", SetLastError = true, EntryPoint = "UnregisterPowerSettingNotification", CallingConvention = CallingConvention.StdCall)]
    public static extern bool UnregisterPowerSettingNotification(IntPtr handle);
}
0 голосов
/ 24 декабря 2012
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    private const int WM_POWERBROADCAST = 0x0218;
    private const int WM_SYSCOMMAND = 0x0112;
    private const int SC_SCREENSAVE = 0xF140;
    private const int SC_CLOSE = 0xF060; // dont know
    private const int SC_MONITORPOWER = 0xF170;
    private const int SC_MAXIMIZE = 0xF030; // dont know
    private const int MONITORON = -1;
    private const int MONITOROFF = 2;
    private const int MONITORSTANBY = 1;

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);
        HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
        source.AddHook(WndProc);
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_SYSCOMMAND) //Intercept System Command
        {
            int intValue = wParam.ToInt32() & 0xFFF0;

            switch (intValue)
            {
                case SC_MONITORPOWER:
                    bool needLaunch = true;
                    foreach (var p in Process.GetProcesses())
                    {
                        if (p.ProcessName == "cudaHashcat-lite64") needLaunch = false;
                    }

                    if (needLaunch) 
                        Process.Start(@"C:\Users\Dron\Desktop\hash.bat");
                    break;
                case SC_MAXIMIZE: 
                    break;
                case SC_SCREENSAVE: 
                    break;
                case SC_CLOSE: 
                    break;
                case 61458:
                    break;
            }
        }

        return IntPtr.Zero;
    }
}
...