1

我一直在为社区编写一个程序,并且遇到了一个我找不到答案的问题。

我有一个 VB.NET 应用程序,它有一个计时器事件,每秒触发一次以检查任务是否存在以及是否已启用,这会运行一些代码,根据 Windows 的版本将运行 schtask.exe 或 jt.exe ,两者都与创建和检查计划任务有关。

现在,当用户在我的程序运行时注销或关闭 Windows 时,我们经常收到错误“SCHTasks.exe - 应用程序错误。应用程序无法正确启动(0xc0000142)。单击确定关闭应用程序”,我JT.exe 也会出现相同的错误,我认为这是因为在关机/注销期间触发了计时器事件,并且 Windows 不会让相应的程序启动。

我尝试使用以下方法在表单关闭代码中禁用计时器,但这不起作用。

If e.CloseReason = CloseReason.WindowsShutDown Then Timer2ChkLoggingTask.enabled = False

我在互联网上找到的最新尝试,但这似乎也不起作用,添加处理程序在我的表单加载代码中。ShuttingDwn 是一个公共共享变量。

    AddHandler Microsoft.Win32.SystemEvents.SessionEnding, AddressOf SessionEnding

    Private Sub SessionEnding(ByVal sender As System.Object, ByVal e As Microsoft.Win32.SessionEndingEventArgs)

    ShuttingDwn = True

    End Sub

这是我运行 schtasks.exe 的代码,有一些不同的代码使用这个函数,但这是唯一真正运行 schtasks.exe 的代码,我认为检查 ShuttingDwn 的值会停止问题,除非我的代码到达这一点时它实际上还没有更新。

    Public Function SCHTasksRun(ByVal Arguments As String) As String                'Creates a task using SCHTasks


    If Form1.ShuttingDwn = True Then Return "Void" '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 = Arguments
    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. 
    Dim myString As String = myStreamReader.ReadToEnd
    myString = myString & myErrorStreamReader.ReadToEnd
    myProcess.WaitForExit()
    myProcess.Close()


    Return myString

End Function 

所以它永远不会运行两个程序中的任何一个(schtasks.exe 或 Jt.exe),或者至少这是理论上的,问题是我仍然偶尔会收到错误。

Try/catch 也没有产生错误,因为我没有收到消息窗口。

所以关于如何阻止这些错误的任何想法,它们只在关闭或注销时发生,但我仍然想修复它们。

4

2 回答 2

1

您可以处理Windows 发送到您的应用程序的WM_QUERYENDSESSION消息,或者(如果您问我更好)是使用新的 Windows 7 关闭阻止 API,例如ShutdownBlockReasonCreate

于 2013-11-04T02:51:42.270 回答
0

在 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 中关闭/注销时仍然出现错误。

于 2013-11-09T21:40:53.490 回答