如何阻止Windows系统服务在Modern Standby模式下运行?
解决Topshelf部署的服务在Modern Standby模式下运行导致文件损坏的问题
方案1:通过系统PowerCfg命令配置服务在Modern Standby时暂停
无需修改代码,直接让Windows在设备进入Modern Standby时暂停你的服务:
- 第一步:获取服务的GUID
打开管理员权限的命令提示符,执行:
复制输出中的GUID(格式类似sc queryex "你的服务名称" | findstr "GUID"{12345678-1234-1234-1234-1234567890AB})。 - 第二步:配置电源计划禁用该服务在Modern Standby期间运行
替换<服务GUID>为你复制的内容,执行以下命令:
这会分别设置电池、交流电模式下,服务在Modern Standby时停止运行。powercfg /setdcvalueindex SCHEME_CURRENT SUB_SERVICES <服务GUID> 0 powercfg /setacvalueindex SCHEME_CURRENT SUB_SERVICES <服务GUID> 0 powercfg /setactive SCHEME_CURRENT
方案2:代码层面监听系统电源事件,主动暂停服务
如果系统配置方案不生效,可在Topshelf服务代码中手动监听电源状态变化,在进入Standby时暂停文件写入等操作:
使用SystemEvents.PowerModeChanged事件
using Microsoft.Win32; using Topshelf; public class YourService : ServiceControl { private bool _inStandby = false; private System.Timers.Timer _workTimer; public bool Start(HostControl hostControl) { SystemEvents.PowerModeChanged += OnPowerModeChanged; // 初始化定时任务(示例为1分钟间隔) _workTimer = new System.Timers.Timer(60000); _workTimer.Elapsed += DoWork; _workTimer.Start(); return true; } public bool Stop(HostControl hostControl) { SystemEvents.PowerModeChanged -= OnPowerModeChanged; _workTimer.Stop(); _workTimer.Dispose(); CleanupResources(); return true; } private void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e) { if (e.Mode == PowerModes.Suspend) { _inStandby = true; PauseCriticalOperations(); } else if (e.Mode == PowerModes.Resume) { _inStandby = false; ResumeCriticalOperations(); } } private void DoWork(object sender, System.Timers.ElapsedEventArgs e) { if (_inStandby) return; PerformFileOperations(); } private void PauseCriticalOperations() { _workTimer.Stop(); CloseOpenResources(); } private void ResumeCriticalOperations() { InitializeResources(); _workTimer.Start(); } // 业务相关方法,根据实际需求实现 private void PerformFileOperations() { /* ... */ } private void CleanupResources() { /* ... */ } private void CloseOpenResources() { /* ... */ } private void InitializeResources() { /* ... */ } }
注意事项
SystemEvents.PowerModeChanged需要STA线程环境,若事件不触发,可在Topshelf配置中指定STA线程:
HostFactory.Run(x => { x.Service<YourService>(s => { s.ConstructUsing(name => new YourService()); s.WhenStarted(tc => tc.Start(null)); s.WhenStopped(tc => tc.Stop(null)); }); x.UseStaThread(); x.RunAsLocalSystem(); x.SetServiceName("YourServiceName"); });
方案3:通过WMI监听电源事件
如果SystemEvents方案不适用,可通过WMI监听底层电源管理事件:
using System.Management; using Topshelf; public class YourService : ServiceControl { private bool _inStandby = false; private ManagementEventWatcher _powerWatcher; private System.Timers.Timer _workTimer; public bool Start(HostControl hostControl) { var query = new WqlEventQuery("SELECT * FROM Win32_PowerManagementEvent"); _powerWatcher = new ManagementEventWatcher(query); _powerWatcher.EventArrived += OnPowerEventReceived; _powerWatcher.Start(); _workTimer = new System.Timers.Timer(60000); _workTimer.Elapsed += DoWork; _workTimer.Start(); return true; } public bool Stop(HostControl hostControl) { _powerWatcher.Stop(); _powerWatcher.Dispose(); _workTimer.Stop(); _workTimer.Dispose(); CleanupResources(); return true; } private void OnPowerEventReceived(object sender, EventArrivedEventArgs e) { var eventType = (uint)e.NewEvent["EventType"]; // EventType=4:进入Standby;EventType=7:从Standby恢复 if (eventType == 4) { _inStandby = true; PauseCriticalOperations(); } else if (eventType == 7) { _inStandby = false; ResumeCriticalOperations(); } } // 其余方法同方案2的DoWork、PauseCriticalOperations等 }
内容的提问来源于stack exchange,提问作者BorderKeeper
相关产品推荐
相关产品推荐

