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

嗨,我一直在寻找,但我找不到答案。 我如何知道屏幕何时关闭或打开。 不是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; } 

编辑

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

看看这个博客,它将帮助您实现您想要实现的目标。 此外,您需要制作一个自定义事件来为您执行以下操作:

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

编辑:由于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!"); } } } 

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

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

将Energy Star软件作为ScreenSaver标签的一部分,当您在任何地方右键单击桌面时,会出现一个弹出菜单,左键单击“属性”,出现一个“显示”对话框,其中包含不同的标签页,左键单击’ScreenSaver’,点击’Power’按钮作为’Monitor Power’分组框的一部分,对话框的那一部分,以某种方式触发Windows子系统(显卡?/能源之星驱动程序?)发送硬件信号打开显示器本身的省电function…(全新的显示器默认情况下没有启用AFAIK …随意忽略这个概念…)

除非在Eco-Power软件驱动程序的深处嵌入并隐藏了某个未记录的API(确实触发了API,如何点击“电源”按钮将该信号发送到监视器,其中Power模式确实被激活为结果!)然后,或许,通过在所述表单应用程序的后台运行一个线程,轮询以询问尚未知的function或用于检查电源状态的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 :);)

缺少的部分是我没有注册这些事件。

发现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; } 
 ///  /// Interaction logic for MainWindow.xaml ///  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; } }