YamaStudio.net

【C#開発】「スリープさせない!デスクトップ警備員」開発記——FPSを落とさない常駐アプリの作り方とMicrosoft Store公開

公開日: 2026年3月10日 | カテゴリ: ツール開発 / C#

「自分が欲しいもの」から始まったアプリ開発

ゲームのダウンロード中や、ちょっとした離席の間にPCがスリープしてしまい、作業が中断される煩わしさ。これを解決するために開発したのが、PCの強制スリープをブロックする常駐型アプリ「スリープさせない!デスクトップ警備員」です。EFTのパッチ待ち、Squadのサーバー待ち、大容量Modのダウンロード——「スリープしないでくれ」場面はゲーマー生活に溢れています。

私自身がC#やJavaなどを扱えることもあり、「無いなら自分で作ってしまおう」と思い立ったのがプロジェクトの始まりでした。Windowsの電源管理APIを叩いてスリープを阻害するというシンプルな仕組みですが、ゲームのパフォーマンス(FPS)に一切影響を与えないよう、徹底的に軽量なバックグラウンド処理を目指してコーディングを行いました。

SetThreadExecutionState とは(簡単な説明)

Windowsには「今このスレッドは実行中だから、PCをスリープさせないで」というAPI SetThreadExecutionState があります。C#からは P/Invoke で呼び出します。

  • ES_CONTINUOUS: 状態を継続的に維持
  • ES_SYSTEM_REQUIRED: システム(PC本体)のスリープを防ぐ
  • ES_DISPLAY_REQUIRED: ディスプレイの消灯を防ぐ(オプション)

原理は単純ですが、「どのタイミングで呼ぶか」「解除を忘れないか」「呼び出し頻度」が品質を決めます。過剰な呼び出しはCPUを無駄に使い、ゲームのマイクロスタッターの原因になり得ます。

C#軽量化:GC・プーリング・トレイUI

FPSゲームはCPUとメモリのリソースを極限まで消費するため、常駐アプリが重い処理を行うとマイクロスタッター(カクつき)の原因になります。以下が実装の要点です。

ガベージコレクション(GC)対策

C#には不要なメモリを自動で解放するGCがありますが、ゲーム中に発生すると処理落ちの原因になります。ループ処理の中で毎回 new でインスタンスを生成するのを避け、一度作った StringBuilder やタイマー用オブジェクトを再利用(プーリング)する設計にしました。

トレイUIのフリーズ防止

システムトレイ常駐時はUIの描画処理を完全に停止。NotifyIconの更新も状態変化時のみ。WinForms/WPFの再描画ループがバックグラウンドで回らないよう、Hide() + 最小化トレイ化でリソース消費をカットしています。

タイマーインターバルの最適化

SetThreadExecutionState を毎秒呼ぶ必要はありません。ES_CONTINUOUS フラグ付きで1回呼べば、明示的に解除するまで有効です。定期呼び出しは「生存確認」程度に5〜10分間隔へ。これによりCPU使用率は0.1%未満を維持できました。

Microsoft Store公開への高いハードル

開発自体は順調に進みましたが、最大の難関は「Microsoft Storeへの公開審査」でした。ユーザーに安心してダウンロードしてもらうためには公式ストアを経由するのがベストだと考えたのですが、個人開発者にとってはクリアすべき課題が山積みでした。

  • MSIXパッケージング: 証明書、バージョン番号、依存関係の整理
  • プライバシーポリシー: データ収集なしでもURL必須
  • 審査リジェクト: アイコン解像度、スクリーンショットサイズで2回落ちた
  • サイドロードテスト: 仮想マシンと実機両方でスリープ阻止を検証

リジェクト(審査落ち)と修正を繰り返し、コードを見直しては申請し直す日々。3週間ほどかかりましたが、最終的に審査を通過し、ストア上に自分のアプリが並んだ瞬間の達成感は、ゲームの難関ボスを倒した時以上のものがありました。

他のゲーマー向けユーティリティ開発Tips

  1. FPS計測を信頼する: 常駐前後でMSI Afterburnerの1% Lowを比較
  2. 機能を絞る: 「スリープ阻止だけ」——多機能は重くなる
  3. 自動起動はオプション: デフォルトOff。ユーザーの選択を尊重
  4. Store公開は早めに: パッケージ要件の学習コストが高い
  5. オープンソース検討: GitHub公開でフィードバックを得やすい

まとめ

「スリープさせない!デスクトップ警備員」は、小さなAPIラッパーに見えて、ゲーマー環境への配慮(GC、タイマー、UI)が品質を決めました。今後も、ゲーマーの痒い所に手が届くようなツールの開発を続けていきたいと思います。C#最適化の詳細は本記事に統合済みです(旧 article-csharp-optimization.html から移行)。

実装で使った技術スタック

  • 言語: C# / .NET(WinForms または WPF)
  • API: kernel32.dll の SetThreadExecutionState(P/Invoke)
  • UI: NotifyIcon(システムトレイ)、コンテキストメニュー
  • 配布: MSIX → Microsoft Store

パフォーマンス検証結果

EFT(Streets、DLSS Quality)プレイ中に常駐ON/OFFで1% Low fpsを比較しました。差は誤差範囲(±1fps)。タスクマネージャー上のCPU使用率は0.1%未満、メモリ20MB前後。ゲーマーが「常駐を恐れる」必要がないレベルまで削ぎ落とせたと自負しています。

Store公開で学んだこと

審査は「コードの正しさ」より「パッケージ要件の充足」が半分です。アイコン解像度(44x44〜256x256)、スクリーンショット1366x768以上、年齢区分、プライバシーポリシーURL——チェックリスト化して2回目の申請で通過しました。個人開発者は最初からStore公開を視野に入れ、開発中からMSIXビルドを試すのが近道です。

コード設計の要点(抜粋)

メインループは System.Threading.Timer ではなく、System.Windows.Forms.Timer をUIスレッド同期で使い、トレイアイコン更新との競合を避けました。SetThreadExecutionState の呼び出しは、アプリ有効化時に1回、無効化時にクリア——定期ポーリングは「万が一OSが状態をリセットした」場合の保険として10分間隔のみです。

ゲーマー向けユーティリティは「機能追加」より「削る勇気」が品質を決めます。オーバーレイ、統計、RGB連携——欲しくなる機能は山ほどありますが、スリープ阻止に特化した結果、Storeレビューでも「軽い」「邪魔にならない」という評価につながりました。

読者へのお願い

同様の常駐ツールを開発する方へ。SetThreadExecutionState は強力ですが、解除を忘れるとPCが眠らなくなります。必ずトレイメニューから「終了」で ES_CONTINUOUS をクリアする設計にしてください。ゲームのFPSを落とさない軽量常駐——この記事が、あなたの開発の参考になれば幸いです。

開発タイムライン(参考)

フェーズ期間内容
プロトタイプ2日P/Invoke + トレイアイコン。動作確認
軽量化1週間GC/タイマー/UI停止。fps計測
MSIX化1週間パッケージング、証明書、テスト
Store審査3週間リジェクト2回、修正、再申請

合計約1.5ヶ月で公開まで到達。個人開発の現実的なスケジュールとして、参考になればと思います。旧記事「ゲーマー向け常駐アプリの軽量化」は本ページに統合済みです。

← 記事一覧へ戻る