C#中如何阻止硬件休眠

发布于:2025-07-15 ⋅ 阅读:(20) ⋅ 点赞:(0)

C#中如何阻止硬件休眠

在 C# 中阻止系统进入休眠状态(包括显示关闭和系统休眠)需要使用 Windows API。以下是完整的实现方案,包含多种控制级别和实际应用场景:

核心解决方案:使用 SetThreadExecutionState API

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public class SleepPreventer : IDisposable
{
    // 导入 Windows API
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern uint SetThreadExecutionState(uint esFlags);

    // 执行状态标志
    private const uint ES_CONTINUOUS = 0x80000000;
    private const uint ES_SYSTEM_REQUIRED = 0x00000001;
    private const uint ES_DISPLAY_REQUIRED = 0x00000002;
    private const uint ES_AWAYMODE_REQUIRED = 0x00000040;

    private uint _previousState;
    private bool _isDisposed;

    /// <summary>
    /// 初始化并阻止系统休眠
    /// </summary>
    /// <param name="preventDisplaySleep">是否阻止显示器关闭</param>
    /// <param name="preventSystemSleep">是否阻止系统休眠</param>
    public SleepPreventer(bool preventDisplaySleep = true, bool preventSystemSleep = true)
    {
        uint newState = ES_CONTINUOUS;

        if (preventSystemSleep)
        {
            newState |= ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED;
        }
        
        if (preventDisplaySleep)
        {
            newState |= ES_DISPLAY_REQUIRED;
        }

        // 设置新状态并保存之前的状态
        _previousState = SetThreadExecutionState(newState);
        
        if (_previousState == 0)
        {
            throw new Exception("设置执行状态失败: " + Marshal.GetLastWin32Error());
        }
    }

    /// <summary>
    /// 恢复原始状态(允许系统休眠)
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_isDisposed)
        {
            // 恢复之前的执行状态
            if (_previousState != 0)
            {
                SetThreadExecutionState(_previousState);
            }
            
            _isDisposed = true;
        }
    }

    ~SleepPreventer()
    {
        Dispose(false);
    }

    /// <summary>
    /// 临时重置休眠计时器(推荐用于长时间操作)
    /// </summary>
    public static void ResetSleepTimer(bool resetDisplay = true)
    {
        uint flags = ES_SYSTEM_REQUIRED;
        if (resetDisplay) flags |= ES_DISPLAY_REQUIRED;
        
        SetThreadExecutionState(flags);
    }
}

使用示例

场景 1:长时间操作期间阻止休眠(如文件传输)

// 开始长时间操作
using (var sleepLock = new SleepPreventer())
{
    // 执行耗时操作(如大文件传输)
    TransferLargeFile("source.zip", "destination.zip");
    
    // 在循环中定期重置计时器
    for (int i = 0; i < 100; i++)
    {
        DoWorkChunk(i);
        SleepPreventer.ResetSleepTimer(); // 每部分完成时重置计时器
    }
} // 离开 using 范围后自动允许休眠

场景 2:媒体播放期间保持唤醒

public class MediaPlayer : IDisposable
{
    private SleepPreventer _sleepPreventer;
    
    public void Play()
    {
        // 播放开始时阻止休眠
        _sleepPreventer = new SleepPreventer(preventDisplaySleep: true);
        
        // 开始播放...
    }
    
    public void Pause()
    {
        // 暂停时允许休眠
        _sleepPreventer?.Dispose();
        _sleepPreventer = null;
    }
    
    public void Dispose()
    {
        _sleepPreventer?.Dispose();
    }
}

场景 3:后台服务保持系统唤醒

public class BackgroundService
{
    private SleepPreventer _sleepPreventer;
    
    public void StartMonitoring()
    {
        // 阻止系统休眠但允许显示器关闭
        _sleepPreventer = new SleepPreventer(preventDisplaySleep: false, 
                                            preventSystemSleep: true);
        
        // 开始监控...
    }
    
    public void Stop()
    {
        _sleepPreventer?.Dispose();
    }
}

高级控制:使用 Windows 电源请求
对于更复杂的场景(需要系统完全保持唤醒状态),可以使用 PowerCreateRequest API:

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr PowerCreateRequest(ref POWER_REQUEST_CONTEXT context);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool PowerSetRequest(IntPtr powerRequest, POWER_REQUEST_TYPE requestType);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool PowerClearRequest(IntPtr powerRequest, POWER_REQUEST_TYPE requestType);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct POWER_REQUEST_CONTEXT
{
    public uint Version;
    public uint Flags;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string SimpleReasonString;
}

private enum POWER_REQUEST_TYPE
{
    PowerRequestDisplayRequired,
    PowerRequestSystemRequired,
    PowerRequestAwayModeRequired
}

public class PowerRequest : IDisposable
{
    private IntPtr _handle;
    private bool _isDisposed;

    public PowerRequest(string reason)
    {
        var context = new POWER_REQUEST_CONTEXT
        {
            Version = 0,
            Flags = 0,
            SimpleReasonString = reason
        };

        _handle = PowerCreateRequest(ref context);
        
        if (_handle == IntPtr.Zero)
            throw new Win32Exception(Marshal.GetLastWin32Error());
        
        if (!PowerSetRequest(_handle, POWER_REQUEST_TYPE.PowerRequestSystemRequired))
            throw new Win32Exception(Marshal.GetLastWin32Error());
    }

    public void Dispose()
    {
        if (!_isDisposed)
        {
            if (_handle != IntPtr.Zero)
            {
                PowerClearRequest(_handle, POWER_REQUEST_TYPE.PowerRequestSystemRequired);
                CloseHandle(_handle);
                _handle = IntPtr.Zero;
            }
            _isDisposed = true;
        }
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool CloseHandle(IntPtr hObject);
}

实际应用技巧

最小化影响:

// 仅在必要时阻止休眠
if (operationWillTakeMoreThan(TimeSpan.FromMinutes(10)))
{
    using (var preventer = new SleepPreventer())
    {
        ExecuteLongOperation();
    }
}

用户配置选项:

// 在设置中添加选项
if (Settings.PreventSleepDuringOperations)
{
    SleepPreventer.ResetSleepTimer();
}

处理系统电源事件:

Microsoft.Win32.SystemEvents.PowerModeChanged += (s, e) => 
{
    if (e.Mode == PowerModes.Suspend)
    {
        // 系统即将休眠,保存状态
        SaveCurrentState();
    }
};

多显示器场景:

// 检测是否有外接显示器
bool hasExternalDisplay = Screen.AllScreens.Length > 1;

// 仅在无外接显示器时阻止显示器关闭
using (var preventer = new SleepPreventer(
    preventDisplaySleep: !hasExternalDisplay))
{
    // 执行操作...
}

在这里插入图片描述
在这里插入图片描述
超时处理

// 设置最大阻止时间
using (var timeout = new System.Threading.Timer(_ => 
{
    preventer?.Dispose();
}, null, TimeSpan.FromHours(2), Timeout.InfiniteTimeSpan))
{
    using (var preventer = new SleepPreventer())
    {
        // 长时间操作...
    }
}

其他使用

public class SystemSleepAPI
{
    //定义API函数
    [DllImport("kernel32.dll")]
    static extern uint SetThreadExecutionState(ExecutionFlag flags);

    [Flags]
    enum ExecutionFlag : uint
    {
        System = 0x00000001,
        Display = 0x00000002,
        Continus = 0x80000000,
    }

    /// <summary>
    ///阻止系统休眠,直到线程结束恢复休眠策略
    /// </summary>
    /// <param name="includeDisplay">是否阻止关闭显示器</param>
    public static void PreventSleep(bool includeDisplay = false)
    {
        try
        {
            if (includeDisplay)
                SetThreadExecutionState(ExecutionFlag.System | ExecutionFlag.Display | ExecutionFlag.Continus);
            else
                SetThreadExecutionState(ExecutionFlag.System | ExecutionFlag.Continus);
        }
        catch { }
    }

    /// <summary>
    ///恢复系统休眠策略
    /// </summary>
    public static void ResotreSleep()
    {
        try { SetThreadExecutionState(ExecutionFlag.Continus); } catch { }
    }

    /// <summary>
    ///重置系统休眠计时器
    /// </summary>
    /// <param name="includeDisplay">是否阻止关闭显示器</param>
    public static void ResetSleepTimer(bool includeDisplay = false)
    {
        try
        {
            if (includeDisplay)
                SetThreadExecutionState(ExecutionFlag.System | ExecutionFlag.Display);
            else
                SetThreadExecutionState(ExecutionFlag.System);
        }
        catch { }
    }
}

使用实例

void time()
{
	PreventSleep(true);
}

网站公告

今日签到

点亮在社区的每一天
去签到