在 Dan-o 的帮助下,我指出了正确的方向,我现在已经解决了这个问题。我不知道这段代码是否完全正确,但到目前为止它似乎运行良好。
原来的计时器是使用在同一个线程中运行的 Windows.Forms.Timer 触发的,因此我的任务检查代码阻止了对 Windows 关闭的检测,我现在使用 System.Timers.Timer,它不会阻止代码. 我还修改了检查任务的代码,并将其隔离,因此它不能由我的任何其他例程运行。
我在 Public Class Form1 之后添加了这个
Public Const WM_QUERYENDSESSION As Integer = &H11 'From http://vbcity.com/forums/t/45823.aspx
Public Shared ShuttingDwn As Boolean = False 'If Windows is shutting down or logging off this gets set to true.
Public Structure TaskExistEnabled 'Structure variable used in function for checking if task exists and is enabled.
Public TaskExists As Boolean
Public TaskEnabled As Boolean
End Structure
然后将此子添加到我的主窗体 form1 中。
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
'Listens for system closing down - This sets a flag when windows Windows shuts down or logs off
'From http://vbcity.com/forums/t/45823.aspx
If m.Msg = WM_QUERYENDSESSION Then
ShuttingDwn = True
End If
MyBase.WndProc(m)
End Sub 'WndProc
在 Sub Form1_Load 代码中创建了我的 System.Timers.Timer。
AddHandler Timer2ChkLoggingTask.Elapsed, New System.Timers.ElapsedEventHandler(AddressOf Timer2ChkLoggingTask_Tick) 'Timer for the task checking
Timer2ChkLoggingTask.Interval = 1000
然后我在我的主 Form1 上创建了计时器代码
Private Sub Timer2ChkLoggingTask_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
'This is only used by the timer for checking the tasks - it runs in a different thread, and so needs to be entirely self contained.
'It was made to run in parallel so the main code was not blocked, so that system shutting would be picked up.
Timer2ChkLoggingTask.Stop() 'Stopping the timer stops the code being called more than once if it take longer than the interval to complete.
Dim TaskExists_oldVal As Boolean = Taskinfo.TaskExists 'Store the old value so we can see if its changed at the end
Dim TaskEnabled_OldVal As Boolean = Taskinfo.TaskEnabled 'Store the old value so we can see if its changed at the end
Dim Mystring As String
If TaskVersion = "V0" Or TaskVersion = "V1" Then 'We have an OS that stores the tasks in Windows/Task
Taskinfo.TaskExists = (IO.File.Exists(Environment.GetEnvironmentVariable("windir") & "\Tasks\" & LoggingTaskName & ".job"))
If Taskinfo.TaskExists = True Then
If ShuttingDwn = False Then 'This in theory should stop an error when shutting down.
' This is the code for the base process
Dim myProcess As New Process()
' Start a new instance of this program
Dim myProcessStartInfo As New ProcessStartInfo(JT)
myProcessStartInfo.Arguments = " /LJ " & QUOTE & Environment.GetEnvironmentVariable("windir") & "\Tasks\" & LoggingTaskName & ".job" & QUOTE & " /PJ"
myProcessStartInfo.UseShellExecute = False
myProcessStartInfo.CreateNoWindow = True
myProcessStartInfo.RedirectStandardOutput = True
myProcess.StartInfo = myProcessStartInfo
Try
myProcess.Start()
Catch ex As Exception
MsgBox(ex.Message)
End Try
Dim myStreamReader As StreamReader = myProcess.StandardOutput
' Read the standard output of the spawned process.
Mystring = myStreamReader.ReadToEnd
myProcess.WaitForExit()
myProcess.Close()
Taskinfo.TaskEnabled = Not Mystring.Contains("Suspend = 1")
End If
End If
Else 'We have Vista upwards and will use schtasks
If ShuttingDwn = False Then 'This in theory should stop an error when shutting down.
' This is the code for the base process
Dim myProcess As New Process()
' Start a new instance of this program
Dim myProcessStartInfo As New ProcessStartInfo("schTasks")
myProcessStartInfo.Arguments = " /Query /TN " & QUOTE & LoggingTaskName & QUOTE
myProcessStartInfo.UseShellExecute = False
myProcessStartInfo.CreateNoWindow = True
myProcessStartInfo.RedirectStandardOutput = True
myProcessStartInfo.RedirectStandardError = True
myProcess.StartInfo = myProcessStartInfo
Try
myProcess.Start()
Catch ex As Exception
MsgBox("There was an error: " & ex.Message)
End Try
Dim myStreamReader As StreamReader = myProcess.StandardOutput
Dim myErrorStreamReader As StreamReader = myProcess.StandardError
' Read the standard output of the spawned process.
Mystring = myStreamReader.ReadToEnd
Mystring = Mystring & myErrorStreamReader.ReadToEnd
myProcess.WaitForExit()
myProcess.Close()
Taskinfo.TaskExists = Not Mystring.Contains("ERROR: The system cannot find the file specified.")
Taskinfo.TaskEnabled = Not Mystring.Contains("Disabled")
End If
End If
If TaskEnabled_OldVal <> Taskinfo.TaskEnabled Or TaskExists_oldVal <> Taskinfo.TaskExists Then 'If either of the values have changed we need to update the buttons.
Me.BeginInvoke(New TimerStart(AddressOf TimerStartFunction)) 'Whilst a background worker thread can stop a timer it can't start - see here http://stackoverflow.com/questions/18545787/timer-can-be-stopped-in-backgroundworker-but-cant-be-started
End If
Timer2ChkLoggingTask.Start()
End Sub
显示按钮/标签的实际更新现在由一个单独的计时器处理,该计时器只查看 Taskinfo 的值,仅当任何 taskinfo 值发生更改时才启用计时器,然后按钮更新代码禁用计时器,所以它仅在任一 taskinfo 变量更改时运行一次。
更新。虽然这似乎在 W7 和 W8 中完美运行,但在 Windows XP 中关闭/注销时仍然出现错误。