What's New
Q & A
Tip Jar
C# Helper...
Follow VBHelper on Twitter
MSDN Visual Basic Community
TitleStart another program using Shell and get its Window handle (hWnd)
KeywordsShell, start, execute, hWnd, Window handle
The Shell function starts a new program and returns the new process's task ID or zero if it cannot execute the program. This program then calls function InstanceToWnd to find the Window handle corresponding to the task ID. To prove the Window handle is correct, the program finishes by calling GetWindowText to read the new program's caption.

Function InstanceToWnd uses the GetWindow API function to loop through every window in the system. For each window, the function calls GetParent to get the window's parent window ID. If GetParent returns 0, the window has no parent so it is a top-level window. That is the kind of window that will hold the newly started program.

If the window is a top-level window, InstanceToWnd uses the GetWindowThreadProcessId API function to get the window's task ID. If this value matches the target ID, the function returns the hWnd of the window it found.

Aaron Bush discovered that on his system FindWindow was returning 0 on the first call. He found that the API function requires null parameters on the first call. After some experimentation, he found that it worked if he declared those parameters as optional. That's the version used here.

' Start the program.
Private Sub cmdRun_Click()
Dim task_id As Variant
Dim task_hWnd As Long
Dim buf As String
Dim buf_len As Long

    On Error GoTo ShellError

    Select Case cboShellStyle.Text
        Case "vbHide"
            task_id = Shell(txtProgram.Text, vbHide)
        Case "vbMaximizedFocus"
            task_id = Shell(txtProgram.Text, _
        Case "vbMinimizedFocus"
            task_id = Shell(txtProgram.Text, _
        Case "vbMinimizedNoFocus"
            task_id = Shell(txtProgram.Text, _
        Case "vbNormalFocus"
            task_id = Shell(txtProgram.Text, vbNormalFocus)
        Case "vbNormalNoFocus"
            task_id = Shell(txtProgram.Text, _
    End Select

    ' Display the task ID.
    lblTaskId.Caption = Hex$(task_id)

    ' Display the hWnd.
    task_hWnd = InstanceToWnd(task_id)
    lblHwnd.Caption = Hex$(task_hWnd)

    ' Display the new process's caption.
    buf = Space$(256)
    buf_len = GetWindowText(task_hWnd, buf, Len(buf))
    buf = Left$(buf, buf_len)
    lblCaption.Caption = buf

    Exit Sub

    MsgBox "Error Shelling file." & vbCrLf & _
        Err.Description, vbOKOnly Or vbExclamation, _
    Exit Sub
End Sub

' Return the window handle for an instance handle.
Private Function InstanceToWnd(ByVal target_pid As Long) As _
Dim test_hwnd As Long
Dim test_pid As Long
Dim test_thread_id As Long

    ' Get the first window handle.
    'test_hwnd = FindWindow(ByVal 0&, ByVal 0&)
    test_hwnd = FindWindow()

    ' 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, _

            If test_pid = target_pid Then
                ' This is the target.
                InstanceToWnd = test_hwnd
                Exit Do
            End If
        End If

        ' Examine the next window.
        test_hwnd = GetWindow(test_hwnd, GW_HWNDNEXT)
End Function
Note that in VBA with Access 2002, Shell() no longer returns a task handle as described in examples and the Access 2002 documentation, but rather returns True or False. Go figure.

See also:

Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.