本文介绍了c#屏幕/显示屏关闭或打开时如何获取事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在搜索,但我找不到答案。如何知道屏幕何时关闭或打开。不是SystemEvents.PowerModeChanged。
我不知道如何检索显示/屏幕EVENTS

  private const int WM_POWERBROADCAST = 0x0218; 
private const int WM_SYSCOMMAND = 0x0112;
private const int SC_SCREENSAVE = 0xF140;
private const int SC_CLOSE = 0xF060; //不知道
private const int SC_MONITORPOWER = 0xF170;
private const int SC_MAXIMIZE = 0xF030; //不知道
private const int MONITORON = -1;
private const int MONITOROFF = 2;
private const int MONITORSTANBY = 1;
[DllImport(user32.dll)]
//静态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 processed)
{


if(msg == WM_SYSCOMMAND)//拦截系统命令
{
//尚未完成
//注意0xFFF0掩码,这是因为系统可以使用4个低位位wParam
//如MSDN库文章中关于WM_SYSCOMMAND所述的值。
int intValue = wParam.ToInt32()& 0xFFF0;
switch(intValue)
{
case SC_MONITORPOWER:// Intercept Monitor Power Message 61808 = 0xF170
InvokeScreenWentOff(null);
日志(SC:屏幕切换到关闭);
break;
case SC_MAXIMIZE:// dontt知道:截取监视器电源消息61458 = 0xF030或
// InvokeScreenWentOn(null);
Log(SC:Maximazed);
break;
case SC_SCREENSAVE://拦截屏幕保护程序电源消息61760 = 0xF140
InvokeScreenSaverWentOn(null);
日志(SC:屏幕保护程序切换到);
break;
case SC_CLOSE://我认为恢复电源消息61536 = 0xF060
// InvokeScreenWentOn(null);
// InvokeScreenSaverWentOff(null);
Log(SC:Close appli);
break;
case 61458:
日志(恢复某事);
// 61458:F012:F010 ==某些恢复SC_MOVE = 0xF010;
break;
}
}
return IntPtr.Zero;
}

编辑



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

解决方案

看看这个博客,这将帮助你做你想要实现的。另外你需要做一个自定义的事件来为你做这样的事情:

  public enum PowerMgmt {
StandBy,
关闭,

};

public class ScreenPowerMgmtEventArgs {
private PowerMgmt _PowerStatus;
public Sc​​reenPowerMgmtEventArgs(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(){
/ *关闭代码* /
this.OnScreenPowerMgmtEvent(new ScreenPowerMgmtEventArgs(PowerMgmt.Off));
}
public void SwitchMonitorOn(){
/ *打开代码* /
this.OnScreenPowerMgmtEvent(new ScreenPowerMgmtEventArgs(PowerMgmt.On));
}
public void SwitchMonitorStandby(){
/ *切换待机的代码* /
this.OnScreenPowerMgmtEvent(new ScreenPowerMgmtEventArgs(PowerMgmt.StandBy));
}

}

编辑: strong> As Manu 不知道如何检索事件,此修改将包含如何使用此类的示例代码,如下所示。

 使用系统; 
使用System.Collections.Generic;
使用System.Diagnostics;
使用System.Linq;
使用System.Runtime.Interop;
使用System.Text;

命名空间TestMonitor {
类程序{
TestScreenPowerMgmt test = new TestScreenPowerMgmt();
Console.WriteLine(按键继续...);
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!);
}

}
}

在这段代码中,意识到某些东西不是很正确,但是在我看来,Manu正在寻找一种方式来询问系统来检测显示器的电源状态,这是不可用的,但代码显示了以编程方式,显示器可以打开/关闭/待机,同时触发事件,但他希望能够钩住表单的 WndProc 并处理消息,指示监视器的状态...现在,在这一点上,我将对此表达我的意见。



我不是100%肯定是否可以完成或者Windows实际上发送一个广播消息,说出嘿!监视器正在睡觉或嘿!监视器正在加载,我恐怕说,监视器实际上并没有向Windows发送一些软件信号,以通知它将要睡眠/关闭/关闭。现在如果有任何人有建议,提示,线索,请随时发表您的评论...



能量之星软件作为ScreenSaver选项卡的一部分被发现当您右键单击桌面时,会出现一个弹出菜单,左键单击属性,出现显示对话框,具有不同的选项卡页面,左键单击屏幕保护程序,单击电源按钮作为监视器电源分组框的一部分,该对话框的一部分以某种方式触发Windows子系统(显卡?/能源之星驱动程序?)发送硬件信号,以切换监视器本身的节能功能。 (全新的监视器默认情况下不启用此功能)AFAIK ...随意驳回这个概念...)



除非有一个未记录的API嵌入式和深埋在Energy-Power软件驱动程序(一个API绝对确实触发了如何点击电源按钮将该信号发送到t他的监视器,其中功率模式确实被激活了结果!)然后也许,通过在所述表单应用程序的后台运行一个线程,轮询询问那个未知功能或API来检查电源状态 - 那里必须在那里只有微软知道...毕竟,能源之星显示微软如何触发监视器本身的省电模式,肯定不是一条路?或者是吗?



对不起Manu如果我不能进一步帮助....:(



编辑#2:我想到了我之前在编辑中写过的内容,并且为了解答而做了一些挖掘,我想我想出了一个答案,但首先,一个想法涌入我的头脑,请参阅此文档 - 从 terranovum.com',线索(或所以我以为...)在注册表中,使用文档的最后一页上的最后两个注册表项包含指定的偏移量到秒数,并结合此 CodeProject 文章,找出空闲时间,这将很容易确定何时显示器进入待机状态,听起来很简单,所以我想,马努不会喜欢这个概念....



进一步调查谷歌导致我的结论,答案在于扩展规范(显示电源管理信令),现在由此产生的问题是如何您询问VESA bios上的信号,现在,许多现代显卡已经安装了VESA Bios,因此必须有一个硬件端口可以读取引脚的值,使用此路由将需要使用的,或者如果您有64位Windows,则通过pinvoke,。基本上如果你可以回想起使用Turbo C或Turbo Pascal(这两个16位DOS),都有一个叫做inport / outport或类似的例程来读取硬件端口,甚至是使用peek / poke的GWBASIC。如果可以找到硬件端口的地址,则可以通过检查水平同步和垂直同步来查询这些值,以确定监视器是否处于待机/关闭/挂起/启动状态,这是我可靠的解决方案。对于长长的答复抱歉,但觉得我不得不写下我的想法....



还有希望有Manu :);)


Hi I have been searching but I can't find the answer. How do I know when the screen is going off or on. Not the SystemEvents.PowerModeChanged .I dont know how to retrieve the display/screen EVENTS

 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

Perhaps I can explain my intension, so there is perhaps a better solution. I have a Dual binding WCF service running on. It's running on an archos (portable tablet pc). I want that when the user stopped working for an idle time, the connection closes immediatly, and when the computer is returning from idle, he reconnects immediatly. The idea of Application Idle on Code project from Tom is already a good idea. The less power consumption , the better. The startup must be as fast as possible.

解决方案

Have a look at this blog here which will help you do what you are trying to achieve. In addition you need to make a custom event to do this for you something like this:

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

}

Edit: As Manu was not sure how to retrieve the events, this edit will include a sample code on how to use this class as shown below.

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

     }
}

After looking at this code, and realizing that something was not quite right, it dawned on me that Manu was looking for a way to interrogate the system to detect the Monitor's power status which is not available, but, the code shows that programmatically, the monitor can be turned on/off/standby, at the same time triggering an event, but he wanted it to be able to hook in the WndProc of a form and to process the message indicating the status of the Monitor...now, at this point, I am going to express my opinion on this.

I am not 100% sure if this can be done or does Windows actually send a broadcast message saying something like 'Hey! Monitor is going to sleep' or 'Hey! Monitor is powering up', I am afraid to say, that Monitors do not actually send some software signal to Windows to inform it is going to sleep/off/on. Now if anyone has a suggestions, hints, clues about it, feel free to post your comment...

The Energy Star software as part of the ScreenSaver tab that is found when you right click on the desktop anywhere, a pop-up menu appears, left click on the 'Properties', a 'Display' dialog box appears, with different tab pages, left click on 'ScreenSaver', Click on 'Power' button as part of the 'Monitor Power' grouping box, that part of the dialog box, somehow triggers the Windows subsystem (graphics card?/Energy Star driver?) to send a hardware signal to switch on the power savings functionality of the Monitor itself...(Monitors that are brand new do not have this enabled by default AFAIK...feel free to dismiss this notion...)

Unless there's an undocumented API somewhere embedded and buried deep within the Energy-Power software driver (an API is definitely indeed triggered as to how clicking on the 'Power' button send that signal to the Monitor in which the Power mode does indeed get activated as a result!) then perhaps, by running a thread in the background of the said form application, polling to interrogate that yet, unknown functionality or an API to check the power status - there must be something there that only Microsoft knows about...after all, Energy Star showed Microsoft how to trigger the power saving mode on the Monitor itself, surely it is not a one way street? or is it?

Sorry Manu if I could not help further .... :(

Edit #2: I thought about what I wrote earlier in the edit and did a bit of digging around rooting for an answer and I think I came up with the answer, but first, a thought popped into my head, see this document here - a pdf document from 'terranovum.com', the clue (or so I thought...) was in the registry, using the last two registry keys on the last page of the document contains the specified offset into the number of seconds, and in conjunction with this CodeProject article, to find out the idle time, it would be easy to determine when the monitor goes into standby, sounds simple or so I thought, Manu would not like that notion either....

Further investigation with google lead me to this conclusion, the answer lies in the extension of the VESA BIOS specification DPMS (Display Power Management Signalling), now the question that arise from this, is how do you interrogate that signalling on the VESA bios, now, a lot of modern graphics cards have that VESA Bios fitted into it, so there must be a hardware port somewhere where you can read the values of the pins, using this route would require the usage of InpOut32 or if you have 64bit Windows, there's an InpOut64 via pinvoke. Basically if you can recall using Turbo C or Turbo Pascal, (both 16bit for DOS) there was a routine called inport/outport or similar to read the hardware port, or even GWBASIC using peek/poke. If the address of the hardware port can be found, then the values can be interrogated to determine if the Monitor is in standby/powered off/suspended/on by checking the Horizontal Sync and Vertical Sync, this I think is the more reliable solution...

Apologies for the long answer but felt I had to write down my thoughts....

There's still hope there Manu :) ;)

这篇关于c#屏幕/显示屏关闭或打开时如何获取事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 17:09