DOBON.NET DOBON.NETプログラミング掲示板過去ログ

スタートメニューの電源ボタン押下のイベント取得方法

環境/言語:[Vista HomePremium C#]
分類:[.NET]

Vista HomePremium 32bit SP1 を利用しています。
スタートメニューの電源ボタンをクリックした時に、ウィンドウを出して、シャットダウン(or スリープ)をするか、
中止するかの選択できるようにしたいと思っています。
というは、1クリックでシャットダウンしてしまうので、クリックミスで電源ボタンを押してしまうと、シャットダウンしてしまい困っています。
http://dobon.net/vb/dotnet/system/sessionending.html
を参考にしてプログラムを作ってみたのですが、作ってから気づきましたが、
このページに書かれてる内容では、OSがシャットダウン処理をし始めて、
全プログラム?にシャットダウンイベントが行き、
作ったプログラムにシャットダウンイベントが来たときに、シャットダウンを止めることができますが、
作ったプログラムにイベントが来る前に、いくつかのプログラムが終了してしまいます。
スタートメニューの電源ボタンが押された時に、すぐにイベントを受け取るにはどうすればいいでしょうか?
押した後、処理が始まる前に選択画面を出すプログラムを作りたいと思っています。
よろしくお願いします。
電源ボタンが押されてから、その処理(シャットダウン or スリープ)が始まるまでに間に、意図的にプログラムを実行させることは、もしかして不可能なのでしょうか?
よろしくお願いします。
> 1クリックでシャットダウンしてしまうので、クリックミスで電源ボタンを押してしまうと、シャットダウンしてしまい困っています。

動機がコレでしたら、コントロールパネルの「電源の管理」で動作を変更できると思いますが。
返信ありがとうございます。
シャットダウンをスリープや休止状態に変えるというのではなく、1クリックで電源切れるのを止めたいんです。
間違えてクリックしたら、そのときPCで処理してたのが終了してしまうので、困っています。
スリープと休止状態は、私のPCでは正常に復帰してくれません。なので、スタートメニューの電源ボタン押下の処理は、私にはシャットダウンしか選択肢がありません。
スタートメニューをクラシック(98、2000?)スタイルに換えれば、電源ボタン押下した時、終了するかの選択画面でるようになりますが、
Vistaのスタートメニューのまま利用したいんです。
よろしくお願いします。
> シャットダウンをスリープや休止状態に変えるというのではなく、
> 1クリックで電源切れるのを止めたいんです。
先のHongliangさんの発言は「PCについている物理的なスイッチ」のことを指しており、スタートメニューのことではありません。
実際、どちらを指しているんですか?

・物理的なスイッチの場合
電源の管理の設定から「何もしない」という設定ができます。
こうすれば、長押し以外の電源スイッチの押下は無視されます。
(長押しで電源が強制的に切れるのは防げません)

・スタートメニューのボタンの場合
デフォルトをスリープ・休止状態・シャットダウンに変えることぐらいはできるでしょうけれど、それ以外は無理じゃないですかね。


それと、シャットダウン/スリープが始まってからその処理を止めるという考えは何らかの問題を生む可能性が高いのでNGパターンでしょう。
(少なくとも一般解ではないはず)


> スタートメニューをクラシック(98、2000?)スタイルに換えれば、
> 電源ボタン押下した時、終了するかの選択画面でるようになりますが、
> Vistaのスタートメニューのまま利用したいんです。
無理じゃない?っていう答えを置いておきます。
あくまであのボタンはシャットダウンボタン or スリープボタンであり、終了方法の選択ボタンではないので。
また、この動作を自作プログラムで変更させることもできません。

変えるためにはWindows(というより、エクスプローラ・スタートメニュー)のその設定が存在する必要があります。
存在しないのであれば、クラシックスタイルで自衛するか、押さないように気をつけるしかないかと思います。
返信ありがとうございます。

> 実際、どちらを指しているんですか?
判断が付くように、スタートメニューの電源ボタンという言葉を使っていたのですが、わかりにくい文章ですみません。

> それと、シャットダウン/スリープが始まってからその処理を止めるという考えは何らかの問題を生む可能性が高いのでNGパターンでしょう。
だから、その処理が始まる前に、選択画面を出すプログラムを作れないかって話だったんですが・・・。

押さないように気をつけることにします。
解決していないので、解決済みのチェックは付けないでおきます。
ありがとうございました。
Vistaで使えるはずなんですが・・・
このAPI関係のことだと思うんです。
ShutdownBlockReasonCreate
ShutdownBlockReasonDestroy
ShutdownBlockReasonQuery
日本語では説明されたところがほとんど無く、英語サイトでは
そこそこありました。読破したんですが、多分・・・と言う所
です。(MobilePCのみならすいません)

参考までに。
> ShutdownBlockReasonCreate
> ShutdownBlockReasonDestroy
> ShutdownBlockReasonQuery
「選択する」ということはできないにしろ、「待った!」はかけられるような感じに見えます。

http://msdn.microsoft.com/en-us/library/aa376877(VS.85).aspx
http://msdn.microsoft.com/en-us/library/aa376878(VS.85).aspx

下記のサイトのTipsでは2点ほど気になる情報が寄せられています。
実際どのようになるかは分かりません。

http://pinvoke.net/default.aspx/user32/ShutdownBlockReasonCreate.html


// 参考
#define MAX_STR_BLOCKREASON 256
返信ありがとうございます。
ShutdownBlockReasonCreate
ShutdownBlockReasonDestroy
ShutdownBlockReasonQuery
について、さっそく調べて試してみます。
日本語サイトないですね><
ありがとうございました。
ShutdownBlockReasonCreateだけだと、シャットダウンしようとすると、
このアプリより、後に起動したアプリは終了してしまいました。
ほかのアプリより早くシャットダウンするように調べたところ、SetProcessShutdownParametersが見つかったので、これを使ってアプリのシャットダウンの優先順序をあげました。
http://msdn.microsoft.com/ja-jp/library/cc429338.aspx
を見ると、
300−3FF 最初の方でシャットダウンするアプリケーション用
400−4FF 最初の方でシャットダウンするシステムの構成要素用
となっていましたので、アプリなので、3FFに設定するのかな?と思ったのですが、4FFを設定したら設定できたので
システム構成用で一番最初にシャットダウンさせる値だと思う4FFを設定しました。(不安ですが・・・^^;)
これで他のアプリが(たぶん)終了することなく、シャットダウン(ついでにログオフも)が止めれるようになりました。
http://community.bartdesmet.net/blogs/bart/archive/2006/10/25/Windows-Vista-_2D00_-ShutdownBlockReasonCreate-in-C_2300_.aspx
の下の方にある選択画面がでるので、メッセージボックス等を用意する必要がなかったので、作りませんでした。
ただ、SetProcessShutdownParametersで設定した値と同じ値があるとどっちが先にシャットダウンされるかわからないようです。
システムのプログラムが終了しないか不安ではありますが、一応私が思っている動作をするようになりました。
どうもありがとうございました。

[DllImport("user32.dll")]
public extern static bool ShutdownBlockReasonCreate(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string pwszReason);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern int SetProcessShutdownParameters(int dwLevel, int dwFlags);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern int GetProcessShutdownParameters(ref int lpdwLevel, ref int lpdwFlags);

private const int WM_QUERYENDSESSION = 0x0011;
private const int WM_ENDSESSION = 0x0016;

public Form1()
{
  InitializeComponent();
  SetProcessShutdownParameters(0x4FF, 0); // システム内の他のプロセスから見た相対的なシャットダウンの優先順序を上げる
  ShutdownBlockReasonCreate(this.Handle, "シャットダウン処理を制限しています。");
}

protected override void WndProc(ref Message m)
{
 base.WndProc(ref m);
 switch (m.Msg)
 {
  case WM_QUERYENDSESSION:
  {
   m.Result = (IntPtr)0; // return false
   break;
  }
  case WM_ENDSESSION:
  {
   m.Result = (IntPtr)0; // return false
   break;
  }
  default:
   break;
 }
}
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板