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

アプリ起動中のシャットダウンまたはログオフについて

環境/言語:[Windows2000 VB.NET .NET Framework1.1]
分類:[.NET]

いつも大変参考にさせていただいております。
okaと申します。

本日は、すぐにできるかなと思ったけども結構てこずっていることがありまして、皆さんのお知恵をお借りさせていただければと思い、投稿いたしました。

現在、ログイン画面→メインメニュー→各種画面→・・・
という具合に遷移するパターンのアプリを作成中です。
ちなみに遷移方法は、Me.Hide→form.ShowDialog→Me.Showです。
そこでAlt + F4キーで画面を消されないように制御をかけたものの、今度はOSからシャットダウンできないということになりました。
よくある e.chancel = true をClosingイベントに置くというやつです。

ここまでは、問題なく発見できたのですが、結局OSからシャットダウンが出来ません。
例えば、各種画面がアクティブの時、シャットダウンまたはログオフを実行すると、そのフォームのみがクローズされ、メインメニュー(呼び出し元)が表示された時点で止まってしまいます。

その他、WndProc内でWM_QUERYENDSESSIONメッセージを捕まえて、フラグを立て、順番にアプリ内でクローズ処理をするというのも試みたのですが、その場合は、アプリケーション終了後、OSのシャットダウンとなりません。

このような問題の回避策をご存知の方がいらっしゃれば、どうかご教授願えませんでしょうか?
よろしくお願いします。
> 現在、ログイン画面→メインメニュー→各種画面→・・・
> という具合に遷移するパターンのアプリを作成中です。
> ちなみに遷移方法は、Me.Hide→form.ShowDialog→Me.Showです。
> そこでAlt + F4キーで画面を消されないように制御をかけたものの、今度はOSからシャットダウンできないということになりました。
> よくある e.chancel = true をClosingイベントに置くというやつです。

過去にも同様の話がありましたが、基本的にAlt+F4を無効にするのは
あまり、よくないような気がします。ただ、方法はありますので。

単純に無効にするには、
http://santamartadotnet.hp.infoseek.co.jp/documents/dotnettips/tips019.html
こちらが参考になるかと。
また、このサイトのTipsにもDBONさんが終了の原因を調べる方法
をお書きになっていますので、そちらも参考になると思います。
■No10010に返信(antさんの記事)

おはようございます。
antさん レスありがとうございます。

> 過去にも同様の話がありましたが、基本的にAlt+F4を無効にするのは
> あまり、よくないような気がします。ただ、方法はありますので。

ごめんなさい。私の文面ではそうなりますよね。
改めて読み返してみて反省しました。
実は、今回の問題はAlt + F4ではなくて、アプリが起動しているときに、スタートボタンからログオフまたはシャットダウンを行っても、呼び出されたフォームがクローズされるだけで、呼び出しもとのフォームが表示された時点で、ログオフやシャットダウンが止まってしまうというものです。
つまり、アプリ起動中にシャットダウンやログオフが出来ないということです。
紛らわしい書き方で申し訳ありませんでした。

改めてよろしくお願いします。


>http://santamartadotnet.hp.infoseek.co.jp/documents/dotnettips/tips019.html
> こちらが参考になるかと。
> また、このサイトのTipsにもDBONさんが終了の原因を調べる方法
> をお書きになっていますので、そちらも参考になると思います。

ちなみにこれらのページは拝見させて頂いております。
> 実は、今回の問題はAlt + F4ではなくて、アプリが起動しているときに、スタートボタンからログオフまたはシャットダウンを行っても、呼び出されたフォームがクローズされるだけで、呼び出しもとのフォームが表示された時点で、ログオフやシャットダウンが止まってしまうというものです。
> つまり、アプリ起動中にシャットダウンやログオフが出来ないということです。
> 紛らわしい書き方で申し訳ありませんでした。


少し整理しておきたいのですが、Closingイベントのe.chancel = true
を取り除いてもシャットダウンができないということなのでしょうか?
もしClosingイベントでe.chancel = trueをなさっているのなら当然
シャットダウンもできないでしょう。しかし、santa martaさんの
「.NETでいきまっしょい!」で紹介されている方法では、
WM_SYSKEYDOWNを無視しているので、Alt+F4は無効になりますが、
WM_CLOSEは無視されないので、シャットダウンはできることになります。
■No10019に返信(antさんの記事)
antさん レスありがとうございます。

> 少し整理しておきたいのですが、Closingイベントのe.chancel = true
> を取り除いてもシャットダウンができないということなのでしょうか?

そうなのです。Closingイベントでの処理は何もない状態です。
現状Alt + F4に関しての制御は行っていません。

> もしClosingイベントでe.chancel = trueをなさっているのなら当然
> シャットダウンもできないでしょう。しかし、santa martaさんの
> 「.NETでいきまっしょい!」で紹介されている方法では、
> WM_SYSKEYDOWNを無視しているので、Alt+F4は無効になりますが、
> WM_CLOSEは無視されないので、シャットダウンはできることになります。

はい。私もそのように思っています。
実際に、アプリ起動中にログオフやシャットダウンをすると、途中までは正常に動いています。つまり、ログオフやシャットダウン処理が走ります。
ただ、メインフォームから呼び出したフォームが表示されている場合、その呼び出された表示中のフォームのみクローズされ、メインフォームが表示された時点で、ログオフまたはシャットダウンが止まってしまうのです。

呼び出し方は

'Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
frm = New Form2
Me.Hide()
frm.ShowDialog()
Me.Show()
End Sub

のようにしていますが、これ自体に問題があるのでしょうか?
上記、メインフォーム(Form1)が表示された時点で止まるというのは、Form2がシャットダウンによってクローズされた後、Me.Show()のところでForm1が表示される所で、シャットダウンが中断するという意味です。
ちなみにForm1が表示されている状態では正常にシャットダウンすることが出来ます。

わかりにくい文で申し訳ありません。
恐らく単純なことなのかもしれませんが、それゆえにはまっています・・・。
よろしくおねがいします。
> のようにしていますが、これ自体に問題があるのでしょうか?
> 上記、メインフォーム(Form1)が表示された時点で止まるというのは、Form2がシャットダウンによってクローズされた後、Me.Show()のところでForm1が表示される所で、シャットダウンが中断するという意味です。
> ちなみにForm1が表示されている状態では正常にシャットダウンすることが出来ます。

いや、Closingイベントに目が行ってしまって、本質が見えていませんでした。
問題なのはモーダルダイアログを表示しているときはそのメインウィンドウ
はWM_CLOSEが送信されてきても反応できないということにあります。
それがモーダルダイアログなので、普通なのですが、シャットダウン
の時には仕方がないので、WM_QUERYENDSESSIONを使って、メインウィンドウ
を閉じてやれなければならいでしょう。一度試されているようですが、
Message構造体のResultにtrueを設定なさっていないのではないでしょうか。
■No10023に返信(antさんの記事)
antさん、度々のレス本当にありがとうございます。

> Message構造体のResultにtrueを設定なさっていないのではないでしょうか。

これについては、逆にMessage構造体の中でやっていることがフラグの設定だけのため、その他に何かいるのでは?と思ってたりしているくらいなのですが・・・。

こんな感じです。↓

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

Const WM_QUERYENDSESSION As Integer = &H11

MyBase.WndProc(m)
Select Case m.Msg
Case WM_QUERYENDSESSION
g_bShutdown = True
Case Else

End Select
End Sub

このg_bShutdownというフラグはグローバル変数となっていて、それを呼び出しもとのフォームで判定して、クローズ処理をするかどうかの分岐をしています。

ちょっとVB6.0で試したんですけど、VB6.0ではモーダルフォームであっても問題なく全フォームクローズ後にシャットダウンされました。

このような状態ですが、どうかおわかりになればご教授お願いいたします。
■No10026に返信(okaさんの記事)

すみません。okaです。
自己レスです。

先程アップしたレスにあるWndProc内の処理を書き間違えてましたので訂正しておきます。

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

Const WM_QUERYENDSESSION As Integer = &H11

Select Case m.Msg
Case WM_QUERYENDSESSION
g_bShutdown = True
Case Else

End Select
MyBase.WndProc(m)
End Sub
>>Message構造体のResultにtrueを設定なさっていないのではないでしょうか。
> これについては、逆にMessage構造体の中でやっていることがフラグの設定だけのため、その他に何かいるのでは?と思ってたりしているくらいなのですが・・・。

いえいえ、その設定を行わない限りWindowsは終了できません。
WindowsはすべてのウィンドウにWM_QUERYENDSESSIONを送信して
一つでもFalseを返すと終了しないのです。したがって、

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

  Const WM_QUERYENDSESSION As Integer = &H11

  Select Case m.Msg
    Case WM_QUERYENDSESSION
      g_bShutdown = True
      m.Result = New IntPtr(1)
    Case Else
  End Select
  MyBase.WndProc(m)
End Sub

のような形でm.Result = New IntPtr(1)が必要です。

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/wm_queryendsession.asp
■No10031に返信(antさんの記事)
antさん レスありがとうございます。

結果報告をさせていただくと、antさんのご指摘点を加えることによって、問題なく終了処理が正常に行われるようになりました。
今回は、私の勉強不足と調査不足でantさんには大変お世話になりました。
おかげさまで、解決となりました。
ありがとうございました。
解決済み!

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