Re: ShellExecuteEx and Information about remote application
- From: "JohnH" <JohnHarris34@xxxxxxxxx>
- Date: 23 Mar 2007 15:20:53 -0700
On Mar 23, 10:55 am, "JohnH" <JohnHarri...@xxxxxxxxx> wrote:
On Mar 23, 12:39 am, Sinna <news4sinna_NOS...@xxxxxxxxxx> wrote:
JohnH wrote:
One of the core functionalities my application will expose is
launching video files and keeping track of "viewing" statistics. It
needs to be able to:
1. Play/open the user-selected video file with system default player
2. Determine when video file (application) has been closed (when user
manually closes)
-My program CAN NOT hang while the video file plays, so I don't
believe WaitForSingleObject will work for me.
3. Close the video file remotely (source: my application)
The last two items, in other words, represent two ways in which the
video can be closed. My application needs to know if and when it was
closed remotely, or needs to be able to close it if the user specifies
that from within my program (Close Video command button.)
Number 1 led me to the ShellExecuteEx function, which I've implemented
successfully. I can open the file with the default player, and I've
got the processID for the new process.
As per Number 2 and 3...I found Randy Birch's
"GetWindowThreadProcessId: Obtain the hWnd of an App Started with
Shell" and have tried to retreive the hWnd of the new video window.
My code (i'm testing with a bitmap rather than a video file):
Dim rProcessID as Long
Dim ShellEI As SHELLEXECUTEINFO
With ShellEI
.cbSize = Len(ShellEI)
.fMask = SEE_MASK_NOCLOSEPROCESS Or SEE_MASK_FLAG_NO_UI
.hwnd = Me.hwnd
.lpVerb = "open"
.lpFile = "c:\test.bmp"
.lpParameters = vbNullChar
.lpDirectory = vbNullChar
.nShow = SW_SHOW
.hInstApp = 0
.lpIDList = 0
End With
Dim bSuccess As Boolean
bSuccess = ShellExecuteEx(ShellEI)
rProcessID = ShellEI.hProcess
If bSuccess Then
Debug.Print "ProcessID: " & rProcessID
Debug.Print "hWnd: " & GethWndFromProcessID(rProcessID)
Else
MsgBox "Error getting ProcessID for opened file.", vbCritical,
"Error"
End If
GethWndFromProcessID is Randy's function. So far during testing, it
is almost always failing (GethWndFromProcessID(rProcessID) is
returning 0) It has worked a -couple- of times, but I have no idea
why those times and not others.
Here's Randy's code for reference:
Private Function GethWndFromProcessID(hProcessIDToFind As Long) As
Long
Dim hWndDesktop As Long
Dim hWndChild As Long
Dim hWndChildProcessID As Long
On Local Error GoTo GethWndFromProcessID_Error
'get the handle to the desktop
hWndDesktop = GetDesktopWindow()
'get the first child under the desktop
hWndChild = GetWindow(hWndDesktop, GW_CHILD)
'hwndchild will = 0 when no more child windows are found
Do While hWndChild <> 0
'get the ThreadProcessID of the window
Call GetWindowThreadProcessId(hWndChild, hWndChildProcessID)
'if it matches the target, exit returning that value
If hWndChildProcessID = hProcessIDToFind Then
GethWndFromProcessID = hWndChild
Exit Do
End If
'not found, so get the next hwnd
hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)
Loop
Exit Function
GethWndFromProcessID_Error:
GethWndFromProcessID = 0
Exit Function
End Function
Can someone give me some direction on this? It seems that getting the
hWnd of the new process window is essential for my tasks 2 and 3.
Task 3 I don't think will be a problem, but beyond this current
pickle, I have really no idea how I'm going to tackle 2.
Thanks so much in advance.
John,
Some notes/directions for Task 2:
- You don't need the hWindow to keep track of the closing of the
launched application as the hProcess will do too.
- Take a look athttp://www.smsoft.ru/en/vbwait.htmtoreplace the
(blocking) WaitForSingleObject call with MsgWaitForMultipleObjects. Keep
in mind that the solution offered above has some restrictions:
* It does not allow launching multiple files at a time to keep track of.
* Your application will keep on running (eventually hidden) until the
launched application is closed.
Some notes/directions for Task 3:
- Here you do need the hWindow. I'm using a derived version of the
following source:http://vb-helper.com/howto_shell_get_hwnd.html. Look
for InstanceToWnd.
- When you have the hWindow, you can send the WM_CLOSE message to close
it friendly or WM_DESTROY to kill it. Take a look athttp://vb-helper.com/howto_kill_application.htmlandsearch for the line
containing the SendMessage call.
Hope it helps,
Sinna- Hide quoted text -
- Show quoted text -
Sinna,
Thank you for your response. It was informative and I liked the way
InstanceToWnd goes about getting the window handle, but unfortunately
the function is not working. For some reason, this line:
' Get the first window handle.
test_hwnd = FindWindow(ByVal 0&, ByVal 0&)
is returning 0. This of course means that the entire function fails,
since it can't even find the first handle. Do you have any idea what
could be causing the problem? Thanks again.- Hide quoted text -
- Show quoted text -
Well I retract that question. I substituted vbNullString for the
[ByVal 0&]s and now I'm getting back a valid handle, but the function
is still not returning my hWindow. Somehow though, the strangest
thing is happening. Let me try to explain:
-I'm passing the PID from ShellExecuteEx to the InstanceToWnd
function. So far so good.
-It cycles through all window handles and calculates their [test] PID
with GetWindowThreadProcessId
-I added (for debugging purposes) a GetWindowText call for each
hWindow pass (so with debugging I could recognize the window i'm
searching for)
Somehow, I'm getting essentially this as my result:
[Target window title]...... [target PID] <> [test PID]
In other words...somehow the PID calculated by
GetWindowThreadProcessId is not matching the value for
ShellExecuteEx's hProcess. Unless I'm making a strange error, I'm
fairly certain I've got matching hWindows. How is it possible that
the two APIs are returning different values for the PIDs? I am
somewhat new to working with API calls but I sort of know what's going
on, and I am stumped!
Here is the code I'm running:
Private Sub cmdOpenFile_Click()
Dim ShellEI As SHELLEXECUTEINFO
Dim pFSO As New FileSystemObject
Dim tFile As File
Dim strFileName As String
Dim hWnd As Long
Set tFile = pFSO.GetFile("c:\test.bmp")
strFileName = tFile.Name
With ShellEI
.cbSize = Len(ShellEI)
.fMask = SEE_MASK_NOCLOSEPROCESS Or SEE_MASK_FLAG_NO_UI
.hWnd = Me.hWnd
.lpVerb = "open"
.lpFile = tFile.Path
.lpParameters = vbNullChar
.lpDirectory = vbNullChar
.nShow = SW_SHOW
.hInstApp = 0
.lpIDList = 0
End With
Dim bSuccess As Boolean
bSuccess = ShellExecuteEx(ShellEI)
If bSuccess Then
rProcessID = ShellEI.hProcess
Sleep 2000
DoEvents
hWnd = InstanceToWnd(rProcessID)
MsgBox hWnd
'Call InitializeFileName(strFileName)
'Call EnumWindows(AddressOf EnumWindowProc, &H0)
CloseHandle (rProcessID)
'CloseHandle (rhWnd)
Else
MsgBox "File could not be found.", vbCritical, "Error"
End If
Set tFile = Nothing
End Sub
' Return the window handle for an instance handle.
Public Function InstanceToWnd(ByVal target_pid As Long) As Long
Dim test_hwnd As Long
Dim test_pid As Long
Dim test_thread_id As Long
Dim sTitle As String
' Get the first window handle.
'test_hwnd = FindWindow(ByVal 0&, ByVal 0&)
test_hwnd = FindWindow(vbNullString, vbNullString)
' Loop until we find the target or we run out of windows.
Do While test_hwnd <> 0
' See if this window has a parent. If not, it is a top-level
window.
If GetParent(test_hwnd) = 0 Then
' This is a top-level window. See if it has the target
instance handle.
test_thread_id = GetWindowThreadProcessId(test_hwnd,
test_pid)
sTitle = Space$(MAX_PATH)
Call GetWindowText(test_hwnd, sTitle, MAX_PATH)
Debug.Print TrimNull(sTitle) & " - " & test_pid & " ?=?
" & target_pid
If test_pid = target_pid Then
MsgBox "OH DEAR GOD THANK YOU, " & test_hwnd
InstanceToWnd = test_hwnd
Exit Do
End If
End If
' Examine the next window.
test_hwnd = GetWindow(test_hwnd, GW_HWNDNEXT)
Loop
End Function
.
- Follow-Ups:
- References:
- Prev by Date: Re: ShellExecuteEx and Information about remote application
- Next by Date: Re: ShellExecuteEx and Information about remote application
- Previous by thread: Re: ShellExecuteEx and Information about remote application
- Next by thread: Re: ShellExecuteEx and Information about remote application
- Index(es):