Go Premium for a chance to win a PS4. Enter to Win


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

Posted on 2004-04-13
Medium Priority
Last Modified: 2007-12-19
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?

Question by:kwkaan
LVL 28

Accepted Solution

AzraSound earned 1000 total points
ID: 10819783

Expert Comment

ID: 10820248
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 .

Assisted Solution

santosh26676 earned 200 total points
ID: 10820328
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!!!
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.


Expert Comment

ID: 10820339
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 =)

Expert Comment

ID: 10820768
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 "

Expert Comment

ID: 10820899
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.

Assisted Solution

McMacdonalds earned 400 total points
ID: 10821315
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!

Assisted Solution

fadixp earned 200 total points
ID: 10822102
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 .

Expert Comment

ID: 10822305
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.
LVL 26

Expert Comment

ID: 10822707
I thinks  AzraSound already give you an answer, use waitforsingleobject, why brother to check the file?
LVL 28

Assisted Solution

Ark earned 200 total points
ID: 10829422
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"

Expert Comment

ID: 10829913
hi Ark,

lazy way worked! :=)


Expert Comment

ID: 10832712
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.

Author Comment

ID: 10838647
Thanks for all your help!

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Background What I'm presenting in this article is the result of 2 conditions in my work area: We have a SQL Server production environment but no development or test environment; andWe have an MS Access front end using tables in SQL Server but we a…
This article describes how to use a set of graphical playing cards to create a Draw Poker game in Excel or VB6.
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…
Suggested Courses

916 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question