2016-03-29 14 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()); 
     } 
    } 
}