Windows 11のModern Standby(最新スタンバイ/S0 Low Power Idle)は、バッテリーを長持ちさせるために「スリープ中の動作」を強く制限する仕組みです。そのため、デスクトップアプリをスリープ中も止めずに動かし続けたい場合は、できること・できないことを切り分けたうえで、現実的な対策に寄せるのが近道です。
Modern Standby(最新スタンバイ)とは何か
Modern Standbyは、従来のS3スリープのように“完全に寝る”のではなく、S0(動作状態)のまま「低電力アイドル」に入る電源モデルです。見た目はスリープでも、スマホのスリープに近い発想で、瞬時にオン/オフできる体験や、状況に応じたネットワーク維持などを狙います。
ただし重要なのは、Modern Standbyは「スリープ中でも何でも動く」ではなく、動かして良いものだけをOSが選別し、その他は止めることで省電力を成立させている点です。ここを誤解すると、「スリープ中もデスクトップアプリを普通に走らせたい」という要求が通らない理由が見えてきません。
| 観点 | 従来のスリープ(S3) | Modern Standby(S0 Low Power Idle) |
|---|---|---|
| ユーザー体験 | 復帰に少し時間がかかる | 瞬時に復帰しやすい |
| スリープ中の基本方針 | ほぼ全て停止 | OSが許可した範囲で限定的に動作 |
| デスクトップアプリの扱い | スリープ中は停止 | 基本的に停止(後述のDAMにより抑制) |
| ネットワーク | 基本的に停止 | 設計・設定により維持される場合がある |
結論:デスクトップアプリをModern Standby中に動かし続ける「特別扱い」は用意されていない
先に結論です。一般的なデスクトップアプリを「特別扱い」してModern Standby中も通常どおり動かし続ける仕組みは、基本的に用意されていません。
Microsoftの説明では、Modern Standbyに入るとデスクトップアプリはDesktop Activity Monitor/Moderator(DAM)によって自動的に“停止(抑制)”されます。つまり、スリープ中にデスクトップアプリがCPUを回し続けるような動作は、設計上の前提に入っていません。
この設計は、単に意地悪で止めているのではなく、Modern Standbyの価値(省電力・発熱抑制・バッテリー持ち・予測可能な消費)を守るための中核です。特定アプリだけ例外を認めると、ユーザー体験が「バックパックの中で熱を持つ」「気づいたらバッテリーが空」になりやすく、OSとして統一的に成立しません。
DAM(Desktop Activity Monitor/Moderator)がやっていること
DAMは、Modern Standby(Connected Standbyを含む)においてデスクトップソフトウェアを抑制するためのWindowsコンポーネントです。主な狙いは、既存アプリの互換性を大きく壊さずに、スリープ時のバッテリー消費を抑えることです。
イメージとしては次のとおりです。
- ユーザーが操作を止めてスリープに入る
- OSはModern Standbyに移行する
- DAMがデスクトップアプリの実行を抑制(セッション種別に応じて停止/強い制限)
- 復帰後、アプリはスリープ前の続きとして実行を再開する(スリープ中は進まない)
Microsoft Learnの説明では、DAMはデスクトップアプリを停止させ、さらにサードパーティ製のシステムサービスをスロットリング(制限付き実行)する、とされています。
また、DAMは内部的にジョブオブジェクト等を利用して、対話セッションのプロセスは「停止」に寄せ、セッション0(サービスなど)は「強い制限」に寄せる、という設計が説明されています。
「登録して回避できないの?」が通らない理由
よくある発想として、
- OSに「このアプリは重要」と申告して例外扱いしてもらう
- ホワイトリスト登録してスリープ中も動ける権限を得る
- 特殊なカテゴリのアプリ(バックグラウンド許可)として扱う
といった“抜け道”を探したくなります。しかしModern Standbyは、そもそも「スリープ中はデスクトップアプリを動かさない」ことで一貫した省電力を作るモデルです。例外を作ると設計が崩れるため、一般的なデスクトップアプリ向けに“特別扱いの公式ルート”は期待しないほうが良いです。デスクトップアプリは停止し、動かしたい場合は別の設計に寄せるのが現実解になります。
現実的な選択肢は「スリープさせない」か「止まっても困らない設計にする」
Modern Standby前提で「重要処理を止めたくない」を実現するなら、方針は大きく2つです。
| 方針 | 向いているケース | 注意点 |
|---|---|---|
| 重要処理の間だけ、そもそもスリープに入らせない | コピー/バックアップ/エンコード/学習処理など、途中で止まると困る | バッテリー消費・発熱が増える。解除し忘れは致命的 |
| スリープで止まってもOK、復帰後に再開できる設計にする | 定期同期/キュー処理/集計など、分割可能な処理 | 状態保存、再実行耐性、ネットワーク不安定の吸収が必要 |
質問の意図が「スリープ中も止めずに処理を進めたい」であれば、まずは前者(重要処理中だけスリープ移行を抑止)が現実的です。ここで使われる代表的なAPIがSetThreadExecutionState()です。
方法:SetThreadExecutionState()で「重要処理中だけ」スリープ移行を抑止する
Windowsは、ユーザー入力や一部の活動から“動作中”を判断しますが、CPUやディスク処理のように自動検知されない活動もあります。そのため、アプリ側から「今は忙しいので寝ないでほしい」とOSへ伝える手段が用意されています。Microsoft Learnでは、アプリが忙しいことを通知するにはSetThreadExecutionStateを使い、スリープや画面オフを防ぐと説明されています。
要点はシンプルです。
- 処理を止めたくないタイミングで SetThreadExecutionState() を呼ぶ
- 処理が終わったら必ず解除する
- 常時ではなく、必要な間だけに限定する
SetThreadExecutionStateで使う主なフラグ
| フラグ | 意味 | 使いどころ |
|---|---|---|
| ES_SYSTEM_REQUIRED | システムのアイドルタイマーをリセットし、スリープ移行を抑止 | バックアップ、コピー、計算、ダウンロードなど |
| ES_DISPLAY_REQUIRED | ディスプレイのアイドルタイマーをリセットし、画面オフを抑止 | プレゼン、動画再生、監視画面など |
| ES_CONTINUOUS | 指定状態を次のES_CONTINUOUS付き呼び出しまで継続 | 一定時間の処理中、継続的に抑止したい場合 |
公式ドキュメントでは、ES_CONTINUOUSなしの呼び出しは「アイドルタイマーをリセットするだけ」で、継続させるには定期的に呼ぶ必要がある、とされています。実装を安定させたい場合は、ES_CONTINUOUSと組み合わせて“必要な間だけ継続”の形にするのが分かりやすいです。
注意:SetThreadExecutionStateは「スリープ中に動かす」魔法ではない
誤解しやすい点を明確にします。SetThreadExecutionStateは、Modern Standbyに入った後でデスクトップアプリを動かし続けるためのものではありません。そうではなく、重要処理の間はスリープに入らないようにするための仕組みです。つまり、狙いは「スリープ中に実行」ではなく「スリープに入る前に食い止める」です。
また、WindowsはSetThreadExecutionStateを呼んだスレッド数をカウントし、カウントがゼロになると条件次第でスリープに入る、という管理方式が説明されています。解除漏れがあると“いつまでも寝ないPC”になります。
C/C++の最小例
#include <windows.h>
void BeginCriticalWork()
{
// 重要処理中はスリープに入らないよう要求
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
}
void EndCriticalWork()
{
// 要求を解除(ES_CONTINUOUS単体でクリアするパターン)
SetThreadExecutionState(ES_CONTINUOUS);
}
int main()
{
BeginCriticalWork();
// ここでバックアップ、エンコード、長時間処理などを実行
// ...
EndCriticalWork();
return 0;
}
この例は分かりやすさ重視です。実運用では「例外・異常終了でも必ず解除する」構造にしてください(後述)。
C#(.NET)の実用例:解除漏れを防ぐラッパー
.NETアプリでは、解除漏れの事故を防ぐためにIDisposableで包むのが実務的です。処理ブロックを抜ければ必ず解除されるため、ユーザー体験を壊しにくくなります。
using System;
using System.Runtime.InteropServices;
public sealed class SleepInhibitor : IDisposable
{
[Flags]
private enum EXECUTION_STATE : uint
{
ES_SYSTEM_REQUIRED = 0x00000001,
ES_DISPLAY_REQUIRED = 0x00000002,
ES_CONTINUOUS = 0x80000000,
}
[DllImport("kernel32.dll")]
private static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
private bool _disposed;
// 画面は消えてよいが、スリープには入ってほしくないケース
public static SleepInhibitor KeepSystemAwake()
{
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED);
return new SleepInhibitor();
}
// 画面も消さずに維持したいケース(プレゼン等)
public static SleepInhibitor KeepSystemAndDisplayAwake()
{
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED);
return new SleepInhibitor();
}
public void Dispose()
{
if (_disposed) return;
_disposed = true;
// 解除
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);
GC.SuppressFinalize(this);
}
}
// 使い方例
// using var inhibitor = SleepInhibitor.KeepSystemAwake();
// 長時間処理...
「常時抑止」ではなく、止まると困る処理の間だけに絞ることが最重要です。Microsoft Learnでも、イベント処理系はES_SYSTEM_REQUIREDで処理中のみ要求して解除し、プレゼン等はES_DISPLAY_REQUIREDを使う、といった使い分けが説明されています。
運用上の落とし穴:ユーザーの操作・設定で“強制”される電源遷移
SetThreadExecutionStateは万能ではありません。次のようなケースでは、期待どおりにならないことがあります。
- ユーザーが明示的にスリープを指示した(電源メニュー、スリープボタン)
- 「フタを閉じたとき」の動作がスリープ/休止状態に設定されている
- 省電力ポリシーや管理者ポリシーで強い制御が入っている
- バッテリー残量が危険域に入り、保護動作として休止状態へ移行する
アプリだけで全てを支配しようとせず、ユーザーに分かるUI(処理中表示、残り時間、スリープ抑止のON/OFF)を用意し、期待値を合わせる設計が安全です。
より丁寧にやるなら:PowerSetRequest(パワー要求)も検討する
SetThreadExecutionStateは手軽ですが、アプリやサービスが「なぜスリープしないのか」を可視化したい、理由文字列を残したい、より管理しやすくしたい場合は、PowerCreateRequest / PowerSetRequest / PowerClearRequest(いわゆるPower Availability Request)も候補になります。
PowerSetRequestのドキュメントでは、要求を作るときに理由(REASON_CONTEXT)を用意し、必要な直前にセットし、終わったらすぐクリアし、プロセス終了時に片付ける、という運用が推奨されています。
また、Away Mode(見た目はスリープでも実行継続)はPowerRequestAwayModeRequiredとして定義されていますが、これは従来のS3スリープ向けであり、Modern Standby前提の回避策として期待するのは危険です。
まず確認:自分のPCはModern Standbyか
「そもそもModern Standby機なのか」を把握すると、原因切り分けが一気に楽になります。代表的な方法は powercfg /a です。
powercfg /a
Microsoft Learnでも、powercfg /a を使って利用可能なスリープ状態を列挙できると説明されています。
出力例として「Standby (S0 Low Power Idle)」が利用可能に出ていれば、Modern Standby前提で考える必要があります(機種によってはS3が無効化されていることもあります)。
デバッグと運用に効く:powercfgで「何が邪魔しているか」を見える化
スリープ抑止を実装すると、今度は「意図せず寝なくなった」「どのプロセスが抑止している?」が問題になりがちです。ここで役立つのがpowercfg系の診断です。
現在のスリープ抑止要因を見る:powercfg /requests
powercfg /requests を使うと、ディスプレイ・システム・実行状態などの要求(power request)が一覧できます。SetThreadExecutionStateやPowerSetRequestの影響確認にも便利です。
powercfg /requests
Modern Standby中の消費や挙動を追う:powercfg /sleepstudy
Modern Standby環境での診断としては、SleepStudyレポートが強力です。Microsoft Learnのpowercfgオプション説明では、/sleepstudyは直近数日間のModern Standby品質を診断し、HTMLレポートを出力できるとされています。
powercfg /sleepstudy /output "sleepstudy.html"
SleepStudyは「スリープ中に何がどれだけ消費していたか」を追えるため、アプリ側でスリープ抑止が必要か、必要ならどのタイミングだけに絞るべきかの判断材料になります。
目的別:やりたいことから逆算する現実解
「スリープ中も動かす」に固執すると詰まりやすいので、目的から逆算すると整理できます。
| やりたいこと | よくある誤解 | 現実的なアプローチ |
|---|---|---|
| 大容量コピー/バックアップを止めたくない | スリープしても裏で進むはず | 処理中だけSetThreadExecutionStateやPowerSetRequestでスリープ移行を抑止。完了後は必ず解除 |
| 長時間の計算(解析・学習)を回し続けたい | 画面を消せば省電力で計算だけ回る | 画面は消しても良いならES_SYSTEM_REQUIREDのみ。発熱・放熱条件に注意 |
| 定期同期・監視を途切れさせたくない | 数分ごとに動けばOK | “止まっても再開できる”設計へ。状態保存、再試行、復帰時の追いつき処理を実装 |
| スリープ中もネットワークで通知を受けたい | デスクトップアプリで常駐すれば受けられる | Modern Standbyではストアアプリのバックグラウンドタスク等、OS管理の枠に寄せる(デスクトップ常駐は前提が違う) |
Modern Standby前提で「嫌われない」実装にするコツ
スリープ抑止は便利ですが、使い方を誤るとユーザーから最も嫌われる類の不具合になります。実装で押さえたいポイントをまとめます。
抑止は“最小時間”に限定する
- 処理開始の直前に要求を立てる
- 処理完了・中断・失敗の全経路で解除する(try/finally、using、deferなど)
- 常駐アプリで「ずっと要求しっぱなし」にしない
ユーザーに明示する
- 「現在、重要処理中のためスリープしません」をUIで表示
- 任意でOFFにできるトグル(例:ノートPCのバッテリー時は抑止しない)
- 残り時間の見積もりや、完了通知(処理が終わったら自然に寝る)
バッテリー・発熱を前提に“安全側”へ
- バッテリー残量が低いときは抑止しない/処理を中断できるようにする
- フタを閉じる前提の処理(バックパックの中)では、発熱・放熱を必ず考慮する
- 企業PCやキッティング端末では、電源ポリシー(GPO/Intune)との整合を取る
よくある質問
デスクトップアプリをModern Standby中に動かすための例外登録はできる?
一般的なデスクトップアプリとしては難しいです。Modern Standby中はDAMによりデスクトップアプリの実行が抑制される前提で説明されており、「例外登録で動かし続ける」方向の仕組みは期待しないほうが安全です。
サービスにすれば動く?
Modern Standby中、サードパーティ製のシステムサービスは「制限付きで実行される」と説明されています。ただし、これをもって“常に期待どおり動く”とは言い切れません。デスクトップアプリをサービスに移し替えるだけで解決する、という発想は危険で、結局は「止まっても再開できる設計」や「必要な間だけスリープを抑止する設計」が必要になります。
スリープ中に動かせないなら、どう設計を変えるべき?
おすすめは次の3点です。
- 中断前提:処理を小さく分割し、進捗を永続化して復帰後に再開
- 失敗前提:ネットワーク断・タイムアウト・再試行を組み込み、再実行しても壊れない
- ユーザー主導:重要処理の実行中は「スリープしない」モードに切り替えるUIを用意
まとめ
Modern Standby(最新スタンバイ)では、デスクトップアプリをスリープ中も通常どおり動かし続けることは原則できません。これはDAMによってデスクトップアプリの実行が抑制される設計だからです。
現実的な解決策は、「スリープ中に動かす」ではなく、止まると困る処理の間だけスリープ移行を抑止することです。Windows APIのSetThreadExecutionStateを適切に使い、必要なときだけ要求し、終わったら確実に解除する――この方針に寄せるのが、Modern Standby時代の最短ルートになります。

コメント