当前位置: 首页 > news >正文

.NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态

在 Windows 系统中,一段时间不操作键盘和鼠标,屏幕便会关闭,系统会进入睡眠状态。但有些程序(比如游戏、视频和演示文稿)在运行过程中应该阻止屏幕关闭,否则屏幕总是关闭,会导致体验会非常糟糕。

本文介绍如何编写 .NET/C# 代码临时阻止屏幕关闭以及系统进入睡眠状态。


本文内容

    • Windows API
    • API 封装

Windows API

我们需要使用到一个 Windows API:

/// <summary>
/// Enables an application to inform the system that it is in use, thereby preventing the system from entering sleep or turning off the display while the application is running.
/// </summary>
[DllImport("kernel32")]
private static extern ExecutionState SetThreadExecutionState(ExecutionState esFlags);

使用到的枚举用 C# 类型定义是:

[Flags]
private enum ExecutionState : uint
{
    /// <summary>
    /// Forces the system to be in the working state by resetting the system idle timer.
    /// </summary>
    SystemRequired = 0x01,

    /// <summary>
    /// Forces the display to be on by resetting the display idle timer.
    /// </summary>
    DisplayRequired = 0x02,

    /// <summary>
    /// This value is not supported. If <see cref="UserPresent"/> is combined with other esFlags values, the call will fail and none of the specified states will be set.
    /// </summary>
    [Obsolete("This value is not supported.")]
    UserPresent = 0x04,

    /// <summary>
    /// Enables away mode. This value must be specified with <see cref="Continuous"/>.
    /// <para />
    /// Away mode should be used only by media-recording and media-distribution applications that must perform critical background processing on desktop computers while the computer appears to be sleeping.
    /// </summary>
    AwaymodeRequired = 0x40,

    /// <summary>
    /// Informs the system that the state being set should remain in effect until the next call that uses <see cref="Continuous"/> and one of the other state flags is cleared.
    /// </summary>
    Continuous = 0x80000000,
}

以上所有的注释均照抄自微软的官方 API 文档:

  • SetThreadExecutionState function (winbase.h) - Microsoft Docs

API 封装

如果你擅长阅读英文,那么以上的 API 函数、枚举和注释足够你完成你的任务了。

不过,我这里提供一些封装,以应对一些常用的场景。

using System;
using System.Runtime.InteropServices;

namespace Walterlv.Windows
{
    /// <summary>
    /// 包含控制屏幕关闭以及系统休眠相关的方法。
    /// </summary>
    public static class SystemSleep
    {
        /// <summary>
        /// 设置此线程此时开始一直将处于运行状态,此时计算机不应该进入睡眠状态。
        /// 此线程退出后,设置将失效。
        /// 如果需要恢复,请调用 <see cref="RestoreForCurrentThread"/> 方法。
        /// </summary>
        /// <param name="keepDisplayOn">
        /// 表示是否应该同时保持屏幕不关闭。
        /// 对于游戏、视频和演示相关的任务需要保持屏幕不关闭;而对于后台服务、下载和监控等任务则不需要。
        /// </param>
        public static void PreventForCurrentThread(bool keepDisplayOn = true)
        {
            SetThreadExecutionState(keepDisplayOn
                ? ExecutionState.Continuous | ExecutionState.SystemRequired | ExecutionState.DisplayRequired
                : ExecutionState.Continuous | ExecutionState.SystemRequired);
        }

        /// <summary>
        /// 恢复此线程的运行状态,操作系统现在可以正常进入睡眠状态和关闭屏幕。
        /// </summary>
        public static void RestoreForCurrentThread()
        {
            SetThreadExecutionState(ExecutionState.Continuous);
        }

        /// <summary>
        /// 重置系统睡眠或者关闭屏幕的计时器,这样系统睡眠或者屏幕能够继续持续工作设定的超时时间。
        /// </summary>
        /// <param name="keepDisplayOn">
        /// 表示是否应该同时保持屏幕不关闭。
        /// 对于游戏、视频和演示相关的任务需要保持屏幕不关闭;而对于后台服务、下载和监控等任务则不需要。
        /// </param>
        public static void ResetIdle(bool keepDisplayOn = true)
        {
            SetThreadExecutionState(keepDisplayOn
                ? ExecutionState.SystemRequired | ExecutionState.DisplayRequired
                : ExecutionState.SystemRequired);
        }
    }
}

如果你对这段封装中的 keepDisplayOn 参数,也就是 ExecutionState.DisplayRequired 枚举不了解,看看下图直接就懂了。一个指的是屏幕关闭,一个指的是系统进入睡眠。

电源和睡眠

此封装后,使用则相当简单:

// 阻止系统睡眠,阻止屏幕关闭。
SystemSleep.PreventForCurrentThread();

// 恢复此线程曾经阻止的系统休眠和屏幕关闭。
SystemSleep.RestoreForCurrentThread();

或者:

// 重置系统计时器,临时性阻止系统睡眠和屏幕关闭。
// 此效果类似于手动使用鼠标或键盘控制了一下电脑。
SystemSleep.ResetIdle();

在使用 PreventForCurrentThread 这个 API 的时候,你需要避免程序对空闲时机的控制不好,导致屏幕始终不关闭。

如果你发现无论你设置了多么短的睡眠时间和屏幕关闭时间,屏幕都不会关闭,那就是有某个程序阻止了屏幕关闭,你可以:

  • 查看有哪些程序会一直保持屏幕处于打开状态
  • 找到是谁持续唤醒了计算机屏幕

参考资料

  • SetThreadExecutionState function (winbase.h) - Microsoft Docs

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • 发现电脑屏幕总是不自动关闭?看看你是否打开了这些程序……
  • 临时编写和调试 C++ 代码?用 VSCode 就够了!一分钟搭好 C++ 调试环境
  • WPF 制作高性能的透明背景异形窗口(使用 WindowChrome 而不要使用 AllowsTransparency=True)
  • 在 WPF 中获取一个依赖对象的所有依赖项属性
  • 如何在 WPF 中获取所有已经显式赋过值的依赖项属性
  • .NET 设计一套高性能的弱事件机制
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地定义和使用弱事件
  • WPF 程序如何跨窗口/跨进程设置控件焦点
  • 使用 SetParent 制作父子窗口的时候,如何设置子窗口的窗口样式以避免抢走父窗口的焦点
  • WPF 程序如何移动焦点到其他控件
  • EFI 分区/恢复分区不可删除?你需要使用命令行了(配合鼠标操作)
  • EFI 分区/恢复分区不可删除?你需要使用命令行了(全命令行操作)
  • 使用傲梅分区助手无损合并分区,无损调整分区大小
  • .NET/C# 检测电脑上安装的 .NET Framework 的版本
  • Android交互
  • angular2开源库收集
  • CSS相对定位
  • Facebook AccountKit 接入的坑点
  • gcc介绍及安装
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • 初识MongoDB分片
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 算法之不定期更新(一)(2018-04-12)
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 微信开放平台全网发布【失败】的几点排查方法
  • 在Mac OS X上安装 Ruby运行环境
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​iOS实时查看App运行日志
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • #{} 和 ${}区别
  • #pragma once与条件编译
  • #微信小程序:微信小程序常见的配置传值
  • $(function(){})与(function($){....})(jQuery)的区别
  • (1)Android开发优化---------UI优化
  • (1)安装hadoop之虚拟机准备(配置IP与主机名)
  • (笔试题)分解质因式
  • (多级缓存)缓存同步
  • (二)WCF的Binding模型
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (机器学习-深度学习快速入门)第三章机器学习-第二节:机器学习模型之线性回归
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • (转)Linux整合apache和tomcat构建Web服务器
  • .NET CORE 3.1 集成JWT鉴权和授权2
  • .Net core 6.0 升8.0
  • .Net 代码性能 - (1)
  • .NET 设计模式—简单工厂(Simple Factory Pattern)
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • .NET多线程执行函数
  • @RequestMapping处理请求异常