6

.Net 4.0 でスクリーンセーバーを作成しました。基本的には、画像内のビットを移動し、タイマーで .Invalidate を使用して onPaint イベントをオーバーライドして表示するだけです。

これまでのところ、うまく機能していますが、1 つの問題に気付きました。

サスペンドタイムアウト後にモニターがサスペンドするのを止めています。インストールして以来、モニターは24時間年中無休で稼働しています。

問題は、省電力機能を具体的に停止するために何もしなかったことです-そして、コンピューターの省電力設定が設定されていることを確認しました(設定されています)。そこで、設定がまだ機能していることを確認するために、別のスクリーンセーバーを選択しました。タイムアウト後にモニターが中断されました。

では、電源管理を適切に行うにはどうすればよいでしょうか? Googleでこの回答を検索しましたが、見つかったのはすべて電源管理をブロックする方法であり、明示的にブロックしませんでした! 時間になったらサスペンドを許可したいだけです。

4

2 に答える 2

1

プログラムを「うまくプレイ」させることができました。なぜこれが機能し、元のコードが機能しなかったのかはわかりませんが、これは機能するだけでなく、実際には、画面が中断した後に計算を行わないことで CPU サイクルを削減するため、プログラムをより「省電力」に適したものにします。要するに、WndProc メッセージをプレビューし、モニターが中断されているメッセージを探し、それを受信したら、再開するまで再描画を停止します (再開してスクリーンセーバーを引き続きアクティブにすることは可能です)。

コードの変更:

    // Field Definitions
    /// <summary>
    /// Constants that relate to the WndProc messages we wish to intercept and evaluate.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:FieldNamesMustNotContainUnderscore", Justification = "Standard practice to use this naming style for Win32 API Constants.")]
    private const int WM_SYSCOMMAND = 0x0112, SC_MONITORPOWER = 0xF170;

    /// <summary>
    /// Gets or sets whether we are suspended. Should coincide with whether the display is turned on or not.
    /// </summary>
    private bool isSuspended = false;


    // New overridden method
    /// <summary>
    /// Intercepts WndProc messages. We are looking for the screen suspend activity. From it, we will return that we are able to suspend and we ourselves will suspend.
    /// </summary>
    /// <param name="m">Message to be checked.</param>
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_SYSCOMMAND)
        {
            // The 0x000F bits are used to indicate the specific state and must be ignored to see if this is a monitor power event.
            if ((m.WParam.ToInt32() & 0xFFF0) == SC_MONITORPOWER)
            {
                switch (m.WParam.ToInt32() & 0x000F)
                {
                    case -1:
                        // Display powering on - resume operation
#if DEBUG
                        System.Diagnostics.Debug.WriteLine("Display powered on.");
#endif
                        this.isSuspended = false;
                        break;
                    case 0:
                    case 1:
                    case 2:
                        // Display being powered off - suspend operation
#if DEBUG
                        System.Diagnostics.Debug.WriteLine("Display suspended");
#endif
                        this.isSuspended = true;
                        break;
                    default:
#if DEBUG
                        System.Diagnostics.Debug.WriteLine(string.Format("Unknown power state: {0}", (m.WParam.ToInt32() & 0x000F).ToString("0")));
#endif
                        // Assuming that unknown values mean to power off. This is a WAG.
                        this.isSuspended = true;
                        break;
                }
            }
        }

        base.WndProc(ref m);
    }


    // Change to my refreshing timer.
    /// <summary>
    /// Called when the refresh timer ticks. This invalidates the form, forcing it to be redrawn, which creates a framerate for us.
    /// </summary>
    /// <param name="sender">Who called this method.</param>
    /// <param name="e">Event Arguments.</param>
    private void RefreshTimer_Tick(object sender, EventArgs e)
    {
        if (this.isSuspended)
        {
            // Program is in suspended mode, so don't do anything this update.
            return;
        }

        // Program is not suspended, so invalidate the client area so it can be painted again.
        this.Invalidate();
    }

この変更を行うと、サスペンドが呼び出されたときにすべての再描画が停止し (および GDI+ 計算が停止します)、変更後、スクリーンセーバーは電源管理設定で「動作」します。

于 2012-06-06T17:21:51.707 に答える
1

偶然にも WM_SYSCOMMAND の 0xF170 (SC_MONITORPOWER) サブコマンドを誤ってトラップしていませか?

于 2012-06-06T00:38:29.813 に答える