开发者

Shell process' standard output reading in Visual Basic 6

First, let me say that I'm not a Visual Basic 6 expert...

My need is to:

  • launch from a VB6 client code an exeternal .exe file
  • wait for the process to finish and - during its execution - read the messages coming from its standard output "on the fly" (so that I can print it on a text-filed widget or similars).

I'm wondering if it is even possible to do that in VB6...after a long search on the Internet I didn't come up with anything. Found a lot of examples of how to use the Shell function, but it seems to force me to read the stdout all at once when the process' executio开发者_高级运维n is over, but I want to poll the process for "fresh" messages as they become available.

Any code snippets/suggestions/references are really appreciated.

Thanks in advance!


Use CreatePipe() to create an anonymous pipe that you can pass to CreateProcess(). You can then read from this pipe as required (either using polling or overlapped/async I/O.

This should give you enough info to find a good example.


You can always use Exec method of WshShell to do the job.

I prefer to use a home-grown API based solution cExec.cls much simpler than Bob Riemersma's user control (but not as versatile).


You can also create a batch file that has all the commands that you need to run, and then from VB6 call the batch file by executing

 Shell "C:\YourPath\BatchFileName.bat > OutputFileName.txt"   'Overwrites OutputFilename.txt everytime

once you execute that, then open OutputFileName.txt and you will find all of the messages and output that was generated during the batch process. You can then read it in VB6 in a simple open "filename" for input as #1

You should also notice that if you use double GreaterThan symbols, the the output file will not be overwritten every time the batch runs. Instead, it will get appended with the new lines of output.

 Shell "C:\YourPath\BatchFileName.bat >> OutputFileName.txt"    'This will append to OutputFileName.txt


Here is the function you want. The exercise of declaring the API (CreatePipe, CreateProcessA, CloseHandle, etc), the types (PROCESS_INFORMATION, STARTUPINFO, SECURITY_ATTRIBUTES) the constants (STARTF_USESTDHANDLES, STARF_USESHOWWINDOW, etc) are left to the reader.

Public Function ExecuteCommand(ByVal CommandLine As String, Optional bShowWindow As Boolean = False, Optional sCurrentDir As String) As String
        Dim proc As PROCESS_INFORMATION     'Process info filled by CreateProcessA
        Dim ret As Long                     'long variable for get the return value of the
        'API functions
        Dim start As STARTUPINFO            'StartUp Info passed to the CreateProceeeA
        'function
        Dim sa As SECURITY_ATTRIBUTES       'Security Attributes passeed to the
        'CreateProcessA function
        Dim hReadPipe As Long               'Read Pipe handle created by CreatePipe
        Dim hWritePipe As Long              'Write Pite handle created by CreatePipe
        Dim lngBytesRead As Long            'Amount of byte read from the Read Pipe handle
        Dim strBuff As String * 256         'String buffer reading the Pipe


        'if the parameter is not empty update the CommandLine property


          If Len(CommandLine) > 0 Then
              mCommand = CommandLine
          End If

        'if the command line is empty then exit whit a error message
          If Len(mCommand) = 0 Then
              ApplicationEventLogError "Command Line empty in procedure ExecuteCommand of module modPipedOutput."
              Exit Function
          End If

        'Create the Pipe
          sa.nLength = Len(sa)
          sa.bInheritHandle = 1&
          sa.lpSecurityDescriptor = 0&
          ret = CreatePipe(hReadPipe, hWritePipe, sa, 0)

          If ret = 0 Then
            'If an error occur during the Pipe creation exit
              Debug.Print "CreatePipe failed. Error: " & Err.LastDllError & " (" & ReturnError(Err.LastDllError)
              Exit Function
          End If


        'Launch the command line application
          start.cb = Len(start)
          start.dwFlags = STARTF_USESTDHANDLES Or STARTF_USESHOWWINDOW

        'set the StdOutput and the StdError output to the same Write Pipe handle
          start.hStdOutput = hWritePipe
          start.hStdError = hWritePipe
        '    start.hStdInput = hInReadPipe
          If bShowWindow Then
              start.wShowWindow = SW_SHOWNORMAL
          Else
              start.wShowWindow = SW_HIDE
          End If

        'Execute the command
          If Len(sCurrentDir) = 0 Then
              ret& = CreateProcessA(0&, mCommand, sa, sa, 1&, _
                  NORMAL_PRIORITY_CLASS, 0&, vbNullString, start, proc)
          Else
              ret& = CreateProcessA(0&, mCommand, sa, sa, 1&, _
                  NORMAL_PRIORITY_CLASS, 0&, sCurrentDir, start, proc)
          End If

          If ret <> 1 Then
            'if the command is not found ....
              Debug.Print "File or command not found in procedure ExecuteCommand"
              Exit Function
          End If

        'Now We can ... must close the hWritePipe
          ret = CloseHandle(hWritePipe)
        '    ret = CloseHandle(hInReadPipe)
          mOutputs = vbNullString

        'Read the ReadPipe handle
          Do
              ret = ReadFile(hReadPipe, strBuff, 256, lngBytesRead, 0&)

              mOutputs = mOutputs & Left$(strBuff, lngBytesRead)
            'Send data to the object via ReceiveOutputs event

          Loop While ret <> 0

        'Close the opened handles
          Call CloseHandle(proc.hProcess)
          Call CloseHandle(proc.hThread)
          Call CloseHandle(hReadPipe)

        'Return the Outputs property with the entire DOS output
          ExecuteCommand = mOutputs

End Function
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜