Improve company productivity with a Business Account.Sign Up

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

How can I wait the shell command to finish before execute to next statement?

MY VB program will execute another .exe file, using ShellExecute command.  The .exe file will generate another large file which will spend around 1 hour.  I've tried to get the return value of ShellExecute:

Private Declare Function ShellExecute Lib "shell32.dll" Alias _
      "ShellExecuteA" (ByVal hwnd As Long, ByVal lpszOp As _
      String, ByVal lpszFile As String, ByVal lpszParams As String, _
      ByVal lpszDir As String, ByVal FsShowCmd As Long) As Long

Dim StartDoc as long
StartDoc = ShellExecute(Scr_hDC, "Open", "c:\IMR\abc.exe ", "parameter", "", SW_SHOWMAXIMIZED)
MsgBox "Complete"

abc.exe will spend 1 hr to finish and wil create another .txt file.  I want to check if the .txt can be generated successfully before alert "Complete".  However, the above "Complete" message will popup immediately instead of waiting for abc.exe really complete.

Any alternatives to solve this problem?

5 Solutions
well if you know exactly the file size you are executing you can do some crazy solution like you find out the disk space before you use the shell and use a timer for example to check the disk space while extracting .
and the message wont pop up until the disk space = diskspace + the file size .
this is the code for example to see how you can do it:
add the following code to a module, and use

Msgbox GetDiskSpace("C:")
to know the disk space of drive c

    lowpart As Long
    highpart As Long
End Type
Private Declare Function GetDiskFreeSpaceEx Lib "kernel32" Alias "GetDiskFreeSpaceExA" (ByVal lpRootPathName As String, lpFreeBytesAvailableToCaller As LARGE_INTEGER, lpTotalNumberOfBytes As LARGE_INTEGER, lpTotalNumberOfFreeBytes As LARGE_INTEGER) As Long

Public Function GetDiskSpace(sDrive As String) As String
    Dim lResult As Long
    Dim liAvailable As LARGE_INTEGER
    Dim liTotal As LARGE_INTEGER
    Dim liFree As LARGE_INTEGER
    Dim dblAvailable As Double
    Dim dblTotal As Double
    Dim dblFree As Double
    If Right(sDrive, 1) <> "" Then sDrive = sDrive & ""
    'Determine the Available Space, Total Size and Free Space of a drive
    lResult = GetDiskFreeSpaceEx(sDrive, liAvailable, liTotal, liFree)
    'Convert the return values from LARGE_INTEGER to doubles
    dblAvailable = CLargeInt(liAvailable.lowpart, liAvailable.highpart)
    dblTotal = CLargeInt(liTotal.lowpart, liTotal.highpart)
    dblFree = CLargeInt(liFree.lowpart, liFree.highpart)
    'Display the results
    GetDiskSpace = "Available Space on " & sDrive & ":  " & dblAvailable & " bytes (" & _
                Format(dblAvailable / 1024 ^ 3, "0.00") & " G) " & vbCr & _
                "Total Space on " & sDrive & ":      " & dblTotal & " bytes (" & _
                Format(dblTotal / 1024 ^ 3, "0.00") & " G) " & vbCr & _
                "Free Space on " & sDrive & ":       " & dblFree & " bytes (" & _
                Format(dblFree / 1024 ^ 3, "0.00") & " G) "
End Function

Private Function CLargeInt(Lo As Long, Hi As Long) As Double
    'This function converts the LARGE_INTEGER data type to a double
    Dim dblLo As Double, dblHi As Double
    If Lo < 0 Then
        dblLo = 2 ^ 32 + Lo
        dblLo = Lo
    End If
    If Hi < 0 Then
        dblHi = 2 ^ 32 + Hi
        dblHi = Hi
    End If
    CLargeInt = dblLo + dblHi * 2 ^ 32
End Function

i hope this works .
Why don't you just run a loop to check if the file is created. This loop is to be just after the shell().

do while true
    if fileexist() then
       msgbox "complete"
       exit do
    do events

The above loop will exit when the file is created else it will continue to loop.

Hope this helps!!!
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

i found a better way , to check the file size it self .
because disk space may not be correct for example if you are downloading some thing then it will be totally wrong the message will appear before the extraction is completed , so this is the code to check the file it self if its totally extracted or not .

Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" _
    (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, _
     ByVal dwShareMode As Long, lpSecurityAttributes As Long, _
     ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, _
     ByVal hTemplateFile As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" _
    (ByVal hObject As Long) As Long
Private Declare Function GetFileSize Lib "kernel32" _
    (ByVal hFile As Long, lpFileSizeHigh As Long) As Long

Private Const OPEN_EXISTING = 3
Private Const FILE_SHARE_READ = &H1
Private Const GENERIC_READ = &H80000000

Private Sub Form_Load()
Dim fhandle As Long
Dim whatdoesthisdo As Long

fhandle = CreateFile("C:\yourfile.exe", GENERIC_READ, FILE_SHARE_READ, _
                    ByVal 0&, OPEN_EXISTING, 0, 0)

MsgBox GetFileSize(fhandle, whatdoesthisdo)

Call CloseHandle(fhandle)
End Sub

use it in timer so it keeps checking untill its totally extracted .
hope you like it other wise i will find a better way =)
nice comment from santosh but i think it wont work if the file is huge and its extracting from zip or rar or even self extract from winzip
because its normally create the file then keep pressing f5 while its extracting you will find out the file is getting bigger each time you press , which mean the file will be created in the first second but the extracting still taking time to be completed .
" its my point of view "
As per the question, only one .txt file will be created after the shell command is over. So i believe my solution will work.

fadixp, I agree with your comment. I have some other solution for the scenario you specified which is not relevant to this question.
1) It's actually not that complicated. You just need to declare the FindWindow API and then create a loop, something like this:

Do While FindWindow(vbNullString, "c:\winnt\system32\cmd.exe") <> 0

The program will run the loop as long as it finds the "shell window"

2) The other option is to create a loop which checks the file size (which the EXE file generates) every i.e. 2 seconds (using the Sleep API call i.e.). Once the file size is the same between the checks you break the loop...

Hope this gives you an idea!
i agree with mcMacdonalds same idea but different way "about checking the size "
@santosh txt file takes an hour to be created as the user said . which means it will take time for the extraction , file will be created but the size still not completed in your solution , i respect your idea santosh =)
still we are all here to solve problems .
Other solution to this could be to create a .txt file with some status by abc.exe just before completing the execution. This file could be checked for existance and can come to a conclusion whether abc.exe has finished executing.
I thinks  AzraSound already give you an answer, use waitforsingleobject, why brother to check the file?
For lazy programmers:

Dim oShell As Object
Set oShell = CreateObject("WScript.Shell")
oShell.Run "c:\IMR\abc.exe parameter", SW_SHOWMAXIMIZED, True
Set oShell = Nothing
MsgBox "Complete"
hi Ark,

lazy way worked! :=)

Why not have the second program create a one byte file with some odd and therefore unique name and extension when it is done creating the main file. Then, you can put in a loop looking for this new file and when it is found, you know the main file creation job is done.
kwkaanAuthor Commented:
Thanks for all your help!
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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

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