LoginSignup
7
3

More than 5 years have passed since last update.

Connected Standby でスリープを検出する方法

Posted at

※Win32の超絶原始的方法です。

WM_POWERBROADCASTをご存知ですか?

WM_POWERBROADCASTはConnected Standbyでは使えない

スリープとかサスペンドのことを調べてみると、いろんな方法が見つかります。System Power Management Eventsとか、SystemEvents.PowerModeChanged Eventとか。

WM_POWERBROADCASTは、電源まわりの何かが起きたときに発行されるウィンドウメッセージなので、例えば、ノートPCでAC電源を繋いだり外したりとかで受け取ることができます。
wParamに渡されるイベントの詳細を見ると、PBT_APMSUSPENDとあるので、スリープ検出できるような気がしてきますが、Connected StandbyとかInstant GoとかModern Standbyとか呼ばれているモードのWindowsで検出できません。

ちなみに、Win8以降でConnected Standby / Instant Go、Win10以降でModern Standbyと呼ばれているみたいです。だいたい同じものです。

PowerRegisterSuspendResumeNotification を使う

ひとつの解として、PowerRegisterSuspendResumeNotificationという関数があります。
スリープ・サスペンド・それらからの復帰のときに実行したい関数を、コールバック関数として登録することができます。

#include <Powerbase.h>
#pragma comment(lib, Powrprof.lib)

// コールバック関数を用意する
ULONG CALLBACK DeviceNotifyCallbackRoutine(
   _In_opt_ PVOID Context,
   ULONG          Type,
   PVOID          Setting
) {
  // ここにサスペンド・復帰したときの処理を書く
  if(Type == PBT_APMRESUMEAUTOMATIC) {
    // 例えばここはスリープやサスペンドから戻ってきたときに実行される
  }
}

int main() {

 // コールバック関数と、関数に渡すもの
  DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS parameters = { DeviceNotifyCallbackRoutine, &context };

  // コールバック関数を登録する. ユーザーモードでよいならRegisterSuspendResumeNotificationでもよい.
  HPOWERNOTIFY notify;
  PowerRegisterSuspendResumeNotification(DEVICE_NOTIFY_CALLBACK, &parameters, &notify);

  // ...

  // 最後に登録を解除する.ユーザーモードの関数を使ったときはUnregisterSuspendResumeNotificationを使う.
 PowerUnregisterSuspendResumeNotification(notify);

}

個人的にstd::unique_ptrを使いたい衝動があるので、

// ポインタを解放するときの処理
struct SuspendResumeNotificationDeleter {
  using pointer = HPOWERNOTIFY;
  void operator ()(HPOWERNOTIFY notify) {
    PowerUnregisterSuspendResumeNotification(notify);
  }
};

// 使う時はこんな感じでいいのかなぁ
HPOWERNOTIFY notify;
DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS parameters = { DeviceNotifyCallbackRoutine, &context };
PowerRegisterSuspendResumeNotification(DEVICE_NOTIFY_CALLBACK, &parameters, &notify);
std::unique_ptr<HPOWERNOTIFY, SuspendResumeNotificationDeleter> ptr(notify);
// 必要なくなったらptr.reset();

最後に

PowerModeChangedのほうが使いやすそう... Win32は苦行だし...

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3