設定した時間が経過したらWindowsをシャットダウンするプログラムを
作っているのですが、正常にシャットダウンされません。
フォームにタイマーコントロールを貼り付け、
Interval = 1000
に設定し、テキストボックスに入力された値を
タイマーイベント内で−1していき、
0以下になったらWindowsをシャットダウンするようにしてあります。
ただ、下のようなコードだとうまくいきません。
現象としては、全てのウィンドウが閉じ、
壁紙だけになった状態から、何も起こらないんです。
マウスカーソルと壁紙だけ表示されており、マウスカーソルは動くのですが、
キー入力等は一切反応しない状態になります。
ですが、
Timer1.Enabled = Falseの行のコメントをはずすと、
正常にシャットダウンされるんです。
ただ、それがなぜなのかが分かりません。
Private Sub Timer1_Timer()
nLeftTime = nLeftTime - 1
If nLeftTime <= 0 Then
' Timer1.Enabled = False '←ここの行
' Windowsの終了
Call ExitWindowsEx(enmShutdown, 0)
End If
End Sub
なぜこういう質問をしたかというと、
別の環境では、コメントアウトしないと正常に動かず、
コメントをはずすと、シャットダウンされないという現象が起こるらしく、
もしかしたらTimer1.Enabledとは別の原因があるのかもしれないと
思ったからです。
もしTimer1.Enabled = Falseのやり方が合っているのでしたら、
なぜこれを行わないと正常に終了しないのかを
教えていただけないでしょうか。
どうか宜しくお願いいたします。
Timer1.Enabled = False
の位置を
Call ExitWindowsEx(enmShutdown, 0)
の後にもってきては?
Take1さんありがとうございます。
現在コメントアウトしないと正常に動かないPCが
手元に無いため、
Timer1.Enabled = Falseを実行しないと
正常に動かないPCでしか試せれませんが、
Timer1.Enabled = Falseを
Call ExitWindowsEx(enmShutdown, 0)
の前にしても後にしても、
正常にシャットダウンされました。
それから、もう一台のPCで実行してみたところ、
コメントアウトしても、しなくても正常にシャットダウンされる
PCも見つかりました。ますます原因が分からなくなってきました。
それぞれの環境で違う点を挙げておきます。
・Timer1.Enabled = Falseを実行する→正常にシャットダウン
Timer1.Enabled = Falseをコメントアウト→壁紙だけ残る
PC1 WinXP Pro : Visual Studio 6.0 Pro SP5
PC2 Win2k Pro SP3 : Visual Studio 6.0 Pro SP5
・Timer1.Enabled = Falseを実行する→反応なし(らしい)
Timer1.Enabled = Falseをコメントアウト→正常にシャットダウン
PC3 Win2k Pro : 開発環境無し
※相手先のPCのため、現象の詳細を確認中
・Timer1.Enabled = Falseを実行・コメントアウトにかかわらず
正常にシャットダウン
PC4 Win2k Pro SP4 : Visual Basic 6.0 Pro SP5 及び
Visual C++ 6.0 Pro SP5
おそらくDLL等のバージョンの違いのために
現象が違うのだと思いますが、
どのDLLなのか分かりません。
もしかしたらDLLが原因ではないかもしれませんし。
もしお分かりになる方がいらっしゃいましたら、
どうか教えてもらえないでしょうか。
横レス失礼します。
シャットダウンの特権の変更はされていますでしょうか?
OSによっては特権の変更をしないと正しく終了しませんょ。
カレントのプロセスからOpenProcessTokenでアクセストークンのハンドルを
LookupPrivilegeValueでLUIDを取得し
_TOKEN_PRIVILEGESの属性をSE_PRIVILEGE_ENABLEDに変更して
AdjustTokenPrivilegesにて調整してみて下さい。
さわさんありがとうございます。
シャットダウン特権の設定は以下のように別関数にて行っています。
このため、どのPC・OSでも
Timer1.Enabled = Falseのコメント・非コメントさえ変えれば、
正常にシャットダウンされます。
Private Function SetPrivillege(SE_NAME As String) As Boolean
Dim lngRet As Long
Dim hToken As Long
Dim udtLUID As LUID
Dim udtTokenPrv As TOKEN_PRIVILEGES
'カレントプロセスに関連付けられているアクセストークンを開く
If OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hToken) Then
' ローカル一意識別子(LUID)を取得し、指定された特権名をローカルに表現
If LookupPrivilegeValue(vbNullString, SE_NAME, udtLUID) Then
udtTokenPrv.PrivilegeCount = 1
udtTokenPrv.Privileges(0).pLuid = udtLUID
udtTokenPrv.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED
' 指定された特権を有効にする
If AdjustTokenPrivileges(hToken, 0, udtTokenPrv, LenB(udtTokenPrv), ByVal 0&, ByVal 0&) Then
SetPrivillege = True
End If
End If
End If
' トークンハンドルを閉じる
If hToken Then CloseHandle hToken
End Function
Timer1.Enabled = False を Call ExitWindowsEx(enmShutdown, 0)
の前にあるとコードの通り正確に実行(コードの発行と処理がほぼ同時に)されると Call EXit〜 は呼び出される事なくタイマーイベントは終了されます。
たまたま実行されたりすることがあるのは、おそらくタイムラグだとおもいます。
コンピュータの環境条件等によっては、まず Timer1.Enabled = False が呼び出されそして実行・・される前に Call EXit〜 が呼び出され、直後に Timer1.Enabled = False が実行されることがあります。
タイマーイベントはあつかいかた次第で不具合がおこりやすいのであなどれません。
対処として、例えばタイマーイベント内の処理をできるだけ減らすとか、
インターバルを大きくするとか、タイマーイベントの外に
プロシージャをつくって、それをタイマーイベントから呼び出してユーザー実行中のプログラムをすべて強制終了させて Call EXit〜 する、という工夫も必要かもしれません。
Take1さんありがとうございます。
すみません、私の説明が下手でうまく伝わっていないみたいです。
正常にシャットダウン、全てのウィンドウが消えて壁紙だけ残る、
反応なし(シャットダウン処理が走らない)、の3つの現象ですが、
Timer1.Enabled = Falseの行のコメント・非コメントの状態にもよりますが、
同じ状態で行えば、毎回必ず起こります。
たまたま正常に終了したりしなかったりということはありません。
Timer1.Enabled = False が Call ExitWindowsEx(enmShutdown, 0) の
前にあっても後にあっても、PC1・2・4は全て毎回必ず正常終了します。
PC1・2に関しては、Timer1.Enabled = Falseを
Form_Unloadイベント内に移動させても、
タイマーイベント内でコメントアウトしたときと同じく
壁紙だけが残り、無反応となります。
ですが、この状態で電源ボタン長押しにて電源オフを行い、
再度起動しても、スキャンディスクが走らないことから、
Windows自体は既に終了したことになっていると思われます。
まず?ExitWindowsExが正常に実行されているのかは
確認されましたか?
if ExitWindowsEx <> True then
nCode := GetLastError;
Debug.Print SysErrorMessage( nCode )
end if
みたいな?Apiのエラーであるのか?
タイムラグ等のイベント連鎖が関係しているのか?
いかがでしょう。。
はずしているかもしれませんが...
私も以前リモートシャットオフでトラブッたことがあります。
そのときはw98でしたが。
結局ネットワークがうまく切断されないと言う結論になり、
Shell "c:\windows\net use * /del"を
(一秒ほど待つ)
Call ExitWindowsEx(EWX_FORCE + EWX_SHUTDOWN, rsv)
の前に入れました。
最終的には完全には解決されませんでしたが、windowsのshutt down
の最後の画面でハングする回数は入れない場合の1/10位になりました。
IF内のイベントはTimer1.Enabled = False後も
処理されるようですね。失礼しましたm(_ _)m
以前失敗した事を錯誤して記憶してました。
自分の環境(XP,HOME,ノートパソコン と 98,ノートパソコン)では
たきさん のタイマーイベント方法でたくさんのアプリケーションを起動させたままでもなんの問題もなく終了します。
調べてみて情報ください。
ツイート | ![]() |