2016-03-29 26 views
1

由於在Windows 8(0.1)計算機以下電源選項: Power Options打開顯示屏上,並殺死屏保

和屏幕配置爲: Screen Saver Settings

的目標是通過編程方式打開顯示並「終止」屏幕保護程序(以便在空閒時間後重新啓動)。 (注意,根據設置,可能只有屏幕保護程序處於打開狀態,或者在屏幕保護程序爲1分鐘後顯示屏完全關閉)。

我曾嘗試是:

SendMessage(HWND_Broadcast, WM_SysCommand, SC_MONITORPOWER, (LPARAM) - 1); 

結合

// From Microsoft's Knowledge Base article #140723: 
// http://support.microsoft.com/kb/140723 
// "How to force a screen saver to close once started 
// in Windows NT, Windows 2000, and Windows Server 2003" 
public static void KillScreenSaver() 
{ 
    IntPtr hDesktop = OpenDesktop("Screen-saver", 0, false, DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS); 
    if (hDesktop != IntPtr.Zero) 
    { 
     if (!EnumDesktopWindows(hDesktop, KillScreenSaverFunc, IntPtr.Zero) || !CloseDesktop(hDesktop)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 
     } 
    } 
    else 
    { 
     TerminateWindow(GetForegroundWindow()); 
    } 
} 

private static bool KillScreenSaverFunc(IntPtr hWnd, IntPtr lParam) 
{ 
    if (IsWindowVisible(hWnd)) 
    { 
     TerminateWindow(hWnd); 
    } 

    return true; 
} 

private static void TerminateWindow(IntPtr hWnd) 
{ 
    if (!PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero)) 
    { 
     throw new Win32Exception(Marshal.GetLastWin32Error()); 
    } 
} 

而且

public static void ActivateScreensaver() 
{ 
    SetScreenSaverActive(TRUE); 
} 

private static void SetScreenSaverActive(uint active) 
{ 
    IntPtr nullVar = IntPtr.Zero; 

    // Ignoring error since ERROR_OPERATION_IN_PROGRESS is expected. 
    // Methode is called to reset timer and to prevent possible errors as mentioned in Microsoft's Knowledge Base article #140723: 
    // http://support.microsoft.com/kb/140723 
    SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, active, ref nullVar, SPIF_SENDWININICHANGE); 
} 

哪工作,部分地。然而,顯示器再次立即關閉(事實上,大多數時候,人們甚至無法看到顯示器再次從電源引導狀態轉爲「穩定點亮」,而不是「閃爍熄滅=電源安全「 很短的時間)。

所以我想我錯過了像可靠地重置系統空閒計時器,以確保屏幕不會立即被關閉,圖片的關鍵部分再次。

編輯:根據我的調查SetThreadExecutionState(ES_DISPLAY_REQUIRED)似乎在重置空閒計時器的伎倆。但是,我仍然不知道正確的呼叫順序。我會當我弄明白自答案...

+0

你試過[模擬鼠標移動(http://stackoverflow.com/questions/12572441/sendmessage-sc-monitorpower-wont-turn-monitor-on-when - 運行窗口-8)? – stuartd

+0

@stuartd謝謝你的提示。我已經使用了它(儘管有點不同 - 在我的回答中使用了一個更新的,不推薦使用的API)。然而,它本身並不足以解決這兩種情況 – BatteryBackupUnit

+0

很好的答案。你能不能只是改變屏幕保護程序/顯示設置? – stuartd

回答

1

將下面的代碼:提到

  • 中斷運行屏幕保護程序
  • 轉關斷屏幕上(「關閉」在電源選項)
private static readonly ILog Log = LogManager.GetLogger(
    MethodBase.GetCurrentMethod().DeclaringType); 

public void TurnOnScreenAndInterruptScreensaver() 
{ 
    TryTurnOnScreenAndResetDisplayIdleTimer(); 

    TryInterruptScreensaver(); 
} 

/// <summary> 
/// Moves the mouse which turns on a turned-off screen and also resets the 
/// display idle timer, which is key, because otherwise the 
/// screen would be turned off again immediately. 
/// </summary> 
private static void TryTurnOnScreenAndResetDisplayIdleTimer() 
{ 
    var input = new SendInputNativeMethods.Input { 
     type = SendInputNativeMethods.SendInputEventType.InputMouse, }; 
    try 
    { 
     SendInputNativeMethods.SendInput(input); 
    } 
    catch (Win32Exception exception) 
    { 
     Log.Error("Could not send mouse move input to turn on display", exception); 
    } 
} 

private static void TryInterruptScreensaver() 
{ 
    try 
    { 
     if (ScreensaverNativeMethods.GetScreenSaverRunning()) 
     { 
      ScreensaverNativeMethods.KillScreenSaver(); 
     } 

     // activate screen saver again so that after idle-"timeout" it shows again 
     ScreensaverNativeMethods.ActivateScreensaver(); 
    } 
    catch (Win32Exception exception) 
    { 
     Log.Error("Screensaver could not be deactivated", exception); 
    } 
} 

SendInputNativeMethods:

public static class SendInputNativeMethods 
{ 
    public static void SendInput(params Input[] inputs) 
    { 
     if (SendInput((uint)inputs.Length, inputs, Marshal.SizeOf<Input>()) 
      != (uint)inputs.Length) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 
     } 
    } 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern uint SendInput(
     uint nInputs, 
     [MarshalAs(UnmanagedType.LPArray), In] Input[] pInputs, 
     int cbSize); 

    [StructLayout(LayoutKind.Sequential)] 
    public struct Input 
    { 
     public SendInputEventType type; 
     public MouseKeybdhardwareInputUnion mkhi; 
    } 

    [StructLayout(LayoutKind.Explicit)] 
    public struct MouseKeybdhardwareInputUnion 
    { 
     [FieldOffset(0)] 
     public MouseInputData mi; 

     [FieldOffset(0)] 
     public KEYBDINPUT ki; 

     [FieldOffset(0)] 
     public HARDWAREINPUT hi; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct KEYBDINPUT 
    { 
     public ushort wVk; 
     public ushort wScan; 
     public uint dwFlags; 
     public uint time; 
     public IntPtr dwExtraInfo; 
    } 
    [StructLayout(LayoutKind.Sequential)] 
    public struct HARDWAREINPUT 
    { 
     public int uMsg; 
     public short wParamL; 
     public short wParamH; 
    } 
    public struct MouseInputData 
    { 
     public int dx; 
     public int dy; 
     public uint mouseData; 
     public MouseEventFlags dwFlags; 
     public uint time; 
     public IntPtr dwExtraInfo; 
    } 
    [Flags] 
    public enum MouseEventFlags : uint 
    { 
     MOUSEEVENTF_MOVE = 0x0001, 
     MOUSEEVENTF_LEFTDOWN = 0x0002, 
     MOUSEEVENTF_LEFTUP = 0x0004, 
     MOUSEEVENTF_RIGHTDOWN = 0x0008, 
     MOUSEEVENTF_RIGHTUP = 0x0010, 
     MOUSEEVENTF_MIDDLEDOWN = 0x0020, 
     MOUSEEVENTF_MIDDLEUP = 0x0040, 
     MOUSEEVENTF_XDOWN = 0x0080, 
     MOUSEEVENTF_XUP = 0x0100, 
     MOUSEEVENTF_WHEEL = 0x0800, 
     MOUSEEVENTF_VIRTUALDESK = 0x4000, 
     MOUSEEVENTF_ABSOLUTE = 0x8000 
    } 
    public enum SendInputEventType : int 
    { 
     InputMouse, 
     InputKeyboard, 
     InputHardware 
    } 

ScreensaverNativeMethods:

internal static class ScreensaverNativeMethods 
{ 
    private const int SPI_GETSCREENSAVERRUNNING = 0x0072; 
    private const int SPI_SETSCREENSAVEACTIVE = 0x0011; 
    private const int SPIF_SENDWININICHANGE = 0x0002; 
    private const uint DESKTOP_WRITEOBJECTS = 0x0080; 
    private const uint DESKTOP_READOBJECTS = 0x0001; 
    private const int WM_CLOSE = 0x0010; 
    private const int TRUE = 1; 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool SystemParametersInfo(
     uint uiAction, 
     uint uiParam, 
     ref IntPtr pvParam, 
     uint fWinIni); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool PostMessage(
     IntPtr hWnd, 
     uint msg, 
     IntPtr wParam, 
     IntPtr lParam); 

    [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
    private static extern IntPtr OpenDesktop(
     string lpszDesktop, 
     uint dwFlags, 
     [In, MarshalAs(UnmanagedType.Bool)]bool fInherit, 
     uint dwDesiredAccess); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool CloseDesktop(IntPtr hDesktop); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool EnumDesktopWindows(
     IntPtr hDesktop, 
     EnumDesktopWindowsProc callback, 
     IntPtr lParam); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool IsWindowVisible(IntPtr hWnd); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern IntPtr GetForegroundWindow(); 

    private delegate bool EnumDesktopWindowsProc(IntPtr hDesktop, IntPtr lParam); 

    public static bool GetScreenSaverRunning() 
    { 
     IntPtr isRunning = IntPtr.Zero; 

     if (!SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref isRunning, 0)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 
     } 

     return isRunning != IntPtr.Zero; 
    } 

    public static void ActivateScreensaver() 
    { 
     SetScreenSaverActive(TRUE); 
    } 

    private static void SetScreenSaverActive(uint active) 
    { 
     IntPtr nullVar = IntPtr.Zero; 

     // Ignoring error since ERROR_OPERATION_IN_PROGRESS is expected. 
     // Methode is called to reset timer and to prevent possible errors 
     // as mentioned in Microsoft's Knowledge Base article #140723: 
     // http://support.microsoft.com/kb/140723 
     SystemParametersInfo(
      SPI_SETSCREENSAVEACTIVE, 
      active, 
      ref nullVar, 
      SPIF_SENDWININICHANGE); 
    } 

    // From Microsoft's Knowledge Base article #140723: 
    // http://support.microsoft.com/kb/140723 
    // "How to force a screen saver to close once started 
    // in Windows NT, Windows 2000, and Windows Server 2003" 
    public static void KillScreenSaver() 
    { 
     IntPtr hDesktop = OpenDesktop(
      "Screen-saver", 
      0, 
      false, 
      DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS); 
     if (hDesktop != IntPtr.Zero) 
     { 
      if (!EnumDesktopWindows(hDesktop, KillScreenSaverFunc, IntPtr.Zero) 
       || !CloseDesktop(hDesktop)) 
      { 
       throw new Win32Exception(Marshal.GetLastWin32Error()); 
      } 
     } 
     else 
     { 
      TerminateWindow(GetForegroundWindow()); 
     } 
    } 

    private static bool KillScreenSaverFunc(IntPtr hWnd, IntPtr lParam) 
    { 
     if (IsWindowVisible(hWnd)) 
     { 
      TerminateWindow(hWnd); 
     } 

     return true; 
    } 

    private static void TerminateWindow(IntPtr hWnd) 
    { 
     if (!PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 
     } 
    } 
}