Solved

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

Posted on 2004-04-13
14
4,336 Views
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?

0
Comment
Question by:kwkaan
14 Comments
 
LVL 28

Accepted Solution

by:
AzraSound earned 250 total points
ID: 10819783
0
 
LVL 2

Expert Comment

by:fadixp
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

Private Type LARGE_INTEGER
    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
    Else
        dblLo = Lo
    End If
   
    If Hi < 0 Then
        dblHi = 2 ^ 32 + Hi
    Else
        dblHi = Hi
    End If
    CLargeInt = dblLo + dblHi * 2 ^ 32
End Function

i hope this works .
0
 
LVL 3

Assisted Solution

by:santosh26676
santosh26676 earned 50 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
    endif
    do events
loop

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

Hope this helps!!!
0
 
LVL 2

Expert Comment

by:fadixp
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 =)
0
 
LVL 2

Expert Comment

by:fadixp
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 "
0
 
LVL 3

Expert Comment

by:santosh26676
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.
0
 
LVL 1

Assisted Solution

by:McMacdonalds
McMacdonalds earned 100 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
        DoEvents
    Loop

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!
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 2

Assisted Solution

by:fadixp
fadixp earned 50 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 .
0
 
LVL 3

Expert Comment

by:santosh26676
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.
0
 
LVL 26

Expert Comment

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

Assisted Solution

by:Ark
Ark earned 50 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"
0
 
LVL 1

Expert Comment

by:daniellyh
ID: 10829913
hi Ark,

lazy way worked! :=)

daniel
0
 

Expert Comment

by:JWEISBROD
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.
0
 

Author Comment

by:kwkaan
ID: 10838647
Thanks for all your help!
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Enums (shorthand for ‘enumerations’) are not often used by programmers but they can be quite valuable when they are.  What are they? An Enum is just a type of variable like a string or an Integer, but in this case one that you create that contains…
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
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…

757 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

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now