c#当屏幕/显示器关闭或打开电源时如何获取事件?

Man*_*anu 13 c# events screen monitor

嗨,我一直在寻找,但我找不到答案.我怎么知道屏幕何时关闭或打开.不是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;
        }  
Run Code Online (Sandbox Code Playgroud)

编辑

也许我可以解释我的意图,所以也许有更好的解决方案.我正在运行双绑定WCF服务.它在archos(便携式平板电脑)上运行.我希望当用户停止工作一段空闲时间时,连接立即关闭,当计算机从空闲状态返回时,他立即重新连接.Tom 的应用程序空闲代码项目的想法已经是一个好主意.功耗越小越好.启动必须尽可能快.

t0m*_*13b 8

看看这个博客在这里,这将帮助你做你想要达到的目的.此外,您需要制作一个自定义事件来为您执行以下操作:

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

}
Run Code Online (Sandbox Code Playgroud)

编辑:由于Manu不确定如何检索事件,此编辑将包含有关如何使用此类的示例代码,如下所示.

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!");
         }

     }
}
Run Code Online (Sandbox Code Playgroud)

看着这个代码,并意识到事情不太对之后,我明白了马努一直在寻找一种方式来询问系统检测到显示器的电源状态是不可用的,但是,该代码显示编程中,监视器可以打开/关闭/待机,同时触发事件,但他希望它能够挂钩WndProc表单并处理指示监视器状态的消息...现在,在此我要对此发表意见.

我不是百分百确定是否可以这样做,或者Windows实际上发送的广播消息是"嘿!监视器将要睡觉'或'嘿!监视器正在加电',我担心,监视器实际上并没有向Windows发送一些软件信号,以告知它将进入休眠/关闭/打开状态.现在,如果有人有任何建议,提示,线索,请随时发表您的评论......

能源之星软件作为屏幕保护程序选项卡的一部分,当您在任何地方右键单击桌面时,会出现一个弹出菜单,左键单击"属性",出现一个"显示"对话框,其中包含不同的标签页,在"屏幕保护程序"左键点击,点击"电源"按钮,为"显示器电源"分组框,对话框的那部分的一部分,不知何故会触发Windows子系统(显卡?/能源之星司机?)发送一个硬件信号打开显示器本身的省电功能......(全新的显示器默认情况下没有启用AFAIK ...随意忽略这个概念...)

除非有什么地方嵌入埋内的能量功耗软件驱动程序深(API是绝对确实引发对如何在"电源"按钮,点击该信号发送到其中的电源模式确实得到激活为Monitor的未公开的API结果!)然后,或许,通过在所述表单应用程序的后台运行一个线程,轮询以询问尚未知的功能或用于检查电源状态的API - 必须有一些只有微软知道的东西......毕竟,能源之星向微软展示了如何触发显示器本身的省电模式,当然它不是一条单行道?或者是吗?

对不起Manu,如果我无法进一步帮助...... :(

编辑#2:我想过,我刚才在编辑撰写并做了一些四处生根的答案,我认为我想出了答案,但首先,一个念头突然出现在我的头上,看到这个文件在这里 -来自'terranovum.com'的pdf文档,线索(或者我认为......)在注册表中,使用文档最后一页上的最后两个注册表项包含指定的秒数偏移量,以及结合这个CodeProject文章,找出空闲时间,很容易确定显示器何时进入待机状态,听起来很简单,或者我认为,Manu不会喜欢这个概念......

进一步调查谷歌引导我得出这个结论,答案在于扩展VESA BIOS规范DPMS(显示电源管理信令),现在由此产生的问题是,你如何查询VESA BIOS上的信令,现在,很多现代显卡都装有VESA Bios,因此必须有一个硬件端口可以读取引脚的值,使用这条路线需要使用InpOut32,或者如果你有64位Windows,那么一个InpOut64通过pinvoke.基本上如果你能回想起使用Turbo C或Turbo Pascal(两者都是16位的DOS),就会有一个叫做inport/outport或类似的例程来读取硬件端口,甚至是使用peek/poke读取GWBASIC.如果可以找到硬件端口的地址,则可以通过检查水平同步和垂直同步来查询值以确定监视器是处于待机/断电/暂停/打开状态,我认为这是更可靠的解决方案. ..

为长篇答案道歉,但觉得我不得不写下我的想法....

还有希望Manu :);)

  • 不是真的,你如何检索事件。如何知道电源是打开还是关闭?- 10 分钟后我的屏幕变暗。- 15 分钟后我的屏幕关闭。- 我移动鼠标,屏幕亮起。如何获得这个事件?(不是会话事件) (2认同)