Link to home
Start Free TrialLog in
Avatar of Alford Miller
Alford MillerFlag for United States of America

asked on

How do I Task Switch to another process in VBA if all I have is a Process Id?

I am writting a subroutine that needs to switch to a window thats running in another process.  I tried using "AppActivate" to switch windows but my program breaks when a user opens a document or a child window in the target process.  I tried using the "FindWindow" and "SetForgroundWindow" functions from user32 but they had similar problem.  Does anyone know of a way around this problem?
Avatar of zzzzzooc
zzzzzooc

Are you trying to set focus to a child window in a parent window (such as the edit box in notepad) or are you just trying to set focus to a parent window (such as notepad itself)? Also.. what do you mean by "breaks"?
For the sake of doing so.. here's an example (further down atleast).

The main problem with using ShowWindow/SetForegroundWindow/etc is the possibility of the window being a child of or related to another window. Tests with notepad and calc both yielded "hangs" (100% cpu usage) which you may be referring to with "break".

The below example shells notepad (minimized without focus.. shelled so I have a ProcID to work with) and uses ShowWindow & SetForegroundWindow on the owner of the window associated with the Process ID. Works fine for me.


Form1:
=========

Private Declare Function GetWindow Lib "User32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "User32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function ShowWindow Lib "User32" (ByVal hWnd As Long, ByVal nCmdShow As Long) As Long
Private Declare Function SetForegroundWindow Lib "User32" (ByVal hWnd As Long) As Long

Private Const GW_HWNDFIRST = 0
Private Const GW_HWNDNEXT = 2
Private Const GW_OWNER = 4

Private Const SW_SHOWNORMAL = 1
Private Sub Form_Load()
    Dim lHandle As Long, lProcIDFind As Long, lProcID As Long
    Dim lTimer As Long
    Call Me.Show
    'Open testing app..
    lProcIDFind = Shell("notepad.exe", vbMinimizedNoFocus)
    'Wait for it to open..
    Call Pause(3)
    lHandle = GetWindow(Me.hWnd, GW_HWNDFIRST)
    Do Until lHandle = 0
        Call GetWindowThreadProcessId(lHandle, lProcID)
        If lProcID = lProcIDFind Then
            'Found a match
            lHandle = GetWindow(lHandle, GW_OWNER)
            Call ShowWindow(lHandle, SW_SHOWNORMAL)
            Call SetForegroundWindow(lHandle)
            Exit Sub
        End If
        lHandle = GetWindow(lHandle, GW_HWNDNEXT)
        DoEvents
    Loop
End Sub
Private Sub Pause(ByVal iSecs As Integer)
    Dim lTimer As Long
    lTimer = Timer + iSecs
    Do Until Timer > lTimer
        DoEvents
    Loop
End Sub

As I read, when you try to use ShowWindow/SetForegroundWindow API's, your app hangs with 100% CPU usage ? If this is the problem, try this API:

Description from win32.hlp (msdn.microsoft.com):
SendNotifyMessage

The SendNotifyMessage function sends the specified message to a window. If the window was created by the calling thread, SendNotifyMessage calls the window procedure for the window and does not return until the window procedure has processed the message. If the window was created by a different thread, SendNotifyMessage passes the message to the window procedure and returns immediately; it does not wait for the window procedure to finish processing the message.


As a message, place WM_ACTIVATE or WM_APPACTIVATE.
Also you can try with SetActiveWindow API.
>> As I read, when you try to use ShowWindow/SetForegroundWindow API's, your app hangs with 100% CPU usage ?

It's probably just an issue with trying to SetForegroundWindow/ShowWindow->Maximized a child window who's parent is minimized. Seems like a logical issue also. :P
Avatar of Alford Miller

ASKER

Hello zzzzzooc, I need to reuse this code in a number of VB/VBA application at my site where sometime the process will be in a shell script or executable.  Is there any way to gather the window handle from a Proccess Id.  That would be esier because I can get the process Id from WMI.
ASKER CERTIFIED SOLUTION
Avatar of zzzzzooc
zzzzzooc

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial