none
電源状態がサスペンドになった後で、サスペンドを解除する RRS feed

  • 質問

  • お世話になっております。北窓舎の芦田と申します。
    特定のアプリが起動しているときに、サスペンド状態を無効にしたいと思っています。
    電源モードがサスペンドになった後で、それを解除する(サスペンド状態ではなくする)方法をお教えください。

    コードでは、電源モードが変化したらプロセスを取得し特定のアプリが起動しているかを判断し、
    起動していればサスペンドを無効に(レジューム状態に)したいと思っているのですが、サスペンド状態を解除することができません。
    現在のコードは次のとおりです。
    Private Sub SystemEvents_PowerModeChanged _
    	(ByVal sender As Object, ByVal e As Microsoft.Win32.PowerModeChangedEventArgs)
    	' --- 
    	Dim previousExecutionState As Long = 0D
    	' --- PowerMode(電源モード:Suspend/Resume)
    	Select Case e.Mode
    	    Case Is = Microsoft.Win32.PowerModes.Suspend
    		' --- ▼ サスペンド状態になった
    		Call cls_DGV.prc_Get_Process()          ' -- プロセスを取得(dgv_Process に格納)
    		Call cls_DGV.prc_Check_AppRunning()     ' -- 指定ソフトのプロセスが起動中かをチェック
    		If (cls_DGV.IsAppRunning) Then
    				
    		    ' --★★ 指定プロセスが起動中ならサスペンド禁止 ★★
    		    Me.DisplayHowToClose = False ' -- frm_HowToClose を表示しない
    		    SetThreadExecutionState(EXECUTION_STATE.ES_SYSTEM_REQUIRED Or EXECUTION_STATE.ES_CONTINUOUS)
    		    Me.PowerStatus = "prohigit from Suspending"
    
    		    Call cls_FileIO.prc_Write_LogFile(Me.PowerStatus) ' --■ Power.log ファイルを書き出す
    		End If
    		Case Is = Microsoft.Win32.PowerModes.Resume
    		    ' --- ▼ サスペンドから復帰した
    		    Me.PowerStatus = "Resume from Suspend/Sleep"
    		    Call cls_FileIO.prc_Write_LogFile(Me.PowerStatus) ' --■ Power.log ファイルを書き出す
    		    Me.DisplayHowToClose = True ' -- frm_HowToClose を表示する
    		End Select
    	End Sub
    	' --- スリープモードを抑止にする.
    	Private Function DisableSleepMode() As Long
    		Return SetThreadExecutionState(EXECUTION_STATE.ES_SYSTEM_REQUIRED Or EXECUTION_STATE.ES_CONTINUOUS)
    	End Function
    	' ---
    	Private Enum EXECUTION_STATE As Integer
    		ES_SYSTEM_REQUIRED = &H1
    		ES_DISPLAY_REQUIRED = &H2
    		ES_USER_PRESENT = &H4
    		ES_CONTINUOUS = &H80000000
    	End Enum
    	' ---
    	Private Declare Auto Function _
    		SetThreadExecutionState Lib "kernel32.dll" (ByVal esFlags As Long) As Long

    皆さまのお知恵を拝借できれば幸いです。

    Ashidacchi

    2017年7月24日 2:10

すべての返信

  • 本来はサスペンドへの遷移自体を禁止したいが、それができないので、次善の策としてサスペンドからの自動復帰ということにしたい、って感じでしょうかね?

    Waitable Timerを使えばサスペンドからの復帰ができるはずです。スレッドの扱いが面倒だった記憶がありますが。

    ただし、電源オプションの「スリープ解除タイマーの許可」によってユーザ側が禁止することもできたはず。

    // Win10では許可のところに重要なやつだけ認めるという項目が増えてるけど、CreateWaitableTimer(Ex)にそれっぽいフラグがあるわけでもないし、なんか別の方法が増えたのかしらん? 

    2017年7月24日 2:44
  • Hongliang さん、
    リプライしていただき、ありがとうございます。
    どんな場合にでも(常に)サスペンドへの遷移を禁止したいというわけではなく、特定のソフトが起動中の場合だけサスペンドへの遷移を禁止したいと思っています。

    Timer により常にプロセスを取得して、特定のプロセスが起動中ならサスペンド禁止にする方法も考えてみましたが、常にプロセスを取得する(例えば 1,000 mSec ごとにプロセスを取得する)のも無駄な気がしたので、サスペンド状態になった時だけプロセスを取得し(特定のプロセスが起動中なら)サスペンドを解除したいと思った次第です。

    プラットフォームとしては、Windows 7, 8.1, および 10 を想定しています。
    Waitable Timer については知らなかったので、調べてみます。

    取り急ぎ、お礼と背景説明まで。

    Ashidacchi

    2017年7月24日 2:51
  • すでにご存知の情報かもしれませんが、MSDNに以下のような記述がありました。

    [スタンバイや休止状態を阻止する方法]
    https://msdn.microsoft.com/ja-jp/library/cc440889.aspx


    2017年7月26日 4:08
  • uemu さん、情報をありがとうございます。
    ご紹介いただいた情報(コード)も試してみたのですが、電源状態がサスペンドになったことを検知してから、それを阻止しようとしてもうまくできませんでした。

    Ashidacchi

    2017年7月26日 4:12
  • 少し調べてみたところ、XPまでしか対応していないようでした。
    失礼致しました。

    VISTA以降は以下の方法が有効のようです。
    [スリープの回避]
    http://koolgeeks.seesaa.net/article/240017362.html

    この方法でも無理な場合は、Hongliang さんのご提案通り、Waitable Timerを使われるのがよいかもしれません。
    http://yamatyuu.net/computer/program/sample64/WaitableTimer.html
    # C言語のサンプルですが。。。


    2017年7月26日 4:33
  • uemu さん、情報提供していただき、ありがとうございます。

    繰り返しになりますが、サスペンドになるのを回避するのではなく、サスペンドになった後でサスペンドを解除する方法を探しています。

    遅くなりましたが、取り急ぎ、情報提供のお礼まで。

    Ashidacchi

    2017年7月27日 0:55
  • 根本的なことですが、質問者さんのいう「サスペンド」が何であるかを明確に把握できていますでしょうか?

    Windowsは常に機能追加されていて、モダンスタンバイ(was Instant Go or コネクトスタンバイ)に対応している機種もあります。プログラム的に「サスペンド」対策を行っていても、そもそも「サスペンド」されておらずモダンスタンバイなどが動作していた、ということはないでしょうか?

    2017年7月28日 22:38
  • 佐祐理 さん、コメントをいただき、ありがとうございます。

    VB.NET, C# などで System Power States(S0, S1 Low Power Idle, S1 など)を検知するコードをご存じならお教えいただけますでしょうか?
     

    Ashidacchi

    2017年7月29日 1:54
  • こちらからの確認には答えていただけない、つまり明確に把握できている上での質問だということでしょうか。また追加質問は本スレッドとは独立した質問に感じられますので、スレッドを分け、改めて投稿されることをお勧めします。
    2017年7月29日 7:44
  • 佐祐理 さん、失礼いたしました。

    ご質問(
    「サスペンド」が何であるかを明確に把握できているか)の答えは否でした。
    System Power States の S1 Low Power Idle がモダンスタンバイの状態だと思ったので、追加質問した次第です。

    Ashidacchi

    2017年7月29日 8:02
  • サスペンド、スタンバイ、スリープ等呼び方はいろいろありますが、CPUを停止させるS1以上のステートが大前提にあります。対してモダンスタンバイはCPUを停止させないS0 low-power idleであり、概念が全く異なります。

    質問者さんとしては、この新しい概念に対してどのような動作を期待するのかを説明するのが先であり、「電源状態がサスペンドになった後で、サスペンドを解除する」の延長で議論すべき話題ではないと考えます。
    また、質問の前提条件であるはずの「サスペンドが何であるか把握できているか」の確認を無視しておきながら、追加質問する態度は回答者を侮辱するものだとは思わないのでしょうか。

    なお、本スレッドについてのコメントとしては、SetThreadExecutionState(ES_SYSTEM_REQUIRED|ES_CONTINUOUS)の代わりにSetThreadExecutionState(ES_DISPLAY_REQUIRED|ES_CONTINUOUS)を使用した場合はどのような挙動になるでしょうか? もしくはSetThreadExecutionState(ES_SYSTEM_REQUIRED|ES_DISPLAY_REQUIRED|ES_CONTINUOUS)も。ディスプレイを表示するためにはシステムを停止できないためモダンスタンバイも含め省電力モードに入らなくなる可能性があるためです。

    2017年7月29日 8:34
  • サスペンド、スタンバイ、スリープ等呼び方はいろいろありますが、CPUを停止させるS1以上のステートが大前提にあります。対してモダンスタンバイはCPUを停止させないS0 low-power idleであり、概念が全く異なります。

    質問者さんとしては、この新しい概念に対してどのような動作を期待するのかを説明するのが先であり、「電源状態がサスペンドになった後で、サスペンドを解除する」の延長で議論すべき話題ではないと考えます。
    また、質問の前提条件であるはずの「サスペンドが何であるか把握できているか」の確認を無視しておきながら、追加質問する態度は回答者を侮辱するものだとは思わないのでしょうか。

    なお、本スレッドについてのコメントとしては、SetThreadExecutionState(ES_SYSTEM_REQUIRED|ES_CONTINUOUS)の代わりにSetThreadExecutionState(ES_DISPLAY_REQUIRED|ES_CONTINUOUS)を使用した場合はどのような挙動になるでしょうか? もしくはSetThreadExecutionState(ES_SYSTEM_REQUIRED|ES_DISPLAY_REQUIRED|ES_CONTINUOUS)も。ディスプレイを表示するためにはシステムを停止できないためモダンスタンバイも含め省電力モードに入らなくなる可能性があるためです。

    どのような誤り方をすれば佐祐理さんのご立腹が収まるのか分かりませんが・・・

    ご質問(ご確認)を無視したつもりではありません。知らなかったので慌てて調べた結果、System Power State が関わっているらしいと思い(誤解しているかも知れませんが)、System Power State について質問しました。その際に、知らなかったとの返答を失念したのは私のミスです。が、繰り返しますが、無視したつもりではありません。

    また、「本スレッドについてのコメントとしては・・・」に回答しないと、お叱りを受けるのでしょうか?
    スレッドを立てて(7/24)から日数を経ており、ソースコードは大きく変えていますが、それでも挙動確認しないと侮辱したとお感じになるのでしょうか?

    Ashidacchi

    2017年7月29日 8:48