Jump to content

Associating a PID to a win title?


Recommended Posts

Is there any way to use the WIN controls (WinWaitActive, for example) when we don't know the title but we do know the PID?

My script starts the process with Run, and that returns the PID. Now, how do I then use the window manipulation functions on it? Even WinGetTitle needs to know the title (which seems very strange to me). I would have thought there would be something like WinGetTitle ( PID ).

Open to suggestions. I'm looking for rock solid reliability here... and knowing what the title is on my machine isn't reliable in this case, as it can be different on someone else's.

Thanks.

- LD

Link to comment
Share on other sites

My whole problem is this:

I'm automating an ssh terminal session. I want it to happen in the background. When all is fine, it works great... but some times it "freezes". Actually, its not frozen, just hidden and awaiting user input. I can't send input to it using controlsend because it doesn't work with console apps... Send is required, but for that I need the window activated... hidden, but active... and to do that, I need the title. I have the PID, not the title.

Cheers.

LD

Edited by LondonNDIB
Link to comment
Share on other sites

  • Moderators

Alright... I need to add another paramter to my requirements.

"for windows that are HIDDEN"

:rolleyes:

Any chance yours can be adapted for that?

Cheers.

-LD

Any chance you tried to edit it? You see WinGetState()? ... Put = 0 after BitAnd(WinGetState(...

Example:

Func _WinGetByPID($iPID, $nArray = 1);0 will return 1 base array; leaving it 1 will return the first visible window it finds
    If IsString($iPID) Then $iPID = ProcessExists($iPID)
    Local $aWList = WinList(), $sHold
    For $iCC = 1 To $aWList[0][0]
        If WinGetProcess($aWList[$iCC][1]) = $iPID And _
            BitAND(WinGetState($aWList[$iCC][1]), 2) = 0 Then
            If $nArray Then Return $aWList[$iCC][0]
            $sHold &= $aWList[$iCC][0] & Chr(1)
        EndIf
    Next
    If $sHold Then Return StringSplit(StringTrimRight($sHold, 1), Chr(1))
    Return SetError(1, 0, 0)
EndFunc

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

No, I hadn't tried to edit it - just use it :rolleyes:

I'm still learning, and there are certain visual cues that still cause me to say "don't touch it! Just try it!". In this case, its "BitAND" that scared me :rambo:

I figured it was a limitation of WinList, but I just tested and saw that it returns hidden windows.

So thank you. But before you had the " = 0" in there, what was it doing? Just checking that it had ANY state? Doesn't every window have to have some state or another? Just curious.

Thanks for your help.

-LD

Link to comment
Share on other sites

  • Moderators

My whole problem is this:

I'm automating an ssh terminal session. I want it to happen in the background. When all is fine, it works great... but some times it "freezes". Actually, its not frozen, just hidden and awaiting user input. I can't send input to it using controlsend because it doesn't work with console apps... Send is required, but for that I need the window activated... hidden, but active... and to do that, I need the title. I have the PID, not the title.

Cheers.

LD

Personally, I would return the "handle"... less chance of a mistake.

Func _WinGetHandleByPID($iPID, $nArray = 1);0 will return 1 base array; leaving it 1 will return the first visible window it finds
    If IsString($iPID) Then $iPID = ProcessExists($iPID)
    Local $aWList = WinList(), $sHold
    For $iCC = 1 To $aWList[0][0]
        If WinGetProcess($aWList[$iCC][1]) = $iPID And _
            BitAND(WinGetState($aWList[$iCC][1]), 2) = 0 Then
            If $nArray Then Return $aWList[$iCC][1]
            $sHold &= $aWList[$iCC][1] & Chr(1)
        EndIf
    Next
    If $sHold Then Return StringSplit(StringTrimRight($sHold, 1), Chr(1))
    Return SetError(1, 0, 0)
EndFunc
As a result.

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

  • Moderators

No, I hadn't tried to edit it - just use it :rolleyes:

I'm still learning, and there are certain visual cues that still cause me to say "don't touch it! Just try it!". In this case, its "BitAND" that scared me :rambo:

I figured it was a limitation of WinList, but I just tested and saw that it returns hidden windows.

So thank you. But before you had the " = 0" in there, what was it doing? Just checking that it had ANY state? Doesn't every window have to have some state or another? Just curious.

Thanks for your help.

-LD

It was checking to make sure it was "visible".

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

Thanks a ton! The help file for BitAND is pretty cryptic for someone that actually needs the help file :rolleyes: But I found some references on Google and its starting to make sense to me.

I can work with what you've given me! Thanks again.

LD

Link to comment
Share on other sites

Hey, just another thought/query...

It seems to take some amount of time before WinList recognizes the window exists (or perhaps, it just takes that time for the "window" to exist, even though the "process" does.

just as a quick test, I did this

$test = Run ( "ssh.exe -i garbage test@test.com", "", @SW_HIDE);providing the garbage file makes this wait for user input
Sleep ( 2 )
$var = WinList ()
For $i = 1 to $var[0][0]
    If WinGetProcess ( $var[$i][0] ) = $test Then
        ConsoleWrite ( $var[$i][0] & " : " & $var[$i][1] & @LF )
    EndIf
Next
ProcessClose ( $test )
Exit

This works... however, if I take out that Sleep, nothing displays in the console. If I make it Sleep (1) then on my machine anyway, it sometimes works, sometimes doesn't. Which means on some slower machine, it may need 5ms? 10ms? 100ms? I hate guessing at what it might need.

I wonder if there is a better way to ensure the window is active. Unfortunately, WinActive, of course, requires knowing the Title and we're back in circles :rolleyes: ProcessExists doesn't help because the process DOES exist... its the window that doesn't (I guess).

Its not a big deal. I'm sure Sleep (250) would suffice for any machine and doesn't cause an undue delay for my purposes. I just try to avoid Sleeps wherever possible... and you seem chalk full of clever ideas!

LD

*EDIT* I suppose I could put the whole thing in a loop... and keep doing it until a title is returned. Like this:

$test = Run ( "ssh.exe -i garbage test@test.com", "", @SW_HIDE);providing the garbage file makes this wait for user input
While 1
$var = WinList ()
For $i = 1 to $var[0][0]
    If WinGetProcess ( $var[$i][0] ) = $test Then
        ConsoleWrite ( $var[$i][0] & " : " & $var[$i][1] & @LF )
                                ExitLoop 2
    EndIf
Next
Wend
ProcessClose ( $test )
Exit
Edited by LondonNDIB
Link to comment
Share on other sites

  • Moderators

Just FYI, Sleep(1) To Sleep(10) are the same thing from my understanding.

Guess we could test the theory...

For $iCC = 1 To 30
    $nTimer = TimerInit()
    For $xCC = 1 To 50
        Sleep($iCC)
    Next
    ConsoleWrite(@LF & 'Timer for Sleep(' & $iCC & ') : ' & TimerDiff($nTimer) / 1000)
Next
ConsoleWrite(@LF)
Looks to me it works in multiples of 10.

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

Helge made a cool UDF a while back. I can't remember the post I found it in, but I have included the code. This function doesn't find a title associated with the PID, but rather a HWND, which, IMO, is a far better solution. It has served me well in a lot of hard automations.

At any rate, it is worth a shot.

;===============================================================================
;
; Function Name:    _ProcessGetHWnd
; Description:      Returns the HWND(s) owned by the specified process (PID only !).
;
; Parameter(s):     $iPid       - the owner-PID.
;                   $iOption    - Optional : return/search methods :
;                       0 - returns the HWND for the first non-titleless window.
;                       1 - returns the HWND for the first found window (default).
;                       2 - returns all HWNDs for all matches.
;
;                   $sTitle     - Optional : the title to match (see notes).
;                   $iTimeout   - Optional : timeout in msec (see notes)
;
; Return Value(s):  On Success - returns the HWND (see below for method 2).
;                       $array[0][0] - number of HWNDs
;                       $array[x][0] - title
;                       $array[x][1] - HWND
;
;                   On Failure  - returns 0 and sets @error to 1.
;
; Note(s):          When a title is specified it will then only return the HWND to the titles
;                   matching that specific string. If no title is specified it will return as
;                   described by the option used.
;
;                   When using a timeout it's possible to use WinWaitDelay (Opt) to specify how
;                   often it should wait before attempting another time to get the HWND.
;
;
; Author(s):        Helge
;
;===============================================================================
Func _ProcessGetHWnd($iPid, $iOption = 1, $sTitle = "", $iTimeout = 2000)
    Local $aReturn[1][1] = [[0]], $aWin, $hTimer = TimerInit()
    
    While 1
        
        ; Get list of windows
        $aWin = WinList($sTitle)
        
        ; Searches thru all windows
        For $i = 1 To $aWin[0][0]
            
            ; Found a window owned by the given PID
            If $iPid = WinGetProcess($aWin[$i][1]) Then
                
                ; Option 0 or 1 used
                If $iOption = 1 OR ($iOption = 0 And $aWin[$i][0] <> "") Then
                    Return $aWin[$i][1]
                
                ; Option 2 is used
                ElseIf $iOption = 2 Then
                    ReDim $aReturn[UBound($aReturn) + 1][2]
                    $aReturn[0][0] += 1
                    $aReturn[$aReturn[0][0]][0] = $aWin[$i][0]
                    $aReturn[$aReturn[0][0]][1] = $aWin[$i][1]
                EndIf
            EndIf
        Next
        
        ; If option 2 is used and there was matches then the list is returned
        If $iOption = 2 And $aReturn[0][0] > 0 Then Return $aReturn
        
        ; If timed out then give up
        If TimerDiff($hTimer) > $iTimeout Then ExitLoop
        
        ; Waits before new attempt
        Sleep(Opt("WinWaitDelay"))
    WEnd
    
    
    ; No matches
    SetError(1)
    Return 0
EndFunc   ;==>_ProcessGetHWnd
Link to comment
Share on other sites

Just FYI, Sleep(1) To Sleep(10) are the same thing from my understanding.

Hmm... well, I ran it about 20 times with a value of 2 and it worked 100% of the time. Without a timer, it worked 0% of the time... with a value of 1 it worked about 80% of the time and failed 20% (4 out of 20) on my machine. So unless I fluked out and the 4 failures would have failed with (2) as well, I'd say there's a difference. Its possibly a limitation (for lack of a better word) of TimerInit that it goes in 10's? Possibly to avoid hogging cpu? Doesn't really matter though.

Thanks ktuimala... I'll take a look at that too.

LD

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...