|
-
Aug 2nd, 2007, 07:40 AM
#1
[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:
Let lngPID = Shell(strExecutable, vbNormalFocus)
Let lngPID = OpenProcess(SYNCHRONIZE, False, lngPID)
Do
Let lngReturn = WaitForSingleObject(lngPID, 0)
DoEvents
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:
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
-
Aug 2nd, 2007, 07:56 AM
#2
Fanatic Member
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.
-
Aug 2nd, 2007, 07:58 AM
#3
Re: How do I 'wait' for ShellExecute to finish
And after that you may try to use GetExitCodeProcess api to Determine when a Shelled App has Ended.
-
Aug 2nd, 2007, 08:31 AM
#4
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
-
Aug 2nd, 2007, 08:46 AM
#5
Re: How do I 'wait' for ShellExecute to finish
 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.
-
Aug 2nd, 2007, 09:52 AM
#6
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
-
Aug 2nd, 2007, 10:09 AM
#7
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.
-
Aug 2nd, 2007, 10:32 AM
#8
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
-
Aug 2nd, 2007, 10:45 AM
#9
Re: How do I 'wait' for ShellExecute to finish
If you know app's you shelling title then you can find it's handle and then find the process it's running in.
-
Aug 2nd, 2007, 11:18 AM
#10
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
-
Aug 2nd, 2007, 12:34 PM
#11
Re: How do I 'wait' for ShellExecute to finish
 Originally Posted by FunkyDexter
... any chance of posting a link or some example code for that technique?..
If you're interested in FindExecutable then here it is: Find Exe Associated with a Registered Extension.
Now you can Shell it and Wait...
-
Aug 2nd, 2007, 12:51 PM
#12
Lively Member
Re: How do I 'wait' for ShellExecute to finish
Can't you just use findwindow to see if the program window exists or not?
-
Aug 2nd, 2007, 01:06 PM
#13
Re: How do I 'wait' for ShellExecute to finish
The problem with FindWindow is that you need to know exact window's title.
So, if you don't know what it is then how are going to find it?
-
Aug 3rd, 2007, 10:48 AM
#14
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
-
Aug 3rd, 2007, 10:56 AM
#15
Member
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
-
Aug 3rd, 2007, 11:15 AM
#16
Re: How do I 'wait' for ShellExecute to finish
 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.
-
Aug 3rd, 2007, 11:18 AM
#17
Re: How do I 'wait' for ShellExecute to finish
 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.
-
Aug 3rd, 2007, 11:21 AM
#18
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
-
Aug 3rd, 2007, 11:26 AM
#19
Re: How do I 'wait' for ShellExecute to finish
 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.
-
Aug 3rd, 2007, 11:28 AM
#20
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
-
Aug 3rd, 2007, 11:31 AM
#21
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.
-
Aug 6th, 2007, 05:03 AM
#22
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:
Private Sub Form_Load()
Dim strText As String
strText = "C:\Program Files\Common Files\Microsoft Shared\PhotoEd\PHOTOED.EXE ""C:\PregemOMR\ImageArchive\31Jul2007\00000004.WS-L100LAPTOP\00000000.00000000.jpg"""
Shell strText
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:
strExecutable = Space$(256)
Call FindExecutable(Mid$(mstrImagePath, InStrRev(mstrImagePath, "\") + 1), Left$(mstrImagePath, InStrRev(mstrImagePath, "\") - 1), strExecutable)
strSend = Trim(strExecutable) & """" & mstrImagePath & """"
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
-
Aug 6th, 2007, 05:43 AM
#23
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.
-
Aug 6th, 2007, 05:50 AM
#24
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
-
Aug 6th, 2007, 06:13 AM
#25
Re: How do I 'wait' for ShellExecute to finish
woohoo, working code at last:-
declarations Code:
Private Declare Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" (ByVal lpFile As String, ByVal lpDirectory As String, ByVal lpResult As String) As Long
Private Const SYNCHRONIZE = &H100000
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwAccess As Long, ByVal fInherit As Integer, ByVal hObject As Long) As Long
event code Code:
Private Sub picSheetInner_DblClick()
Dim strExecutable As String
Dim lngPID As Long
Dim lngReturn As Long
Dim strSend As String
On Error GoTo errHandler
strExecutable = Space$(256)
Call FindExecutable(Mid$(mstrImagePath, InStrRev(mstrImagePath, "\") + 1), Left$(mstrImagePath, InStrRev(mstrImagePath, "\") - 1), strExecutable)
strExecutable = Left$(strExecutable, InStr(strExecutable, vbNull) - 1)
strSend = strExecutable & " """ & mstrImagePath & """"
Let lngPID = Shell(strSend)
Let lngPID = OpenProcess(SYNCHRONIZE, False, lngPID)
Do
Let lngReturn = WaitForSingleObject(lngPID, 0)
DoEvents
Loop While lngReturn <> 0
Exit Sub
errHandler:
Call hmferErrors.faimErrors(Err, "picSheetInner_DblClick", "frmPaper2", , gstrUserName, , App.EXEName)
End
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
-
Aug 6th, 2007, 07:15 AM
#26
Re: [RESOLVED] How do I 'wait' for ShellExecute to finish
Doesn't it makes you feel great!? Good job.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|