17

こんにちは私は探していましたが、答えが見つかりません。画面がいつオフまたはオンになるかを知るにはどうすればよいですか。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(ポータブルタブレットPC)で実行されています。ユーザーがアイドル時間の作業を停止すると、接続はすぐに閉じられ、コンピューターがアイドル状態から戻ったときに、ユーザーはすぐに再接続するようにしたいと思います。TomによるApplicationIdleonCodeプロジェクトのアイデアはすでに良いアイデアです。消費電力が少ないほど良いです。起動はできるだけ速くする必要があります。

4

4 に答える 4

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

}

編集: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がシステムに問い合わせて、利用できないモニターの電源ステータスを検出する方法を探していることに気づきましたが、コードはプログラムでそれを示しています。モニターのオン/オフ/スタンバイをオン/オフ/スタンバイにすると同時に、イベントをトリガーすることもできますがWndProc、フォームにフックして、モニターのステータスを示すメッセージを処理できるようにしたかったのです...今、これでポイント、これについて意見を述べたいと思います。

これが可能かどうか、またはWindowsが実際に「Hey!モニターがスリープ状態になります」または「Hey!モニターの電源が入っています」と私は言いますが、モニターは実際には、スリープ/オフ/オンになることを通知するソフトウェア信号をWindowsに送信しません。今、誰かがそれについての提案、ヒント、手がかりを持っているなら、あなたのコメントを投稿してください...

スクリーンセーバータブの一部としてのEnergyStarソフトウェアは、デスクトップを右クリックするとポップアップメニューが表示され、[プロパティ]を左クリックすると[表示]ダイアログボックスが表示され、さまざまなタブページが表示されます。 [スクリーンセーバー]を左クリックし、[画面の電源]グループボックスの一部として[電源]ボタンをクリックします。ダイアログボックスのその部分は、どういうわけかWindowsサブシステム(グラフィックカード?/ EnergyStarドライバー?)をトリガーしてハードウェアを送信しますモニター自体の省電力機能をオンにするように信号を送ります...(新品のモニターでは、デフォルトでこれが有効になっていないAFAIK ...この概念を無視してください...)

Energy-Powerソフトウェアドライバーの奥深くに埋め込まれ、埋め込まれているドキュメント化されていないAPIがない限り([電源]ボタンをクリックすると、その信号がモニターに送信され、電源モードが実際にアクティブ化される方法について、APIが実際にトリガーされます。結果!)そして、おそらく、前述のフォームアプリケーションのバックグラウンドでスレッドを実行し、ポーリングしてそのまだ不明な機能または電源ステータスをチェックするAPIを調べることによって、Microsoftだけが知っていることがあるはずです...結局のところ、Energy Starは、モニター自体で省電力モードをトリガーする方法をMicrosoftに示しました。確かに、それは一方通行ではありませんか?またはそれは?

これ以上助けられなかったらマヌーごめんなさい....:(

編集#2:私は編集の前半で書いたことを考え、答えを応援することを少し掘り下げて答えを思いついたと思いますが、最初に考えが頭に浮かびました。このドキュメントを参照してください- 'terranovum.com'からのpdfドキュメント、手がかり(または私が思った...)はレジストリにあり、ドキュメントの最後のページの最後の2つのレジストリキーを使用して、秒数に指定されたオフセットが含まれています。このCodeProjectの記事と併せて、アイドル時間を見つけるために、モニターがいつスタンバイになるか、単純に聞こえるか、マヌーもその概念を好まないかどうかを判断するのは簡単です。

googleでさらに調査すると、この結論に至ります。答えはVESA BIOS仕様DPMS(Display Power Management Signalling)の拡張にあります。これから生じる問題は、VESABIOSでそのシグナリングをどのように調べるかです。 、最新のグラフィックカードの多くにはVESA Biosが組み込まれているため、ピンの値を読み取ることができるハードウェアポートがどこかにある必要があります。このルートを使用するには、InpOut32を使用する必要があります。または、64ビットWindowsを使用している場合は、InpOut64 _pinvoke経由。基本的に、TurboCまたはTurboPascal(DOSの場合は両方とも16ビット)を使用してリコールできる場合は、ハードウェアポートを読み取るためのinport / outportなどと呼ばれるルーチン、またはpeek/pokeを使用するGWBASICがありました。ハードウェアポートのアドレスが見つかった場合は、水平同期と垂直同期をチェックすることで、モニターがスタンバイ/電源オフ/一時停止/オンになっているかどうかを判断するために値を調べることができます。これがより信頼性の高いソリューションだと思います。 ..

長い答えをお詫びしますが、自分の考えを書き留めなければならないと感じました。

マヌーにはまだ希望があります:);)

于 2010-02-05T16:42:04.093 に答える
4

欠けていたのは、イベントに登録しなかったことです。

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;
}
于 2013-05-19T09:01:50.980 に答える
2

これは、MainWindowが非表示であっても機能します。コードは上記の投稿とhttps://www.codeproject.com/Articles/1193099/Determining-the-Monitors-On-Off-sleep-StatusのC++コードに基づいています。

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);
}
于 2018-11-19T07:37:36.983 に答える
-3
/// <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;
    }
}
于 2012-12-24T13:55:48.870 に答える