Results 1 to 26 of 26

Thread: [RESOLVED] How do I 'wait' for ShellExecute to finish

  1. #1

    Thread Starter
    Super Moderator FunkyDexter's Avatar
    Join Date
    Apr 2005
    Location
    An obscure body in the SK system. The inhabitants call it Earth
    Posts
    7,957

    Resolved [RESOLVED] How do I 'wait' for ShellExecute to finish

    I've often usd the Shell command and 'waited' for it to finish using this technique:-
    Waiting For Shell Code:
    1. Let lngPID = Shell(strExecutable, vbNormalFocus)
    2. Let lngPID = OpenProcess(SYNCHRONIZE, False, lngPID)
    3. Do
    4.    Let lngReturn = WaitForSingleObject(lngPID, 0)
    5.    DoEvents
    6. Loop While lngReturn <> 0
    ...but now I want to do something similar except I want to use the default program to open a file.

    Shell execute will use the default program for me:-
    Shell Execute Code:
    1. Call ShellExecute(hWnd, "open", mstrImagePath, "", "", 10)
    ...but it doesn't return a program or process ID I can use with the WaitForSingleObject call.

    Is there any way I can wait for ShellExecute?
    The best argument against democracy is a five minute conversation with the average voter - Winston Churchill

    Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd

  2. #2
    Fanatic Member
    Join Date
    May 2001
    Posts
    837

    Re: How do I 'wait' for ShellExecute to finish

    The docs say ShellExecute returns an application instance handle, and this page seems to be talking about converting that to a process ID. However, you say that Shell returns the process ID, but the page says Shell returns an instance handle.

    http://support.microsoft.com/kb/q242308
    The human brain cannot hold all of the knowledge that exists in this world, but it can hold pointers to that knowledge.

  3. #3

  4. #4

    Thread Starter
    Super Moderator FunkyDexter's Avatar
    Join Date
    Apr 2005
    Location
    An obscure body in the SK system. The inhabitants call it Earth
    Posts
    7,957

    Re: How do I 'wait' for ShellExecute to finish

    Thanks for the replies

    Rhino> That's the technique I use with Shell but it doesn't work for ShellExecute (or, at least, it aint working for me).

    DNA> In different explanations of the technique for wating for Shell I've seen the Shell return value referred to as a process ID, a program ID and a task ID. If I'm honest all I really know is that it returns something I can use with the OpenProcess command to get a handle to the object for use with the WaitForSingleObject command.

    The fact that they're both returning something that could be called an instance id implies that I could use exactly the same technique for ShellExecute as Shell but I've tried it and it doesn't work. The OpenProcess Command returns 0 and that, in turn, always returns a 0 from the WaitForSingleObject command (presumably there is no object with a handle of 0) so my loop never ends.

    I'm taking a closer look at DNA's link because it talks about getting the process ID and I think that might be what I'm after to feed into the OpenProcess Command but I'm not sure yet.

    Thanks so far


    edit>Rhino I slightly missread your post first time and didn't spot the use of GetExitCodeProcessed in place of WaitForSingleObject. Gave it a quick try but still no joy - the PID being equal to zero means that GetExitCodeProcessed returns zero and the loop drops straight out without the shelled app being closed.
    Last edited by FunkyDexter; Aug 2nd, 2007 at 08:40 AM.
    The best argument against democracy is a five minute conversation with the average voter - Winston Churchill

    Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd

  5. #5
    PowerPoster RhinoBull's Avatar
    Join Date
    Mar 2004
    Location
    New Amsterdam
    Posts
    24,132

    Re: How do I 'wait' for ShellExecute to finish

    Quote Originally Posted by FunkyDexter
    edit>Rhino I slightly missread your post first time and didn't spot the use of GetExitCodeProcessed in place of WaitForSingleObject. Gave it a quick try but still no joy - the PID being equal to zero means that GetExitCodeProcessed returns zero and the loop drops straight out without the shelled app being closed.
    You mean you cannot get process id knowing its window handle? Try this sample... or perhaps some other that you may find on that site.

  6. #6

    Thread Starter
    Super Moderator FunkyDexter's Avatar
    Join Date
    Apr 2005
    Location
    An obscure body in the SK system. The inhabitants call it Earth
    Posts
    7,957

    Re: How do I 'wait' for ShellExecute to finish

    To be honest, I'm not sure (this is pretty shaky territory for me) but I believe I'm trying to get a process handle from an instance handle. My thinking has gone thusly (with links to help spot where I'm going wrong):-

    According to the documentation ShellExecute returns me a handle to the instance of the application
    According to the documentation WaitForSingleObject (which I'm used to using) and GetExitProcess both need a handle to the process

    So I need to get the process handle from the instance, right? I can't find an example of doing this directly but, from the links you guys have given me, there would seem to be enough info to get the window handle from the instance (DNA's link) and then maybe use that to get the process handle, presumably by using the GetWindowThreadProcessID function.

    The trouble is, using the technique in DNA's link is returning me a window handle of zero. It's just not finding the window for the application.
    Last edited by FunkyDexter; Aug 2nd, 2007 at 09:56 AM.
    The best argument against democracy is a five minute conversation with the average voter - Winston Churchill

    Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd

  7. #7
    Fanatic Member
    Join Date
    Jul 2007
    Location
    Essex, UK.
    Posts
    579

    Re: How do I 'wait' for ShellExecute to finish

    I've had this problem loads of times and the solution is Karl Petersons Shell32.

    HTML Code:
    http://vb.mvps.org/samples/project.asp?id=Shell32
    I think you will find everything you want here.

  8. #8

    Thread Starter
    Super Moderator FunkyDexter's Avatar
    Join Date
    Apr 2005
    Location
    An obscure body in the SK system. The inhabitants call it Earth
    Posts
    7,957

    Re: How do I 'wait' for ShellExecute to finish

    Hi Steve, thanks for the link. Unfortunately it's the same technique used in DNA's link and it's not working for me. The problem is that Shell returns a process ID and ShellExecute returns an Instance handle. They're not the same thing so the same techniques just don't work.

    I have a doorstop of a reference guide sat here called Visual Basic Programmers Guide to the Win32 API that contains the following line of text: "Unfotunately, the ShellExecute function does not return the process handle or identifier, making it difficult to determine which process was actually launched by the function". That's it, no further explanation. No expansion on whether 'difficult' actually means 'impossible'. Still, on the plus side, the book's big enough to club myself to death with if I can't find a way of doing this soon

    Actually, I'm starting to think I'm going about this the wrong way. I'm starting to think what I should be doing is using the FindExecutable function to find the associated executable and then using that in the Shell command. I'm going to give that a go and post back how I get on.
    The best argument against democracy is a five minute conversation with the average voter - Winston Churchill

    Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd

  9. #9

  10. #10

    Thread Starter
    Super Moderator FunkyDexter's Avatar
    Join Date
    Apr 2005
    Location
    An obscure body in the SK system. The inhabitants call it Earth
    Posts
    7,957

    Re: How do I 'wait' for ShellExecute to finish

    Ooh, it's agettin' closer.

    Right, despite VB having one of it's ocassionally tantrums and crashing on me (and MS then asking me if I'd like to debug visual studio using... visual studio) I've got the FindExecuable working and can use it to shell out photoeditor (the default package for jpg's on my machine... I know, I know, stop pointing at me and sniggering), detect it closing and then carry on in my program.

    All I need to do now is get the right file into photoeditor. I reckon I've got 2 aproaches to this:
    1. I can find a way of telling photo editor to load the file - I'd probably need to use the packages api for this which kinda defeats the point of using the default package on the PC in the first place, or maybe I could create a pif on the fly, hmm, or...
    2 I can use shell execute to open the program, use findexecutable to get the shelling title and then use that to get the handle. This sounds a bit more reliable to me. Rhino, any chance of posting a link or some example code for that technique?

    Thanks all so far.
    The best argument against democracy is a five minute conversation with the average voter - Winston Churchill

    Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd

  11. #11

  12. #12
    Lively Member
    Join Date
    Jul 2005
    Location
    Grand Rapids, MI.
    Posts
    74

    Re: How do I 'wait' for ShellExecute to finish

    Can't you just use findwindow to see if the program window exists or not?

  13. #13

  14. #14

    Thread Starter
    Super Moderator FunkyDexter's Avatar
    Join Date
    Apr 2005
    Location
    An obscure body in the SK system. The inhabitants call it Earth
    Posts
    7,957

    Re: How do I 'wait' for ShellExecute to finish

    Hi Rhino. I think I'm missing something here. I'd worked out how FindExeutable worked and that'll give me the shelling title, but how can I use that to get the processID? I'm not in work today (hurrah ) and haven't got the reference book so forgive me if this is a dumb question.
    The best argument against democracy is a five minute conversation with the average voter - Winston Churchill

    Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd

  15. #15
    Member
    Join Date
    Jan 2006
    Posts
    39

    Re: How do I 'wait' for ShellExecute to finish

    Try this code...

    Code:
    Public Function LaunchApp(ByVal strApp As String, ByVal boolWaitForFinish As Boolean) As Long
    '***********************************************************************************
    'Purpose:   This routine used Windows API commands to launch another application.
    '           The first argument is path and name of the application to launch.
    '           The second argument is whether to wait for the application to close
    '           before returning control back to the calling routine.
    '***********************************************************************************
    Dim typProcess As PROCESS_INFORMATION
    Dim typStartUp As STARTUPINFO
    Dim lngReturnValue As Long
    Dim lngRemState As Long
    Dim strAppLocation As String
    Dim lngFolderDelimiterLocation As Long
    
        LaunchApp = 0
        
        ' Initialize the STARTUPINFO structure
        typStartUp.cb = Len(typStartUp)
        
        lngFolderDelimiterLocation = InStrRev(strApp, "\")
        If lngFolderDelimiterLocation >= 1 Then
            strAppLocation = Left(strApp, lngFolderDelimiterLocation - 1)
        End If
    
        ' Start the shelled application:
        lngReturnValue = CreateProcessA(vbNullString, strApp, 0, 0, 1, NORMAL_PRIORITY_CLASS, 0, strAppLocation, typStartUp, typProcess)
    
        ' Wait for the shelled application to finish
        If boolWaitForFinish Then
            lngRemState = frmMain.WindowState
            frmMain.WindowState = vbMinimized
            lngReturnValue = WaitForSingleObject(typProcess.hProcess, INFINITE)
            Call GetExitCodeProcess(typProcess.hProcess, lngReturnValue)
            Call CloseHandle(typProcess.hThread)
            Call CloseHandle(typProcess.hProcess)
            LaunchApp = lngReturnValue
            frmMain.WindowState = lngRemState
        End If
        
    End Function

  16. #16
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: How do I 'wait' for ShellExecute to finish

    Quote Originally Posted by FunkyDexter
    Hi Rhino. I think I'm missing something here. I'd worked out how FindExeutable worked and that'll give me the shelling title, but how can I use that to get the processID? I'm not in work today (hurrah ) and haven't got the reference book so forgive me if this is a dumb question.
    You have it backwards. Use FindExecutable to identify what the default application is to launch a given file. Once you do that, you can send that exe name plus the file name (in a single string) to Shell, which lets you wait until it's finished.

  17. #17
    PowerPoster RhinoBull's Avatar
    Join Date
    Mar 2004
    Location
    New Amsterdam
    Posts
    24,132

    Re: How do I 'wait' for ShellExecute to finish

    Quote Originally Posted by Ellis Dee
    You have it backwards. Use FindExecutable to identify what the default application is to launch a given file. Once you do that, you can send that exe name plus the file name (in a single string) to Shell, which lets you wait until it's finished.
    That's precisely correct. Thanks for clarifying that Ellis.

  18. #18

    Thread Starter
    Super Moderator FunkyDexter's Avatar
    Join Date
    Apr 2005
    Location
    An obscure body in the SK system. The inhabitants call it Earth
    Posts
    7,957

    Re: How do I 'wait' for ShellExecute to finish

    send that exe name plus the file to open in a single command to Shell
    I tried that last thing yesterday and it didn't seem to work. I'm assuming you just separate the exe and the filename with a space in the same way you pass parms to an exe, is that right?

    JJSomer, that technique works for starting an application but not for starting a file in it's default application. I can get the default application and I can start it, but how do you then get it to load up the file? Particularly given that I don't know what the default application is going to be at design time.
    The best argument against democracy is a five minute conversation with the average voter - Winston Churchill

    Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd

  19. #19
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: How do I 'wait' for ShellExecute to finish

    Quote Originally Posted by FunkyDexter
    I tried that last thing yesterday and it didn't seem to work. I'm assuming you just separate the exe and the filename with a space in the same way you pass parms to an exe, is that right?
    Yes, but I recall fighting with the OS to determine if/where quotes should be placed to handle path/filenames that have spaces in them.

    And I'm pretty sure the quote convention is different in the native Shell command compared to the ShellExecute API, though not positive.

  20. #20

    Thread Starter
    Super Moderator FunkyDexter's Avatar
    Join Date
    Apr 2005
    Location
    An obscure body in the SK system. The inhabitants call it Earth
    Posts
    7,957

    Re: How do I 'wait' for ShellExecute to finish

    Cool, I'll have a fiddle around with it on Monday. If I can just pass the filename in that's going to by far the easiest method. Thanks.
    The best argument against democracy is a five minute conversation with the average voter - Winston Churchill

    Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd

  21. #21
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: How do I 'wait' for ShellExecute to finish

    There's also the registry approach that I described in this post. It would seem that I was working with ShellExecute, but there is an example of the quotes issue I mentioned.

  22. #22

    Thread Starter
    Super Moderator FunkyDexter's Avatar
    Join Date
    Apr 2005
    Location
    An obscure body in the SK system. The inhabitants call it Earth
    Posts
    7,957

    Re: How do I 'wait' for ShellExecute to finish

    Ooohhh, I'm so close I can almost taste it.

    I did this in a quick test app:-
    test Code:
    1. Private Sub Form_Load()
    2.     Dim strText As String
    3.     strText = "C:\Program Files\Common Files\Microsoft Shared\PhotoEd\PHOTOED.EXE ""C:\PregemOMR\ImageArchive\31Jul2007\00000004.WS-L100LAPTOP\00000000.00000000.jpg"""
    4.     Shell strText
    5. End Sub
    The editor opened up with the file loaded

    but when I bring it into my main app it opens without the file loaded:-
    real ap Code:
    1. strExecutable = Space$(256)
    2. Call FindExecutable(Mid$(mstrImagePath, InStrRev(mstrImagePath, "\") + 1), Left$(mstrImagePath, InStrRev(mstrImagePath, "\") - 1), strExecutable)
    3. strSend = Trim(strExecutable) & """" & mstrImagePath & """"
    4. Let lngPID = Shell(strSend)

    I'm fairly sure I'm just doing something wrong with the quotes but strText in the test app displays exactly the same as strSend in my main app when I send them to the immediate window:-
    Code:
    C:\Program Files\Common Files\Microsoft Shared\PhotoEd\PHOTOED.EXE "C:\PregemOMR\ImageArchive\31Jul2007\00000004.WS-L100LAPTOP\00000000.00000000.jpg"
    C:\Program Files\Common Files\Microsoft Shared\PhotoEd\PHOTOED.EXE "C:\PregemOMR\ImageArchive\31Jul2007\00000004.WS-L100LAPTOP\00000000.00000000.jpg"
    Anyone see what I'm missing?
    Last edited by FunkyDexter; Aug 6th, 2007 at 05:07 AM.
    The best argument against democracy is a five minute conversation with the average voter - Winston Churchill

    Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd

  23. #23
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: How do I 'wait' for ShellExecute to finish

    Your debug results show the same text, but I can't figure out how this line...

    strSend = Trim(strExecutable) & """" & mstrImagePath & """"

    ...puts a space between the executable name and the document name. Are you sure there's a space there? Try this instead:

    strSend = Trim(strExecutable) & " """ & mstrImagePath & """"
    Last edited by Ellis Dee; Aug 6th, 2007 at 05:47 AM.

  24. #24

    Thread Starter
    Super Moderator FunkyDexter's Avatar
    Join Date
    Apr 2005
    Location
    An obscure body in the SK system. The inhabitants call it Earth
    Posts
    7,957

    Re: How do I 'wait' for ShellExecute to finish

    Actually, I think you might have hit on something there. In the immediate window it shows a space but I couldn't work out where it was coming from myself. I orignnaly had a space concatenated in when I built the string but I seemed to get a double space so I dropped it out. I bet it's not actually a space but something else that can't be represented. I'll investigate a bit further.

    edit> aha - it's a null.
    Last edited by FunkyDexter; Aug 6th, 2007 at 05:58 AM.
    The best argument against democracy is a five minute conversation with the average voter - Winston Churchill

    Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd

  25. #25

    Thread Starter
    Super Moderator FunkyDexter's Avatar
    Join Date
    Apr 2005
    Location
    An obscure body in the SK system. The inhabitants call it Earth
    Posts
    7,957

    Re: How do I 'wait' for ShellExecute to finish

    woohoo, working code at last:-
    declarations Code:
    1. Private Declare Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" (ByVal lpFile As String, ByVal lpDirectory As String, ByVal lpResult As String) As Long
    2. Private Const SYNCHRONIZE = &H100000
    3. Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
    4. Private Declare Function OpenProcess Lib "kernel32" (ByVal dwAccess As Long, ByVal fInherit As Integer, ByVal hObject As Long) As Long

    event code Code:
    1. Private Sub picSheetInner_DblClick()
    2.     Dim strExecutable As String
    3.     Dim lngPID As Long
    4.     Dim lngReturn As Long
    5.     Dim strSend As String
    6. On Error GoTo errHandler
    7.     strExecutable = Space$(256)
    8.     Call FindExecutable(Mid$(mstrImagePath, InStrRev(mstrImagePath, "\") + 1), Left$(mstrImagePath, InStrRev(mstrImagePath, "\") - 1), strExecutable)
    9.     strExecutable = Left$(strExecutable, InStr(strExecutable, vbNull) - 1)
    10.     strSend = strExecutable & " """ & mstrImagePath & """"
    11.     Let lngPID = Shell(strSend)
    12.     Let lngPID = OpenProcess(SYNCHRONIZE, False, lngPID)
    13.     Do
    14.         Let lngReturn = WaitForSingleObject(lngPID, 0)
    15.         DoEvents
    16.     Loop While lngReturn <> 0
    17.     Exit Sub
    18. errHandler:
    19.     Call hmferErrors.faimErrors(Err, "picSheetInner_DblClick", "frmPaper2", , gstrUserName, , App.EXEName)
    20.     End
    21. End Sub

    Thanks to all for your help, particularly Rhino, DNA and Ellis.
    The best argument against democracy is a five minute conversation with the average voter - Winston Churchill

    Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd

  26. #26

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width