简体   繁体   中英

How to find a running process when it is a bat file

I have a vb.net program that watches for an event and then executes the associated program with that event. Then monitors the task and if it stops unexpectedly, then it is restarted. All this works, but I tried to make the program smart enough that if the controlling program is stopped and restarted, while one of the existing events is running, it would find the correct task, then start monitoring it. I did a Process.GetProcess and looped looking at the MainModule.Filename. This works for .exe, but when starting a .bat file, the file name is “cmd.exe”.

Any ideas what other properties I can use to match up a running task?

Basic Start task:

Dim psi As New ProcessStartInfo()
psi.FileName = tmpProgramToExcute
psi.UseShellExecute = True
psi.Arguments = tmpCommandLineOptions
psi.Verb = "runas"
psi.WindowStyle = tmpWindowStyle
tmpTask = New Process
tmpTask.StartInfo = psi
tmpTask.Start()

Searching code:

If (tmpTask IsNot Nothing) AndAlso tmpTask.HasExited Then
    tmpTask.Dispose()
    tmpTask = Nothing
End If
Dim tmpProcess() As Process = Process.GetProcesses
For xLoop_tmpProcess As Integer = 0 To tmpProcess.Count - 1
    Try
        If tmpProcess(xLoop_tmpProcess).MainModule.FileName.ToLower = tmpProgramToExcute.ToLower Then
            tmpTask = tmpProcess(xLoop_tmpProcess)
            NewProcessingList(tmpKey).Task = tmpTask
            Exit For
        End If
    Catch ex As Exception
    End Try
Next

Updated 9/8/2016 12:39pm Local time I went back to my old vb6 program, which is btw the one I am replacing, was written in 2003. I had as one of my black box functions was to start a program. This is it:

Function StartPrg(PrgName As String, Optional tmpText As String = "", Optional WindowState As WindowStyle = 4, Optional CmdPram As String = "") As Long
'0     hidden and focus is passed to the hidden window.
'1     Has focus and is restored to its original size and position.
'2     Is displayed as an icon with focus (minimized).
'3     Is maximized with focus.
'4     Is restored to its most recent size and position. No Focus.
'6     Is displayed as an icon. No Focus.
Dim tmpPID As Long
Dim xLoop As Long
Dim yLoop As Long
Dim PrgStarted As Boolean
'Log.It "Try to start " + PrgName
'tmpPID = Shell(PrgName, WindowState)


Dim Ret As Integer
Dim Bfr As String
Dim ExPath As String
Dim Ext As String

'If Dir(PrgName) = "" Or PrgName = "" Then
'   StartPrg = -1
'   Exit Function
'End If

If Ext = ".EXE" Or Ext = ".COM" Or Ext = ".BAT" Then
   tmpPID = Shell(PrgName + " " + CmdPram, WindowState)
Else
   Bfr = String(300, 32)
   Ext = UCase(Right$(PrgName, 4))
   Ret = FindExecutable(PrgName, vbNullString, Bfr)
   If Ret > 32 Then
      ExPath = Left$(Bfr, InStr(Bfr, Chr$(0)) - 1)
      tmpPID = Shell(ExPath + " " + CmdPram, WindowState)
   Else
      StartPrg = -1
      Exit Function
   End If
End If

'Log.It PrgName + " started"
For xLoop = 1 To 10
   DoEvents
   If PrgStarted Then Exit For
   For xSleepLoop = 1 To 100
      PrgStarted = PrgExist(tmpPID)
      If PrgStarted Then Exit For
      Sleep 10
      DoEvents
   Next xSleepLoop
Next
If xLoop < 11 Then
   MyPID = tmpPID
   fEnumWindows
   If Len(tmpText) > 0 Then
      For xLoop = 1 To OnWin
         If MyWinList(1, xLoop) = tmpPID Then
            SendMessageA MyWinList(2, xLoop), WM_SETTEXT, 0&, tmpText
            DoEvents
            Sleep 10
         End If
      Next
   End If
   StartPrg = tmpPID
Else
   StartPrg = -1
   Exit Function
End If
End Function

So I tried to replcate it in vb.net:

Public Function ShellAndNotWait(ByVal sFilePath As String,
                                          Optional ByVal sCommandLineOptions As String = "",
                                          Optional ByRef sStdOut As Boolean = False,
                                          Optional ByRef sStdError As Boolean = False,
                                          Optional pWindowStyle As eShellWindowStyle = eShellWindowStyle.RecentSizeNoFocus,
                                          Optional pWindowName As String = "") As Process
            Dim psi As New ProcessStartInfo()
            psi.FileName = sFilePath
            psi.UseShellExecute = (Not (sFilePath.ToUpper.EndsWith(".EXE") Or sFilePath.ToUpper.EndsWith(".COM") Or sFilePath.ToUpper.EndsWith(".BAT")))
            psi.Arguments = sCommandLineOptions
            psi.RedirectStandardOutput = sStdOut
            psi.RedirectStandardError = sStdError
            psi.CreateNoWindow = sStdOut Or sStdError
            Select Case pWindowStyle
                Case eShellWindowStyle.HiddenFocus
                    psi.WindowStyle = ProcessWindowStyle.Hidden
                Case eShellWindowStyle.IconFocus Or
                     eShellWindowStyle.IconNoFocus
                    psi.WindowStyle = ProcessWindowStyle.Minimized
                Case eShellWindowStyle.RecentSizeFocus Or
                     eShellWindowStyle.RecentSizeNoFocus
                    psi.WindowStyle = ProcessWindowStyle.Normal
                Case eShellWindowStyle.MaximizedFocus
                    psi.WindowStyle = ProcessWindowStyle.Maximized
            End Select
            Dim proc As New Process
            proc.StartInfo = psi
            proc.Start()
            If proc Is Nothing Then Return Nothing
            Sleep(100)
            If pWindowName.Length > 0 Then SetWindowText(proc.MainWindowHandle, pWindowName)
            If pWindowStyle = eShellWindowStyle.HiddenFocus OrElse
                    pWindowStyle = eShellWindowStyle.IconFocus OrElse
                    pWindowStyle = eShellWindowStyle.MaximizedFocus OrElse
                    pWindowStyle = eShellWindowStyle.RecentSizeFocus Then
                AppActivate(proc.Id)
            End If
            Return proc

        End Function

I can set the title all that works. Then as long as it is unique I can find the task again and assume the task as if I started it from the start. My issue is the VB6 shell had 6 modes of starting the window and .Net doesn't. I was trying to emulate some of it, but setting the startinfo windowstyle to minimize does not work. After some google it looks like if you are starting cmd.exe, it ignores the "hint". A lot of posts was about hiding the window, so the fix was set CreateWindow to false. Well I want a window, just minimize to the task bar. If someone says something simple, I will leave it on this thread. Also I will do some more google, but if I can't find anything on this, I will start a new thread. For now I am leaving it open just so it will all be in one place, but looks like I went with the window title for the fix.

Bottom line.... To find an existing app that I started, but was orphen because the app that started it was restarted itself, I went with window title. So the rule is, all window titles that this app is managing must be unique.

More detail.... I was wanting a program to manage a list of programs, I call services, but they are not true window services, they are just plain programs and batch files that if they stop, they will be restarted. I went with a window app so I can have some sort of GUI to start/stop and if a program was stated hidden it could be made visible. So I created a class to track the info needed (clsServiceList), then added it to a list of call lstServices (lstServices = new list(of clsServiceList)). There are two main subs "ServiceUpdate" and "StartService". After a call to ServiceUpdate, all the status (properties) of lstServices should be current. This could be called at the start up to find orphen task or every few seconds to see if one needed to be restarted. As part of this thread was to find a way to set the window title, then manage the window style. So here is the code, if I need to add to it just let me know. Thanks all for your help.

    Private Class clsServiceList
        ';0     hidden And focus Is passed to the hidden window.  
        ';1     Has focus And Is restored to its original size And position. 
        ';2     Is displayed as an icon with focus (minimized). 
        ';3     Is maximized with focus. 
        ';4     Is restored to its most recent size And position. No Focus.
        ';6     Is displayed as an icon. No Focus.
        Public ProcessName As String
        Public ProgramToExcute As String
        Public CommandLineOptions As String
        Public Task As Process = Nothing
        Public WindowTitle As String = ""
        Public WindowStyle As eShellWindowStyle = eShellWindowStyle.RecentSizeNoFocus
        Public HowRun As String = "" 'KR keep running or JS just once
        Public IsWindowIconic As Boolean = False
        Public IsWindowVisible As Boolean = False
        Public IsWindowZoomed As Boolean = False
        Public IsWindowNormal As Boolean = False
        Sub New(pProcessName As String,
                 pProgramToExcute As String,
                 pCommandLineOptions As String,
                 pWindowTitle As String,
                 pWindowStyle As String,
                 pHowRun As String)
            Me.ProcessName = pProcessName
            Me.ProgramToExcute = pProgramToExcute
            Me.CommandLineOptions = pCommandLineOptions
            WindowStyle = CType(CIntNull(pWindowStyle), eShellWindowStyle)
            WindowTitle = pWindowTitle
            HowRun = pHowRun
        End Sub
    End Class

End Class

Private Sub ServicesUpdate()
    Dim tmpProcess() As Process = Process.GetProcesses
    For xLoop_Services As Integer = 0 To lstServices.Count - 1
        For xLoop_Process As Integer = 0 To tmpProcess.Count - 1
            If tmpProcess(xLoop_Process).MainWindowTitle = lstServices(xLoop_Services).WindowTitle Then
                If lstServices(xLoop_Services).Task Is Nothing Then lstServices(xLoop_Services).Task = tmpProcess(xLoop_Process)
                lstServices(xLoop_Services).IsWindowIconic = IsWindowIconic(lstServices(xLoop_Services).Task.MainWindowHandle)
                lstServices(xLoop_Services).IsWindowZoomed = IsWindowZoomed(lstServices(xLoop_Services).Task.MainWindowHandle)
                lstServices(xLoop_Services).IsWindowNormal = IsWindowNormal(lstServices(xLoop_Services).Task.MainWindowHandle)
                lstServices(xLoop_Services).IsWindowVisible = IsWindowVisible(lstServices(xLoop_Services).Task.MainWindowHandle)
            End If
        Next
    Next

End Sub

    Public Function IsWindowIconic(ByVal hWnd As IntPtr) As Boolean
        Return ((GetWindowLong(hWnd, WindowLongFlags.GWL_STYLE) And WS_MINIMIZE) = WS_MINIMIZE)
    End Function

    Public Function IsWindowVisible(ByVal hWnd As IntPtr) As Boolean
        Return ((GetWindowLong(hWnd, WindowLongFlags.GWL_STYLE) And WS_VISIBLE) = WS_VISIBLE)
    End Function

    Public Function IsWindowZoomed(ByVal hWnd As IntPtr) As Boolean
        Return ((GetWindowLong(hWnd, WindowLongFlags.GWL_STYLE) And WS_MAXIMIZE) = WS_MAXIMIZE)
    End Function

    Public Function IsWindowNormal(ByVal hWnd As IntPtr) As Boolean
        Return Not (IsWindowIconic(hWnd) Or IsWindowZoomed(hWnd))
    End Function


    <DllImport("user32.dll", SetLastError:=True)>
    Private Function GetWindowLong(hWnd As IntPtr,
 <MarshalAs(UnmanagedType.I4)> nIndex As WindowLongFlags) As Integer
    End Function
    Public Enum WindowLongFlags As Integer
        GWL_EXSTYLE = -20
        GWLP_HINSTANCE = -6
        GWLP_HWNDPARENT = -8
        GWL_ID = -12
        GWL_STYLE = -16
        GWL_USERDATA = -21
        GWL_WNDPROC = -4
        DWLP_USER = &H8
        DWLP_MSGRESULT = &H0
        DWLP_DLGPROC = &H4
    End Enum
    ' Window Styles 
    Const WS_OVERLAPPED As UInt32 = 0
    Const WS_POPUP As UInt32 = &H80000000&
    Const WS_CHILD As UInt32 = &H40000000
    Const WS_MINIMIZE As UInt32 = &H20000000
    Const WS_VISIBLE As UInt32 = &H10000000
    Const WS_DISABLED As UInt32 = &H8000000
    Const WS_CLIPSIBLINGS As UInt32 = &H4000000
    Const WS_CLIPCHILDREN As UInt32 = &H2000000
    Const WS_MAXIMIZE As UInt32 = &H1000000
    Const WS_CAPTION As UInt32 = &HC00000      ' WS_BORDER or WS_DLGFRAME  
    Const WS_BORDER As UInt32 = &H800000
    Const WS_DLGFRAME As UInt32 = &H400000
    Const WS_VSCROLL As UInt32 = &H200000
    Const WS_HSCROLL As UInt32 = &H100000
    Const WS_SYSMENU As UInt32 = &H80000
    Const WS_THICKFRAME As UInt32 = &H40000
    Const WS_GROUP As UInt32 = &H20000
    Const WS_TABSTOP As UInt32 = &H10000
    Const WS_MINIMIZEBOX As UInt32 = &H20000
    Const WS_MAXIMIZEBOX As UInt32 = &H10000
    Const WS_TILED As UInt32 = WS_OVERLAPPED
    Const WS_ICONIC As UInt32 = WS_MINIMIZE
    Const WS_SIZEBOX As UInt32 = WS_THICKFRAME

    ' Extended Window Styles 
    Const WS_EX_DLGMODALFRAME As UInt32 = &H1
    Const WS_EX_NOPARENTNOTIFY As UInt32 = &H4
    Const WS_EX_TOPMOST As UInt32 = &H8
    Const WS_EX_ACCEPTFILES As UInt32 = &H10
    Const WS_EX_TRANSPARENT As UInt32 = &H20
    Const WS_EX_MDICHILD As UInt32 = &H40
    Const WS_EX_TOOLWINDOW As UInt32 = &H80
    Const WS_EX_WINDOWEDGE As UInt32 = &H100
    Const WS_EX_CLIENTEDGE As UInt32 = &H200
    Const WS_EX_CONTEXTHELP As UInt32 = &H400
    Const WS_EX_RIGHT As UInt32 = &H1000
    Const WS_EX_LEFT As UInt32 = &H0
    Const WS_EX_RTLREADING As UInt32 = &H2000
    Const WS_EX_LTRREADING As UInt32 = &H0
    Const WS_EX_LEFTSCROLLBAR As UInt32 = &H4000
    Const WS_EX_RIGHTSCROLLBAR As UInt32 = &H0
    Const WS_EX_CONTROLPARENT As UInt32 = &H10000
    Const WS_EX_STATICEDGE As UInt32 = &H20000
    Const WS_EX_APPWINDOW As UInt32 = &H40000
    Const WS_EX_OVERLAPPEDWINDOW As UInt32 = (WS_EX_WINDOWEDGE Or WS_EX_CLIENTEDGE)
    Const WS_EX_PALETTEWINDOW As UInt32 = (WS_EX_WINDOWEDGE Or WS_EX_TOOLWINDOW Or WS_EX_TOPMOST)
    Const WS_EX_LAYERED As UInt32 = &H80000
    Const WS_EX_NOINHERITLAYOUT As UInt32 = &H100000 ' Disable inheritence of mirroring by children
    Const WS_EX_LAYOUTRTL As UInt32 = &H400000 ' Right to left mirroring
    Const WS_EX_COMPOSITED As UInt32 = &H2000000
    Const WS_EX_NOACTIVATE As UInt32 = &H8000000




Private Sub StartService(pServiceNumber As Integer)
    If Path.GetFileName(lstServices(pServiceNumber).ProgramToExcute) = lstServices(pServiceNumber).ProgramToExcute Then
        Dim tmpPath As String = Space(300)
        Dim tmpValue As Long = FindExecutable(lstServices(pServiceNumber).ProgramToExcute, vbNullString, tmpPath)
        If tmpValue > 32 Then
            lstServices(pServiceNumber).ProgramToExcute = tmpPath.Substring(0, tmpPath.IndexOf(vbNullChar))
        End If

    End If
    Dim tmpProcess As Process = ShellAndNotWait(lstServices(pServiceNumber).ProgramToExcute,
                                                          lstServices(pServiceNumber).CommandLineOptions,
                                                          False, False,
                                                          lstServices(pServiceNumber).WindowStyle,
                                                          lstServices(pServiceNumber).WindowTitle)
    lstServices(pServiceNumber).Task = tmpProcess
    lstServices(pServiceNumber).IsWindowIconic = IsWindowIconic(lstServices(pServiceNumber).Task.MainWindowHandle)
    lstServices(pServiceNumber).IsWindowZoomed = IsWindowZoomed(lstServices(pServiceNumber).Task.MainWindowHandle)
    lstServices(pServiceNumber).IsWindowNormal = IsWindowNormal(lstServices(pServiceNumber).Task.MainWindowHandle)
    lstServices(pServiceNumber).IsWindowVisible = IsWindowVisible(lstServices(pServiceNumber).Task.MainWindowHandle)
    If lstServices(pServiceNumber).WindowTitle.Length = 0 Then lstServices(pServiceNumber).WindowTitle = tmpProcess.MainWindowTitle
End Sub

    Public Function ShellAndNotWait(ByVal sFilePath As String,
                                      Optional ByVal sCommandLineOptions As String = "",
                                      Optional ByRef sStdOut As Boolean = False,
                                      Optional ByRef sStdError As Boolean = False,
                                      Optional pWindowStyle As eShellWindowStyle = eShellWindowStyle.RecentSizeNoFocus,
                                      Optional pWindowName As String = "") As Process
        Dim psi As New ProcessStartInfo()
        psi.FileName = sFilePath
        psi.UseShellExecute = (Not (sFilePath.ToUpper.EndsWith(".EXE") Or sFilePath.ToUpper.EndsWith(".COM") Or sFilePath.ToUpper.EndsWith(".BAT")))
        psi.Arguments = sCommandLineOptions
        psi.RedirectStandardOutput = sStdOut
        psi.RedirectStandardError = sStdError
        psi.CreateNoWindow = sStdOut Or sStdError
        Dim proc As New Process
        proc.StartInfo = psi
        proc.Start()
        If proc Is Nothing Then Return Nothing
        Sleep(100)
        If pWindowName.Length > 0 Then SetWindowText(proc.MainWindowHandle, pWindowName)
        Select Case pWindowStyle
            Case eShellWindowStyle.HiddenFocus Or eShellWindowStyle.HiddenFocus
                ShowWindow(proc.MainWindowHandle, eSHOW_WINDOW.SW_HIDE)
            Case eShellWindowStyle.IconFocus Or eShellWindowStyle.IconNoFocus
                ShowWindow(proc.MainWindowHandle, eSHOW_WINDOW.SW_MINIMIZE)
            Case eShellWindowStyle.MaximizedFocus
                ShowWindow(proc.MainWindowHandle, eSHOW_WINDOW.SW_MAXIMIZE)
            Case eShellWindowStyle.RecentSizeFocus Or eShellWindowStyle.RecentSizeNoFocus
                ShowWindow(proc.MainWindowHandle, eSHOW_WINDOW.SW_NORMAL)
        End Select
        If pWindowStyle = eShellWindowStyle.HiddenFocus OrElse
                pWindowStyle = eShellWindowStyle.IconFocus OrElse
                pWindowStyle = eShellWindowStyle.MaximizedFocus OrElse
                pWindowStyle = eShellWindowStyle.RecentSizeFocus Then
            AppActivate(proc.Id)
        End If
        Return proc

    End Function


    <DllImport("shell32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Function FindExecutable(ByVal lpFile As String,
                                   ByVal lpDirectory As String,
                                   ByVal lpResult As String) As Long
    End Function

    <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As eSHOW_WINDOW) As Integer
    End Function
    <Flags()>
    Public Enum eSHOW_WINDOW As Integer
        SW_HIDE = 0
        SW_SHOWNORMAL = 1
        SW_NORMAL = 1
        SW_SHOWMINIMIZED = 2
        SW_SHOWMAXIMIZED = 3
        SW_MAXIMIZE = 3
        SW_SHOWNOACTIVATE = 4
        SW_SHOW = 5
        SW_MINIMIZE = 6
        SW_SHOWMINNOACTIVE = 7
        SW_SHOWNA = 8
        SW_RESTORE = 9
        SW_SHOWDEFAULT = 10
        SW_FORCEMINIMIZE = 11
        SW_MAX = 11
    End Enum

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM