• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 204
  • Last Modified:

program hangs while batch file is running

Hi,
  When one of the buttons in my program is clicked, it creates a batch file & 2 SQL scripts. It then runs the batch file which runs the 2 SQL scripts which output 2 text files. The text files are then parsed for the data required.
The problem is that when the batch file is running (about 20 seconds) the program & progress form freeze.The skin comes off the form also. Once the batch file finishes the form refresh's itself & the program is fine.
I thought the batch file would run independently of the program & the program would just check to see if it had finished once a second.
Does anyone know how I can get around this so that the forms don't freeze.

      ''' RUN MULTI.BAT
        Dim s As New System.Diagnostics.Process
        s.StartInfo.FileName = Application.StartupPath & "\temp\" & LOT & "MULTI.bat"
        s.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
        s.Start()
        's.WaitForExit(30000)
        i = 0
        Do Until i = 30
            If s.HasExited = False Then
                PROGRESS.ProgressBar1.Value = PROG
                PROGRESS.Refresh()
                frm.Refresh()

                System.Threading.Thread.Sleep(1000)
            Else
                PROG = 32
                PROGRESS.ProgressBar1.Value = PROG
                PROGRESS.Refresh()
                Exit Do
            End If
            i = i + 1
            PROG = PROG + 1
        Loop
        s.Close()
 
Thanks for the help,
E_MURF1.
0
e_murf1
Asked:
e_murf1
  • 2
1 Solution
 
gbzhhuCommented:
Use threads

System.Threading.Thread class
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
If you want to hold in a loop that won't lock up the GUI then:

            While Not s.HasExited
                System.Threading.Thread.Sleep(50)
                Application.DoEvents()
            Wend

Otherwise here is a threaded implementation that encapsulates the thread in a class:

Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents Label1 As System.Windows.Forms.Label
    Friend WithEvents Label2 As System.Windows.Forms.Label
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.Button1 = New System.Windows.Forms.Button
        Me.Label1 = New System.Windows.Forms.Label
        Me.Label2 = New System.Windows.Forms.Label
        Me.SuspendLayout()
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(40, 40)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(104, 24)
        Me.Button1.TabIndex = 0
        Me.Button1.Text = "Button1"
        '
        'Label1
        '
        Me.Label1.Location = New System.Drawing.Point(8, 120)
        Me.Label1.Name = "Label1"
        Me.Label1.Size = New System.Drawing.Size(272, 24)
        Me.Label1.TabIndex = 1
        Me.Label1.Text = "Label1"
        '
        'Label2
        '
        Me.Label2.Location = New System.Drawing.Point(8, 152)
        Me.Label2.Name = "Label2"
        Me.Label2.Size = New System.Drawing.Size(272, 24)
        Me.Label2.TabIndex = 2
        Me.Label2.Text = "Label2"
        '
        'Form2
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 266)
        Me.Controls.Add(Me.Label2)
        Me.Controls.Add(Me.Label1)
        Me.Controls.Add(Me.Button1)
        Me.Name = "Form2"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Public Delegate Sub StatusUpdate(ByVal sender As MyProcess, ByVal info As MyProcess.ProcessInfo)

    Private myThreads As New ArrayList

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim mp As New MyProcess("calc")
        AddHandler mp.ProcessUpdate, AddressOf Me.ProcessUpdate
        myThreads.Add(mp)
        mp.StartProcess()
    End Sub

    Private Sub ProcessUpdate(ByVal sender As MyProcess, ByVal info As MyProcess.ProcessInfo)
        ' If necessary, prevent cross-thread UI update violations via Delegates
        If Me.InvokeRequired Then
            Dim su As New StatusUpdate(AddressOf Me.UpdateGUI)
            Me.Invoke(su, New Object() {sender, info})
        Else
            UpdateGUI(sender, info)
        End If
    End Sub

    Private Sub UpdateGUI(ByVal sender As MyProcess, ByVal info As MyProcess.ProcessInfo)
        ' do something with the data in here...
        ' (it is safe to update the GUI since a Delegate was used if necessary)

        ' some possibilities...
        Select Case info.Status
            Case MyProcess.ProcessStatus.Complete
                Select Case info.ExeName
                    Case "calc"
                        Label1.Text = info.ExeName
                        Label2.Text = info.Message

                    Case "c:\prog1.exe"
                        ' take next step...

                End Select

            Case MyProcess.ProcessStatus.Aborted
                ' do something else in here..

            Case MyProcess.ProcessStatus.Failed
                ' or something else in here...

        End Select
    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        Dim mp As MyProcess
        For Each mp In myThreads
            mp.StopProcess()
        Next
    End Sub

    Public Class MyProcess

        Public Enum ProcessStatus
            Complete
            Aborted
            Failed
        End Enum

        Public Structure ProcessInfo
            Public ExeName As String
            Public Status As MyProcess.ProcessStatus
            Public Message As String

            Public Sub New(ByVal ExeName As String, ByVal Status As ProcessStatus, ByVal Message As String)
                Me.ExeName = ExeName
                Me.Status = Status
                Me.Message = Message
            End Sub
        End Structure

        Public Event ProcessUpdate(ByVal sender As MyProcess, ByVal info As MyProcess.ProcessInfo)

        Private Exe As String
        Private t As System.Threading.Thread
        Private p As Process
        Private abort As Boolean = False

        Public ReadOnly Property ExeName() As String
            Get
                Return Exe
            End Get
        End Property

        Public ReadOnly Property ExeComplete() As Boolean
            Get
                If Not IsNothing(p) Then
                    Return p.HasExited
                Else
                    Return False
                End If
            End Get
        End Property

        Private Sub New()
        End Sub

        Public Sub New(ByVal fullPathToExe As String)
            Exe = fullPathToExe
        End Sub

        Public Sub StartProcess()
            If IsNothing(p) Then
                t = New System.Threading.Thread(AddressOf Me.MonitorExe)
                t.Start()
            End If
        End Sub

        Private Sub MonitorExe()
            Try
                p = Process.Start(Exe)
                While Not abort AndAlso Not p.HasExited
                    p.WaitForExit(250)
                End While
                If Not abort Then
                    RaiseEvent ProcessUpdate(Me, New ProcessInfo(Exe, ProcessStatus.Complete, "Complete"))
                Else
                    p.Kill()
                    RaiseEvent ProcessUpdate(Me, New ProcessInfo(Exe, ProcessStatus.Aborted, "Aborted"))
                End If
            Catch ex As Exception
                RaiseEvent ProcessUpdate(Me, New ProcessInfo(Exe, ProcessStatus.Failed, ex.Message))
            End Try
        End Sub

        Public Sub StopProcess()
            abort = True
        End Sub

    End Class

End Class
0
 
e_murf1Author Commented:
Hi gbzhhu,
  I tried using the different threads & the program still froze, I could have been doing it wrong.

Hi Idlemind,
  I used your while loop & it worked perfect. I think mine wasn't working because I didn't use 'Application.DoEvents()'. I thought that having Refresh() in my loops would keep the GUI updated. I just have to go find out what 'DoEvents' is actually doing.

Thanks for your help, much appreciated.  
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now