スリープ復帰で壊れるアプリ ── 電源イベントの仕組みと復帰に強い業務アプリの作り方

· 更新日: · · Windows, 電源管理, Windows開発, 業務アプリ, 装置制御, 不具合調査, Win32 API

更新履歴(1件・最終更新 2026年09月05日)

この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。

技術的な主張と注意事項を保ち、電源通知・復帰後の症状・再接続・時間管理・スリープ抑止・調査手順を小見出しと比較表で読みやすく整理した。 更新前のバージョンを見る (DOI: 10.5281/zenodo.22170907)
初版公開
この記事を引用する(DOI: 10.5281/zenodo.22170906)

この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。

小村 豪(2026)「スリープ復帰で壊れるアプリ ── 電源イベントの仕組みと復帰に強い業務アプリの作り方」合同会社小村ソフト. https://doi.org/10.5281/zenodo.22170906 https://comcomponent.com/blog/windows-sleep-resume-power-events/

DOI(最新版)
10.5281/zenodo.22170906
DOI(この版)
10.5281/zenodo.22345464

ノートPCを閉じて翌朝開くと、業務アプリがエラーだらけになっている。装置の監視アプリが、昼休みの後だけデータを取りこぼす。Excelに出力する常駐ツールが、ときどき接続エラーで止まる。こうした症状で、まず疑いたいのがスリープをまたいだ動作です。

従来の業務アプリには、「PCは点けっぱなし」という前提で書かれたものがあります。しかし、ノートPCが業務の中心になったいま、放置すれば数分でスリープする環境を無視できません。さらにModern Standby(モダンスタンバイ)対応機では、従来とはスリープの仕組みも異なります。

この記事は、Windowsで業務アプリ・装置制御ソフトを作る開発者に向けたものです。OSから届く通知 → 復帰後に壊れるもの → 回復の設計 → 現場での調査の順に、一次情報にもとづいて整理します。

1. まず結論

設計の中心は、「スリープ前に必ず片付ける」ことではなく、「いつ止まっても復帰後に立て直せる」ことです。押さえる点は3つあります。

  • 事前通知は、処理を完了できる保証ではありません。スリープを拒否することはできず、PBT_APMSUSPEND の猶予はおよそ2秒です。緊急サスペンドでは通知自体が来ません。Modern Standbyでも、デスクトップアプリがスリープ中に動き続ける前提は置けません。123
  • 接続・ハンドル・時間の連続性は、復帰をまたいで保たれない前提で設計します。復帰通知だけでなく通信エラーからも同じ再接続処理へ進め、タイマーのスケジュールや経過時間の差分も見直します。
  • スリープ抑止と、復帰への備えは別の対策です。必要な処理区間では SetThreadExecutionState や電源要求を使い、終わったら必ず解除します。ただしユーザーの明示的なスリープ操作などは防げないため、回復処理を省く理由にはなりません。45

目的に合わせて、次の章から読むこともできます。

知りたいこと 読む章
スリープ前後にどの通知が届くか 2章: 電源イベントの流れ
Modern Standbyで何が違うか 3章: システムの動作とアプリの停止
接続エラーや時刻のずれがなぜ起きるか 4章: 定番の症状
再接続・時間管理・スリープ抑止をどう実装するか 5章: 復帰に強い設計
問い合わせをどう切り分けるか 6章: powercfg とイベントログ

2. スリープ前後に何が起きるか ── 電源イベントの流れ

OSは電源状態の変化を WM_POWERBROADCAST メッセージでアプリに通知します。2 まず、サスペンド遷移の前後で使う3つのイベントを押さえます。Modern Standbyの低電力アイドルとの違いは、3章で補足します。

イベント 意味
PBT_APMSUSPEND まもなくスリープに入る(最後の準備の機会)
PBT_APMRESUMEAUTOMATIC 復帰した(復帰時に必ず届く)
PBT_APMRESUMESUSPEND ユーザー操作による復帰(こちらは条件付き)
スリープと復帰の通知の流れスリープ直前にPBT_APMSUSPENDが約2秒の猶予付きで届き、復帰時はPBT_APMRESUMEAUTOMATICが必ず届いて、ユーザー操作による復帰の場合だけ続けてPBT_APMRESUMESUSPENDが届くアプリOSアプリOSスリープ(コードは動かない)PBT_APMSUSPEND(猶予約2秒)状態保存・接続クローズPBT_APMRESUMEAUTOMATIC(復帰時に届く)再接続・状態の立て直しPBT_APMRESUMESUSPEND(ユーザー復帰時のみ)画面更新などユーザー向け処理

図1: 通知は「直前に一言、復帰後に一言か二言」だけ。立て直しの主役は復帰側の処理になる。

スリープ前の通知は「間に合えば準備する」機会

PBT_APMSUSPEND は、スリープに入る直前の通知です。ファイルを閉じる、状態を保存するといった準備ができますが、次の2つの制約があります。

制約 設計への影響
処理の猶予はアプリごとにおよそ2秒 時間を超えると、システムはアプリを待たずに進む1
緊急サスペンドでは事前通知がない バッテリー残量が危機的な場合などは、準備なしで止まる2

したがって、「この通知を受けてから必ず保存し終える」という設計は成立しません。事前通知では間に合う範囲で準備し、回復の本体は復帰側に置きます。

通常スリープと緊急サスペンドの違い通常のスリープでは直前にPBT_APMSUSPENDが届き約2秒の準備時間があるが、クリティカルバッテリーなどによる緊急サスペンドでは事前通知なしで停止するため、事前通知に依存した設計は成立しない通常のスリープPBT_APMSUSPEND(約2秒の猶予)準備してから停止緊急サスペンド(電池切れ間際)事前通知なしで停止「通知が来る前提」の設計は不成立

図2: 緊急サスペンドは予告なし。だから準備は「できたら儲けもの」で、本体は復帰側に置く。

復帰通知は、機械的な回復とユーザー向け処理を分ける

サスペンドから復帰すると、まず PBT_APMRESUMEAUTOMATIC が届きます。さらに、電源ボタンやキー入力で復帰した場合、または復帰後にユーザーの在席が検知された場合には、PBT_APMRESUMESUSPEND が続きます。67

一方、ネットワーク経由の遠隔起動やメンテナンスのための無人復帰では、PBT_APMRESUMEAUTOMATIC しか届きません。接続の張り直しなど必須の回復処理は前者で、画面更新や再ログイン要求などユーザー向けの動作は後者で行います。6

復帰2段階の処理の使い分け復帰時に届くPBT_APMRESUMEAUTOMATICには再接続など機械的な立て直しを置き、ユーザー操作時だけ届くPBT_APMRESUMESUSPENDには画面更新や再ログイン要求などユーザー向けの処理を置くPBT_APMRESUMEAUTOMATIC(復帰時)機械的な立て直しPBT_APMRESUMESUSPEND(ユーザー復帰時)ユーザー向けの処理再接続・ハンドル開き直し画面更新・再ログイン要求

図3: 無人復帰では後者が来ないため、必須の立て直しを後者に置くと取りこぼす。

ウィンドウがないアプリでも通知を受け取れる

ウィンドウを持たないサービスやコンソールアプリでは、RegisterSuspendResumeNotification を DEVICE_NOTIFY_CALLBACK 指定で使い、コールバックで同じ通知を受け取れます。8

また、WM_POWERBROADCAST では、低電力状態がスリープなのか休止なのかを区別できません。7 アプリ側は、「止まって、戻ってきた」という共通の事象として回復処理を設計します。

3. Modern Standby ── 「スリープ」の意味が変わった

システムが動くことと、アプリが動けることは別

従来のS3スリープは、システム全体を止めるモデルです。これに対してModern Standbyは、画面を消した後もシステムが間欠的に動く、スマートフォンに近いモデルです。

ただし、通常のデスクトップアプリまで動き続けるわけではありません。スリープ入りの最初の段階で、Desktop Activity Moderator(DAM)により一時停止されます。3

方式 システムの動作 デスクトップアプリの前提
従来のS3スリープ システム全体が停止する スリープ中にコードは動かない
Modern Standby ネットワーク維持や通知受信などのために間欠的に動く DAMにより一時停止され、通常のコードは動かない

間欠的な動作の恩恵を受けるのは、この仕組みに対応したコンポーネントです。業務アプリの設計上は、どちらも「スリープ中に自分のコードは動かない」という結論になります。3

従来のスリープとModern Standbyの違い従来のS3スリープはシステム全体が停止するが、Modern Standbyでは画面消灯後もシステムが間欠的に動く。ただしデスクトップアプリはDAMにより一時停止されるため、どちらでもアプリのコードは動かない従来のS3スリープ:全体が停止アプリのコードは動かないModern Standby:システムは間欠動作デスクトップアプリはDAMで一時停止

図4: モデルは変わっても、デスクトップアプリにとっての結論は「スリープ中は動けない」で共通。

復帰通知だけを回復の条件にしない

Modern Standbyの低電力アイドルの出入りは、従来のサスペンド遷移と一致しない場合があります。通知が届かないまま、接続が壊れていることもあります。復帰通知は回復を早める補助と考え、通信エラーの検知から再接続できる経路を中心に置いてください。具体的な構造は5章で説明します。

また、低電力状態への移行が段階的なので、切断や停止のタイミングはS3ほど明確ではありません。ユーザーにも「画面が消えただけ」なのか「スリープした」のか区別しにくいため、症状を聞くときはフタを閉じたか、何分放置したかを確認します。

4. 何が壊れるのか ── 定番の症状

復帰後のエラーは、接続・デバイスハンドル・時間の連続性に分けると整理できます。共有リソースでは、再認証やネットワークの再確立にかかる時間も確認します。

TCP接続は、送受信するまで切断に気づけない

スリープ中、接続相手やNAT・ファイアウォールは、こちらの沈黙をタイムアウトとして扱い、接続を破棄します。しかし、こちらのソケットはそれを知らないままなので、復帰後に送受信して初めて失敗することになります。

受信待ちのまま、いつまでもエラーにならない場合もあります。これが、キープアライブによる生死確認を必要とする理由です。データベース接続やWebSocketも、同じ構図で考えられます。

シリアルポートやUSB機器は、ハンドルを開き直す

USB機器は、復帰時に一度抜かれて挿し直されたように見える場合があり、開いていたハンドルがエラーを返すようになります。装置制御アプリで「昼休みの後だけ通信エラー」になる典型的なパターンです。

ハンドルを使い続ける前提ではなく、デバイスを開き直せる構造にします。再接続の設計は、シリアル通信の記事でも扱っています。

周期処理・経過時間・定時処理を分けて見直す

時間に関する問題は、次の3種類に分かれます。

処理 スリープをまたぐと起きること 対処
「10秒ごとにポーリング」する周期処理 スリープ中は止まる。復帰後の発火はAPIや実行環境によって異なる 復帰時にスケジュールを組み直す
前回時刻との差分を使う計算 差分が突然「8時間ぶん」になり、平均値やタイムアウト判定が壊れる 異常に大きな差分をガードする
「毎晩2時に実行」する定時処理 その時刻にPCが眠っていれば実行されない 必要ならタスクスケジューラのスリープ解除機能を使う

特に周期処理は、期限切れ分が復帰直後に1回発火する場合もあれば、次の周期まで何も起きない場合もあります。実行できなかった分をどう扱うかを、タイマーの暗黙の挙動に任せないことが重要です。

時間の連続性が壊れる3つの形周期処理はスリープ中に止まり復帰後の発火はAPIごとに異なるため復帰時にスケジュールを組み直し、前回時刻との差分は復帰後に巨大な値になるためガードし、定時処理は眠っていると実行されないためタスクスケジューラのスリープ解除を検討する周期処理:スリープ中は止まる復帰時にスケジュールを組み直す経過時間の差分:巨大化異常な差分をガードする定時処理:眠っていて未実行スリープ解除の設定で起こす

図5: タイマーと時刻の処理は「時間が飛ぶ」前提で書く。3つの形それぞれに対処の型がある。

スリープをまたいで壊れる3つのものスリープをまたぐと、TCP接続は相手側のタイムアウトで破棄され、USB機器のハンドルは再接続扱いで無効になり、経過時間ベースの処理は巨大な時間ジャンプを観測する。それぞれ再接続・開き直し・差分ガードで立て直すスリープ区間TCP接続:相手側で破棄済みUSB機器:ハンドルが無効化経過時間:巨大なジャンプエラー検知と再接続デバイスを開き直す異常な差分をガード

図6: 壊れるものは「接続」「ハンドル」「時間の連続性」の3系統で、それぞれ立て直しの型が決まっている。

ネットワークドライブやVPNは、復帰直後にも待ち時間がある

ネットワークドライブやVPNは、復帰後に再認証・再確立が必要になることがあります。そのため、復帰直後の数秒〜数十秒はアクセスが失敗する時間帯があります。

復帰した瞬間に一斉にリトライするのではなく、少し待ち、段階的に再試行する設計にします。

5. 復帰に強いアプリの作り方

原則は、接続やハンドルがスリープをまたいで生き残らなくても、いつでも立て直せる構造にすることです。再接続、時間の扱い、必要な区間のスリープ抑止を、それぞれ設計します。

復帰通知と通信エラーを、同じ再接続処理に合流させる

トップレベルウィンドウの WM_POWERBROADCAST で PBT_APMRESUMEAUTOMATIC を受けたら、保持している接続を破棄して張り直します。ただし、復帰通知だけに頼ってはいけません。通知の取りこぼしや、通知が届く前の通信もあるためです。

「通信エラーを検知したら再接続する」経路を必ず併設し、復帰通知はその処理を早めるきっかけと位置づけます。次のC#の例は、復帰通知から再接続を要求する部分です。通信エラー側からも、同じ再接続処理へ合流させます。

// C#: 復帰通知と通信エラーの両方から同じ再接続処理に合流させる
protected override void WndProc(ref Message m)
{
    const int WM_POWERBROADCAST = 0x0218;
    const int PBT_APMRESUMEAUTOMATIC = 0x0012;
    if (m.Msg == WM_POWERBROADCAST && (int)m.WParam == PBT_APMRESUMEAUTOMATIC)
    {
        _connectionManager.RequestReconnect();   // 冪等な再接続要求
    }
    base.WndProc(ref m);
}

再接続は「冪等・バックオフ・キープアライブ」を組み合わせる

再接続処理では、次の3点をそろえます。

要素 役割
冪等な再接続 何度要求されても安全に立て直せるようにする
指数バックオフ付きの再試行 失敗したら再試行までの間隔を延ばす
定常時のキープアライブ 接続が生きているかを確認し、切断を早期に検知する

この3点セットは、スリープ復帰だけでなく、ネットワークの瞬断や機器の再起動にもそのまま役立ちます。

復帰に強い再接続設計復帰通知と通信エラーとキープアライブ失敗のどれもが同じ冪等な再接続処理に合流し、失敗時は指数バックオフで再試行するはいいいえ復帰通知(PBT_APMRESUMEAUTOMATIC)冪等な再接続処理通信エラー検知キープアライブ失敗成功?通常運転へ指数バックオフ後に再試行

図7: 再接続を1本の冪等な処理に集約し、復帰通知・エラー検知・キープアライブのどこからでも同じ道に入る。

時間が飛んだ区間を、そのまま計算に混ぜない

「前回からの経過時間」を使う処理では、異常に大きな差分を検出したら、その区間を無効化するガードを入れます。平均に混ぜない、通常のタイムアウトとして扱わないためです。

復帰をまたぐ時間の計測では、スリープ中も進む時刻(実時間)と、処理に使った時間を区別します。周期処理のスケジュールの組み直しや、定時処理が実行されなかった場合の扱いも、4章の区分で見直してください。

中断できない処理区間は、明示的にスリープを抑止する

データ移行や装置との連続通信など、スリープされては困る処理の間は、SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED) を使います。画面も維持したい場合は ES_DISPLAY_REQUIRED を追加します。74

もうひとつの手段が、PowerCreateRequest と PowerSetRequest による電源要求です。理由の文字列を添えられるので、powercfg /requests で「誰が、なぜスリープを妨げているか」が分かります。運用時に理由を確認できる点で、こちらのほうが親切です。5

手段 管理する単位と注意点
SetThreadExecutionState スレッド単位。解除は設定したときと同じスレッドから行う
電源要求(PowerCreateRequest + PowerSetRequest) ハンドルで管理する。async/awaitなどでスレッドが替わる処理ではこちらを使う

ただし、抑止を設定すれば、どんな中断も防げるわけではありません。次の制約を、回復処理とは別に確認します。

制約 必要な対応
抑止するのは無操作による自動スリープ フタを閉じる、スタートメニューからスリープを選ぶなどの明示的な操作に備え、再接続処理を残す
Modern Standby機のバッテリー駆動では、スリープタイムアウト後しばらくすると電源要求も打ち切られる 中断できない処理はAC電源や運用側で担保する5
解除漏れは、PCがスリープしない原因になる 処理が終わったら必ず解除する
スリープ抑止の2つの手段手軽に使えるSetThreadExecutionStateと、理由の文字列を添えられて管理者からpowercfgで見える電源要求APIのどちらを使う場合でも、処理の終了時に必ず解除するスリープされたくない処理区間SetThreadExecutionState電源要求(PowerSetRequest)手軽・フラグ指定のみ理由付き・powercfgで可視処理終了時に必ず解除

図8: どちらの手段でも「終わったら解除」が絶対条件。理由を可視化できる電源要求のほうが運用には親切。

常時稼働が要件なら、配置先と運用を見直す

サービスやウィンドウレスアプリでも、RegisterSuspendResumeNotification の DEVICE_NOTIFY_CALLBACK で通知を受け取れます。8

ただし、常時稼働が本当に必要なら、スリープするクライアントPCへの常駐そのものを見直します。サーバー側か、スリープしない運用の端末に処理を寄せるのが根本的な対策です。

6. 調べ方 ── powercfgとイベントログ

問い合わせでは、まず「エラーの直前にPCがスリープしていたか」を確認します。フタを閉じたか、何分放置したかを聞いたうえで、症状に合った道具を使います。

調べたいこと 道具 確認する内容
スリープしない原因 powercfg /requests 電源要求を出しているプロセス・ドライバー。SetThreadExecutionState の解除忘れも確認する
勝手に起きる原因 powercfg /lastwake、powercfg /waketimers 直前の復帰要因と、復帰予約中のタイマー
Modern Standbyの品質 powercfg /sleepstudy スリープ区間ごとの消費電力とアクティビティ9
スリープ・復帰の時系列 システムイベントログの Kernel-Power スリープ入りと復帰の記録

イベントログをアプリのログと突き合わせれば、「エラーの直前に復帰があったか」を客観的に確かめられます。スリープを疑うだけで終わらず、発生時刻をそろえて切り分けます。

電源トラブルの症状と調査コマンドの対応スリープしない症状はpowercfg /requestsで電源要求の主を調べ、勝手に起きる症状は/lastwakeと/waketimersで復帰要因を調べ、時系列の確認はイベントログのKernel-Powerで行うスリープしないpowercfg /requests勝手に起きるpowercfg /lastwake・/waketimers時系列を確認したいイベントログのKernel-Power解除し忘れたスリープ抑止も判明

図9: 症状と調査コマンドの対応は3系統。まず「直前にスリープしたか」を確かめてから使い分ける。

7. まとめ

スリープ対策は、通知を受け取るだけでは完成しません。事前準備が間に合わないことも、復帰通知が届かないことも織り込んで、次のように役割を分けます。

設計・調査の対象 押さえる点
スリープ前 拒否はできない。PBT_APMSUSPEND の約2秒の猶予で準備するが、緊急時には通知が来ない
復帰通知 PBT_APMRESUMEAUTOMATIC で必須の回復、PBT_APMRESUMESUSPEND でユーザー向け処理。通知だけには頼らない
接続・ハンドル 通信エラーからの再接続を中心に、冪等性・指数バックオフ・キープアライブを組み合わせる
時間 異常な経過時間の差分をガードし、周期処理を組み直す。定時処理は眠っていれば走らない
スリープ抑止 必要な区間だけ設定し、終わったら解除する。明示的なスリープ操作などへの回復の備えは残す
原因調査 直前のスリープ有無を聞き、powercfg と Kernel-Power の記録をアプリのログと照合する

スリープは、アプリから見れば「予告なしに時間が飛び、周辺との接続が切れて戻ってくる」イベントです。これを異常事態ではなく日常の一部として設計に織り込めているかどうかが、ノートPC時代の業務アプリの安定性を分けます。

関連記事

関連する相談領域

合同会社小村ソフトでは、「スリープ復帰後に通信が壊れる」「装置との接続が昼休み後に切れる」といった不具合の原因調査、既存アプリへの再接続ロジック・電源イベント対応の後付け実装、ノートPC運用を前提とした業務アプリ・装置制御ソフトの設計レビューを扱っています。

参考リンク

  1. Microsoft Learn, PBT_APMSUSPEND event. コンピューターがサスペンド状態に入る直前に届くイベントであること、アプリはデータ保存に必要な処理を完了させるべきこと、システムがこの通知の処理に許すのはおよそ2秒であり、それを超えて処理を続けるアプリは中断されうることについて。 ↩ ↩2

  2. Microsoft Learn, System Power Management Events. システムがスリープ等の動作モード変化を事前にブロードキャストすること、アイドルによるスリープ前にPBT_APMSUSPENDが通知されファイルクローズやデータ保存の準備ができること、緊急サスペンド(クリティカルバッテリーなど)では事前通知が行われないこと、このメッセージの処理にはアプリごとに最大2秒が許されタイムアウト後は打ち切られること、復帰時には全アプリに通知されることについて。 ↩ ↩2 ↩3

  3. Microsoft Learn, Prepare software for modern standby. Modern Standbyへの移行の最初の段階でDesktop Activity Moderator(DAM)がデスクトップアプリを一時停止すること、その後システムが低電力フェーズ・レジリエンシーフェーズへ段階的に移行し、許可されたコンポーネントだけが間欠的に動作することについて。 ↩ ↩2 ↩3

  4. Microsoft Learn, SetThreadExecutionState function (winbase.h). ES_SYSTEM_REQUIREDやES_DISPLAY_REQUIREDによりシステムのアイドルスリープや画面消灯を抑止できること、ES_CONTINUOUSで継続的な抑止を宣言し、用が済んだらES_CONTINUOUS単独で呼んで解除する使い方について。 ↩ ↩2

  5. Microsoft Learn, PowerSetRequest function (winbase.h). PowerCreateRequestで作成した電源要求オブジェクトに対しシステム維持・画面維持などの要求種別を設定できること、診断用の理由文字列を添えられ、未解決の電源要求はpowercfg /requestsで列挙できることについて。 ↩ ↩2 ↩3

  6. Microsoft Learn, PBT_APMRESUMESUSPEND event. ユーザー操作による復帰やその後のユーザー入力検知の際にPBT_APMRESUMEAUTOMATICに続いて送られること、リモートウェイクなど外部要因の復帰ではPBT_APMRESUMEAUTOMATICのみが送られること、アプリはスリープ時に閉じたファイルを開き直しユーザー入力に備えるべきことについて。 ↩ ↩2

  7. Microsoft Learn, WM_POWERBROADCAST message. 復帰時に必ずPBT_APMRESUMEAUTOMATICが送られ、ユーザー入力による復帰ではさらにPBT_APMRESUMESUSPENDが送られること、このメッセージでは低電力状態の種類は区別できないこと、電源状態遷移の詳細はシステムイベントログに記録されること、システムの低電力状態への移行を防ぐにはSetThreadExecutionStateを呼ぶことについて。 ↩ ↩2 ↩3

  8. Microsoft Learn, RegisterSuspendResumeNotification function (winuser.h). サスペンド・レジューム通知の受信を登録するAPIで、ウィンドウハンドル宛のメッセージ配送に加え、DEVICE_NOTIFY_CALLBACKを指定することでウィンドウを持たないアプリやサービスがコールバックで通知を受け取れることについて。 ↩ ↩2

  9. Microsoft Learn, Modern standby SleepStudy. powercfg /sleepstudyで生成されるレポートにより、Modern Standby区間ごとの消費電力・アクティビティ・復帰要因(電源ボタン、ユーザー入力、ウェイクタイマーなど)を確認できることについて。 ↩

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

アプリはスリープに入ることを事前に知って拒否できますか?
現在のWindowsでは、通知は受け取れますが拒否はできません。スリープ直前にはWM_POWERBROADCASTメッセージでPBT_APMSUSPENDイベントが届き、ここでファイルを閉じる・状態を保存するなどの準備ができますが、処理に許される時間はアプリごとにおよそ2秒で、超えるとシステムはアプリを待たずに進みます。またバッテリー切れ間際などの緊急サスペンドでは事前通知そのものが来ません。したがって「スリープ前に必ず完了させる」設計は成立せず、「いつ切られても復帰時に立て直せる」設計にする必要があります。どうしてもスリープさせたくない処理区間は、SetThreadExecutionStateや電源要求(PowerSetRequest)で明示的に抑止します。
復帰したことはどうやって検知すればよいですか?
ウィンドウを持つアプリならWM_POWERBROADCASTを処理します。サスペンドからの復帰時にはPBT_APMRESUMEAUTOMATICが届き、ユーザーの操作(電源ボタンやキー入力)による復帰の場合はその後にPBT_APMRESUMESUSPENDも届きます。無人で復帰してすぐ再スリープする場合はPBT_APMRESUMEAUTOMATICしか来ないため、再接続などの必須処理はPBT_APMRESUMEAUTOMATIC側に置き、画面更新などユーザー向けの処理をPBT_APMRESUMESUSPEND側に置く使い分けが基本です。ウィンドウを持たないサービスやコンソールアプリは、RegisterSuspendResumeNotificationをDEVICE_NOTIFY_CALLBACK指定で使えばコールバックで同じ通知を受け取れます。
スリープ中もアプリを動かし続けることはできますか?
原則としてできません。スリープ中はCPUの実行自体が止まり(Modern Standby機ではデスクトップアプリはDesktop Activity Moderatorにより一時停止され)、アプリのコードは走りません。選択肢は2つです。ひとつは、処理中だけスリープを抑止すること。SetThreadExecutionStateにES_SYSTEM_REQUIREDを指定するか、PowerCreateRequest/PowerSetRequestで電源要求を出せば、無操作による自動スリープをその間抑止できます(powercfg /requestsで確認できます)。ただしユーザーがフタを閉じるなどの明示的なスリープ操作までは止められないため、抑止中でも復帰への備えは必要です。もうひとつは、スリープを受け入れて「復帰後に追いつく」設計にすることです。夜間バッチのような定時処理は、タスクスケジューラの「タスクの実行時にスリープを解除する」でPCを起こす方法もあります。常時稼働が本当に必要な処理は、スリープしない設定のサーバーやサービスに寄せるのが正道です。
復帰後にTCP接続やシリアルポートが使えなくなるのはなぜですか?
スリープ中はネットワークアダプターやUSBデバイスも省電力状態に落ちるためです。TCP接続は相手側やNAT・ファイアウォールのタイムアウトで破棄されており、復帰後の送受信はエラーになります(エラーになるまで気づけないことも多い)。USBシリアル変換器などは復帰時にデバイスの取り外し・再接続として扱われることがあり、開いていたハンドルは無効になります。どちらも「ハンドルや接続は復帰をまたいで生き残らない」前提で、復帰通知や通信エラーを契機に接続を張り直す再接続ロジックを実装するのが正解です。定期的なキープアライブと、失敗時の指数バックオフ付き再試行を組み合わせるのが定石です。
勝手にスリープする・勝手に復帰する原因はどう調べますか?
powercfgコマンドが第一の道具です。「スリープしない」方向ではpowercfg /requestsで、どのプロセス・ドライバーが電源要求を出してスリープを妨げているかが一覧できます。「勝手に起きる」方向ではpowercfg /lastwakeで直前の復帰要因が、powercfg /waketimersで復帰予約中のタイマーが確認できます。Modern Standby機ではpowercfg /sleepstudyでスリープ中の消費とアクティビティのレポートが出ます。また、スリープ・復帰の履歴はイベントログ(システムログのKernel-Powerソース)に記録されるため、「いつスリープし、いつ何が理由で起きたか」を時系列で確認できます。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る