Helpful Information
 
 
Category: Visual Basic Programming
Launching bat files serially in VB6?

I have a VB 6.0 app that routinely launches batch files that are located throughout a controlled development environment. I am currently launching these batch files using the Shell("cmd.exe /c " & "[batfile.bat]").

The problem is that by default, the Shell function runs other programs asynchronously, meaning that I can't run one bat file after another with a single button click.

Does anyone know of a way to launch multiple executables in serial through VB?

Thanks,
Steve

I don't quite understand what you mean by "in serial".

Please elaborate.

By "in serial," I mean one after another. "Synchronous" could describe it, too.

Thanks,
Steve

Do you mean that you want it to run & complete a program before it executes the next one?

Yes. I apologize for not being clear.

My goal is to run one batch file, have it complete, and then run another.

Thanks,
Steve

This is our function, hope I gave you all the constants and type defs.



Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessID As Long
dwThreadID As Long
End Type

Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type

Private Const STARTF_USESHOWWINDOW = &H1
Private Const NORMAL_PRIORITY_CLASS = &H20&
Global Const SW_HIDE = 0
Private Const INFINITE = -1&

Declare Function CreateProcessA Lib "kernel32" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Function winapi_shellAndWait(ByVal cmd As String)
Dim proc As PROCESS_INFORMATION
Dim Start As STARTUPINFO
Dim rc As Long

' Initialize the STARTUPINFO structure:
Start.cb = Len(Start)
Start.dwFlags = STARTF_USESHOWWINDOW
Start.wShowWindow = SW_HIDE

' Start the shelled application:
rc = CreateProcessA(vbNullString, cmd, 0&, 0&, 1&, NORMAL_PRIORITY_CLASS, 0&, vbNullString, Start, proc)

' Wait for the shelled application to finish:
rc = WaitForSingleObject(proc.hProcess, INFINITE)
Call GetExitCodeProcess(proc.hProcess, rc)
Call CloseHandle(proc.hThread)
Call CloseHandle(proc.hProcess)
winapi_shellAndWait = rc

End Function

Fantastic! Thank you.

At the risk of sounding like the newbie I am, what do I need to do to use your functions on my button click event?

Again, thank you for your help.

Originally posted by sstringer
Fantastic! Thank you.

At the risk of sounding like the newbie I am, what do I need to do to use your functions on my button click event?

Again, thank you for your help.

Just build the command ie c:\...\?.bat and pass it to the function

That's undoubtedly a very cool little function, although I found it crashed the IDE when I got it to run some installation .exes. The called program appeared not to run at all, but when I closed the locked IDE the called program then ran. I got other crashes using it to call dos commands that required user input, although often its possible to reformulate these so that they don't bother to prompt for anything.

The eventual solution I found was to create a new batch file and write all the shell commands to it before closing it and running it with a normal SHELL command.

Its definately not perfect - depending on the programs being run the first may not appear to finish before the second starts. (I suspect that this comes from having a two part program; one which decompresses files and the second to actually install them).

Another problem is that you need to have a known write-accessible path for the batch file.

Also, the VB code will continue to execute asynchronously, even if the commands in the batch run (more or less) synchronously. I got around this by moving whole of the rest of the setup routine to the batch file; the other way to do it is to pop up a message box explaining what is happening.

I just mention it because in the situations where the API method crashes the computer the simpler approach sometimes works.

I have a easy way!U can load the bat filepath into a string array.And in the event of command button click,u can put a static integer variable-i as the index of the array.When u click the button,u increase i and shell the bat file which path is the array(i)...

Iterating an index does, indeed, work. Thanks for the tip, cleverpig.

One note: Iterating an index, by itself, does not solve the problem of running the bat files sequentially if used with the Shell() command.

If you require your numerous bat files to run sequentially--that is, launching one only after the previous bat file completes it's job--there's an excellent article in the MS Knowledgebase that describes an efficient method to accomplish this in VB6:

http://support.microsoft.com/default.aspx?scid=kb;en-us;129796&Product=vb6

Cheers,
Steve

Yes,it's a way to asynchron the shell program by using process control!...Thx for your post!

I usually parse the files with a string and eval:
_______________________________________
Function runbatserial()

Dim filenamer, scriptit

For X = 1 To 3
filenamer = "c:\temp\" & Format(X, "000")
scriptit = "Shell (" & Chr(34) & "cmd.exe /c " & Chr(34) & " & " & Chr(34) & filenamer & ".bat" & Chr(34) & ")"
Eval (scriptit)
Next

End Function
_______________________________________


In this example, the files are numbered (generated on the fly by another event), but it can include prenamed files, ie "For each blah In (file1,file2,file3) Do blah blah blah"

I have been using this method to utilize my old bat files on a single machine in the frankenstein network without having to update all of the machines with the olddos commands. The newest security patches have systematically wiped out the functionality of scripts and bats I have been using for years. By numbering the bats and adding a shared folder set with a running script, I can trigger an event and output on my old machine, ie "If exist blah.bat Then Call blah.bat" ;)

??Wow?What's Eval??It sounds like regular expression!!..










privacy (GDPR)