Sign in to follow this  
Followers 0
joseLB

PID -> Window Handle (hWND) conversion

12 posts in this topic

#1 ·  Posted (edited)

Dears

I'm in a trouble. How to convert PID to window handle....

Wen I run a program ->Run ( "filename" )<-, I receive a PID as result. I only have the "filename" , no known title, class, etc., as this "filename" is passed as the only parameter thru $commandline.

Immediatedly I need to wait up to that program to be running... and later I need to use _ScreenCapture_CaptureWnd, where the window Handle is required.

So, from PID I need to go to hwnd... Any suggestion? I searched all help, but was unable to find a way.

Thanks in advance

Jose

Edited by joseLB

Share this post


Link to post
Share on other sites



Hi!

Use WinList() to get all the windows, you can then use WinGetProcess() to compare the windows to your pid you see which windows your pid owns

:)


Broken link? PM me and I'll send you the file!

Share this post


Link to post
Share on other sites

I seem to answer this question every other day...

Credit goes to the original author. Who I forget now... :)

Func _GetHwndFromPID($PID)
    $hWnd = 0
    $stPID = DllStructCreate("int")
    Do
        $winlist2 = WinList()
        For $i = 1 To $winlist2[0][0]
            If $winlist2[$i][0] <> "" Then
                DllCall("user32.dll", "int", "GetWindowThreadProcessId", "hwnd", $winlist2[$i][1], "ptr", DllStructGetPtr($stPID))
                If DllStructGetData($stPID, 1) = $PID Then
                    $hWnd = $winlist2[$i][1]
                    ExitLoop
                EndIf
            EndIf
        Next
        Sleep(100)
    Until $hWnd <> 0
    Return $hWnd
EndFunc ;==>_GetHwndFromPID

Cheers,

Brett

Share this post


Link to post
Share on other sites

Thanks Brett and monoceres, you did my day!

but how complex, uh!

I think that when you run a program, all that information is avaiable, without need for a loop. If yes, here is my suggestion:

RUN function (and all related ones), to have 1 more parameter: how will be the return. Default (0) is like today, just pid. Value 1 would return an array with the most possible parameters of the created process. Or, value 1= array with a group of parameters, 2=array with another group of parameters, etc.

Jose

Share this post


Link to post
Share on other sites

Hi,

Here is a snippet from my program that helps me automate Telnet sessions using PuTTY.

I would be releasing that app here, but for now, here is something useful from there:

#cs
    Busy wait on window having windowTitle and belonging to process with PID processPID.
    Time out timeoutSeconds in seconds
    Returns -1 if timed out
#ce

Func BusyWaitOnWindow($processPID, $windowTitle, $timeoutSeconds)

    Local $multiplierValue = 1000;
    Local $timeOut = $timeoutSeconds;
    
    Local $puttyHWND = -1;
    
    While ((0 <> $timeOut) AND (-1 == $puttyHWND))
  
   ; Find out the program by finding programs that have this title
    ; check if the PID of that window matches the PID of the spawned process
    ; if so, we have found our window

    ; NOTE: Winwait will return (prematurely) if a window with same title exists
        
        Winwait($windowTitle); If multiple instances of this script is spawned extremely fast (2 or more scripts per second), it gets hung here because the title changes to something unexpected (window title resembles log filename)
    ; I believe this has to do with the way ControlSendPlus.au3 modifies the global key state, thus effectively changing the sequence of commands sent versus what this script is supposed to generate
        
        Local $matchingWindows = WinList($windowTitle)
    
        If 0 == $matchingWindows[0][0] Then
    
            MsgBox(0, "Details", "NO matching window titles! Will continue busy wait for " & $timeOut & " more seconds..", 1)
            
      $timeOut -= 1;
      Sleep($multiplierValue);

            ContinueLoop
        EndIf
        
        For $dx = 1 to $matchingWindows[0][0]
    
            If WinGetProcess($matchingWindows[$dx][1]) == $processPID Then
    
                $puttyHWND = $matchingWindows[$dx][1];
                ExitLoop
            EndIf
        Next

  WEnd
  
  If NOT IsHWnd($puttyHWND) Then
  
        MsgBox(4096, "", $PuttyHWND & " - It's not a HWND")
      $puttyHWND = -1;
    EndIf
  
  return $puttyHWND;

EndFunc

Share this post


Link to post
Share on other sites

I seem to answer this question every other day...

Credit goes to the original author. Who I forget now... :D

Func _GetHwndFromPID($PID)
    $hWnd = 0
    $stPID = DllStructCreate("int")
    Do
        $winlist2 = WinList()
        For $i = 1 To $winlist2[0][0]
            If $winlist2[$i][0] <> "" Then
                DllCall("user32.dll", "int", "GetWindowThreadProcessId", "hwnd", $winlist2[$i][1], "ptr", DllStructGetPtr($stPID))
                If DllStructGetData($stPID, 1) = $PID Then
                    $hWnd = $winlist2[$i][1]
                    ExitLoop
                EndIf
            EndIf
        Next
        Sleep(100)
    Until $hWnd <> 0
    Return $hWnd
EndFunc ;==>_GetHwndFromPID

Cheers,

Brett

I vote for a function like this or this functionality to be added to one of the current autoit functions... or enable the other functions to work off of PID as well as the hwnd for finding windows.

It makes sense to be able to simply run $pid = run(bla app) and then winactivate($pid)

Share this post


Link to post
Share on other sites

#Include <Array.au3>
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global $Data = _WinAPI_EnumProcessWindows(ProcessExists('SciTE.exe'))

If IsArray($Data) Then
    _ArrayDisplay($Data, '_WinAPI_EnumProcessWindows')
EndIf

WinAPIEx.au3

Share this post


Link to post
Share on other sites

#Include <Array.au3>
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global $Data = _WinAPI_EnumProcessWindows(ProcessExists('SciTE.exe'))

If IsArray($Data) Then
    _ArrayDisplay($Data, '_WinAPI_EnumProcessWindows')
EndIf

WinAPIEx.au3

Will this method work for child process windows? So in your example, If SciTE.exe spawned a child process that also has windows...would this method enum the windows from the child process? I'm thinking that it wouldn't and I would have to create a loop to enum the child process windows, but I haven't had a chance to play with it yet. Note that I'm talking about a child process and not a child window.

Share this post


Link to post
Share on other sites

I spent a lot of time testing this. I have a command line tool that when executed, opens a command line window. I cannot get the handle using the pid for my executable. I can get the pid with the WinGetHandle function. I was hoping I could get the handle using the pid, this way I could run multiple instances of the executable and control the one I want specifically. For now, I launch it using Run, then get the handle using the title, then rename the title to something completely different.

_WinAPI_EnumProcessWindows definitely does not work for a non-window process. That being said, I don't think it would work for a child process either. :mellow:

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0