VB 6:如何执行一个 .bat 文件并等待它运行完毕后再继续?

4

VB 6:我如何执行一个.bat文件,但在继续之前等待其完成运行?

3个回答

6

这里有一些简单的代码可以实现此功能。请注意,它使用DoEvents来发送消息,因此在等待时您的应用程序不会被冻结。

Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Private Const SYNCHRONIZE = &H100000
Private Const WAIT_TIMEOUT As Long = &H102&

Private Sub RunCommandLine(sCmdLine As String)

    Dim nProcessID      As Long
    Dim hProcess        As Long
    Dim nResult         As Long

    nProcessID = Shell(sCmdLine, vbNormalNoFocus)

    If nProcessID <> 0 Then

        hProcess = OpenProcess(SYNCHRONIZE, 0, nProcessID)

        If hProcess <> 0 Then
            Do

                DoEvents
                nResult = WaitForSingleObject(hProcess, 50)

            Loop Until nResult <> WAIT_TIMEOUT Or m_bStop
            CloseHandle hProcess

        End If
    End If


End Sub

你忘了将 WAIT_TIMEOUT 和 SYNCHRONIZE 定义为常量并赋值,否则代码将把它们视为空值,这就失去了它们的作用。 - Ahmad
添加。当然,在所有VB6代码中始终使用Option Explicit以避免此风险! - Joel Spolsky

6

您需要使用Win32 API调用ShellExecuteEx并在SHELLEXECUTEINFO结构中等待从ShellExecuteEx返回的进程句柄上的WaitForSingleObject。这是我从一个项目中提取出来的旧代码。它以前百分之百地工作,但我可能没有包含所有依赖项。您应该能够根据您的要求进行编辑:

      Type SHELLEXECUTEINFO
                cbSize As Long
                fMask As Long
                hwnd As Long
                lpVerb As String
                lpFile As String
                lpParameters As String
                lpDirectory As String
                nShow As Long
                hInstApp As Long
                '  Optional fields'
                lpIDList As Long
                lpClass As String
                hkeyClass As Long
                dwHotKey As Long
                hIcon As Long
                hProcess As Long
        End Type

        Public Declare Function ShellExecuteEx Lib "shell32.dll" 
            (lpExecInfo As SHELLEXECUTEINFO) As Long

        Public Declare Function apiShellExecute Lib "shell32.dll" _
            Alias "ShellExecuteA" _
            (ByVal hwnd As Long, _
            ByVal lpOperation As String, _
            ByVal lpFile As String, _
            ByVal lpParameters As String, _
            ByVal lpDirectory As String, _
            ByVal nShowCmd As Long) _
                As Long

        Declare Function WaitForSingleObject Lib "kernel32" 
             (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long


        Public Const SEE_MASK_NOCLOSEPROCESS As Long = &H40
        Public Const SEE_MASK_FLAG_DDEWAIT As Long = &H100

        '***App Window Constants***'
        Public Const WIN_NORMAL = 1         'Open Normal'
        Public Const WIN_MAX = 2            'Open Maximized'
        Public Const WIN_MIN = 3            'Open Minimized'

        '***Error Codes***'
        Private Const ERROR_SUCCESS = 32&
        Private Const ERROR_NO_ASSOC = 31&
        Private Const ERROR_OUT_OF_MEM = 0&
        Private Const ERROR_FILE_NOT_FOUND = 2&
        Private Const ERROR_PATH_NOT_FOUND = 3&
        Private Const ERROR_BAD_FORMAT = 11&

' Returns 'True' if file was opened ...'
Public Function fHandleFile(ByVal stFile As String, _
                            ByVal lShowHow As Long, _
                            ByRef stRet As String, _
                            Optional ByVal bWaitForClose As Boolean = False) As Boolean
On Error GoTo err_Handler
    Dim lRet As Long
    Dim ret As Long
    Dim lngProcessHandle As Long
    Dim varTaskID As Variant
    Dim shInfo As SHELLEXECUTEINFO
    Dim retval As Long

    'First try ShellExecute'
    With shInfo
        .cbSize = LenB(shInfo)
        .lpFile = stFile
        .nShow = lShowHow
        If bWaitForClose Then
            .fMask = SEE_MASK_FLAG_DDEWAIT + SEE_MASK_NOCLOSEPROCESS
        End If
        .lpVerb = "open"
    End With

    Call ShellExecuteEx(shInfo)
    lRet = shInfo.hInstApp

    If lRet > ERROR_SUCCESS And bWaitForClose = True Then
        lngProcessHandle = shInfo.hProcess

        Do
            retval = WaitForSingleObject(lngProcessHandle, 0)
            DoEvents
        Loop Until retval <> 258
        ret = CloseHandle(lngProcessHandle)
    End If

    fHandleFile = (lRet > 0)

exit_handler:
    Exit Function

err_Handler:
    RaiseError Err.Number, Err.Source, Err.Description
End Function

哇,非常感谢!很高兴我决定在这里寻求帮助,而不是自己尝试解决它。 - Kevin Dente

0

同样地,使用内置的Shell()函数:

Private Const INFINITE = &HFFFF
Private Const SYNCHRONIZE = &H100000
Private Const PROCESS_QUERY_INFORMATION = &H400

Private Declare Function CloseHandle Lib "kernel32" ( _
    ByVal hObject As Long) As Long

Private Declare Function GetExitCodeProcess Lib "kernel32" ( _
    ByVal hProcess As Long, _
    lpExitCode As Long) As Long

Private Declare Function OpenProcess Lib "kernel32" ( _
    ByVal dwDesiredAccess As Long, _
    ByVal bInheritHandle As Long, _
    ByVal dwProcessId As Long) As Long

Private Declare Function WaitForSingleObject Lib "kernel32" ( _
    ByVal hHandle As Long, _
    ByVal dwMilliseconds As Long) As Long

Private Function SyncShell( _
    ByVal PathName As String, _
    ByVal WindowStyle As VbAppWinStyle) As Long
    'Shell and wait.  Return exit code result, raise an
    'exception on any error.
    Dim lngPid As Long
    Dim lngHandle As Long
    Dim lngExitCode As Long

    lngPid = Shell(PathName, WindowStyle)
    If lngPid <> 0 Then
        lngHandle = OpenProcess(SYNCHRONIZE _
                             Or PROCESS_QUERY_INFORMATION, 0, lngPid)
        If lngHandle <> 0 Then
            WaitForSingleObject lngHandle, INFINITE
            If GetExitCodeProcess(lngHandle, lngExitCode) <> 0 Then
                SyncShell = lngExitCode
                CloseHandle lngHandle
            Else
                CloseHandle lngHandle
                Err.Raise &H8004AA00, "SyncShell", _
                          "Failed to retrieve exit code, error " _
                        & CStr(Err.LastDllError)
            End If
        Else
            Err.Raise &H8004AA01, "SyncShell", _
                      "Failed to open child process"
        End If
    Else
        Err.Raise &H8004AA02, "SyncShell", _
                  "Failed to Shell child process"
    End If
End Function

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接