Jump to content

Get PIDs of multiple instances of same (non-AutoIt) application?


Recommended Posts

I have a script that runs another application (vDos.exe), and the same script can be run multiple times to open other instances of the same vDos.exe application.

When I open a new instance of vDos.exe, I want to make sure that its window does not open directly over a previous instance, so I want to get the window positions of previous instances. Has someone written a method of finding the PIDs of all instances of the same executable, so that I can get the window positions of each of them?

I've found various application counters in the forum, but they seem to be designed to find multiple instances of the script, not of another application.

Many thanks for any pointers.

 

Link to post
Share on other sites
2 hours ago, emendelson said:

Has someone written a method of finding the PIDs of all instances of the same executable, so that I can get the window positions of each of them?

Lookup the ProcessList() function in the help file.

Edited by TheXman
Link to post
Share on other sites
8 hours ago, emendelson said:

I want to make sure that its window does not open directly over a previous instance, so I want to get the window positions of previous instances

Well PIDs will not tell you what are the position of the windows.  I believe the best way would be to use WinList() with the title special definition [CLASS:vdos class here].  Within the array obtained you can loop thru getting position of each window through WinGetPos.

Link to post
Share on other sites
Posted (edited)

Again, thanks to Nine, I think I've mostly solved this problem, but I have more question.

I created a function that loops through the windows of the existing instances of vDos.exe, and, if the newly-created instance matches the location of one of the earlier ones, sets the new window to be moved 30 pixels down and to the right. This causes a potential problem where the move down and to the right could put the new window into the position of an instances tested EARLIER in the loop.

So I tried putting the loop inside another loop that performs the testing loop multiple times (the same number of times as there are instances).  I think there must be a better or more efficient way to do this, though it seems to work reasonably well. Here is the code (with the _GetHwndFromPID() function taken from some excellent code posted in the forum years ago):

$running = ProcessExists("vdos.exe")
$PID = Run("vDos.exe") ; this is simplified from the actual code
If $running <> 0 Then MoveNew($PID)

Func MoveNew($PID)
    Local $hWnd, $w, $vList, $oldWnd
    Local $tmpWinPos, $tmpXpos, $tmpYpos, $finalXpos, $finalYpos
    
    $hWnd = _GetHwndFromPID($PID)
    WinWait($hWnd)
    $w = WinGetPos($hWnd)
    $xNew = $w[0]
    $yNew = $w[1]
    $finalXpos = $xNew
    $finalYpos = $yNew

    $vList = WinList("[CLASS:vDos]", "")
    For $n = 1 To UBound($vList) - 1
        For $i = 1 To UBound($vList) - 1
            If $i <> $hWnd Then  ;; don't test new instance against itself
                $oldWnd = $vList[$i][1]
                $tmpWinPos = WinGetPos($oldWnd)
                $tmpXpos = $tmpWinPos[0]
                $tmpYpos = $tmpWinPos[1]
                If (($tmpXpos = $finalXpos) Or ($tmpYpos = $finalYpos)) Then
                    $finalXpos = $finalXpos + 30
                    $finalYpos = $finalYpos + 30
                EndIf
            EndIf
        Next
    Next
    
    If (($xNew <> $finalXpos) Or ($yNew <> $finalYpos)) Then
        WinMove($hWnd, "", $finalXpos, $finalYpos)
    EndIf
EndFunc   ;==>MoveNew

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

 

 

Edited by emendelson
Fix code
Link to post
Share on other sites

Here the way I would do it.  That will ensure that no other window share the same position :

#include <Constants.au3>

Const $sClass = "[CLASS:Notepad]"
Local $PID = Run("Notepad")
Sleep(1000)
MoveNew($PID, $sClass)

Func MoveNew($PID, $sClass)
  Local $hCurrent = _GetHwndFromPID($PID, $sClass)
  If Not $hCurrent Then Exit MsgBox($MB_SYSTEMMODAL, "Error", "Unable to find current window")
  Local $aCurrent = WinGetPos($hCurrent)
  Local $aPos, $xMax = -1, $yMax = -1, $bFound = False
  Local $aList = WinList($sClass)
  For $i = 1 To $aList[0][0]
    If WinGetProcess($aList[$i][1]) = $PID Then ContinueLoop
    $aPos = WinGetPos($aList[$i][1])
    $xMax = $aPos[0] > $xMax ? $aPos[0] : $xMax
    $yMax = $aPos[1] > $yMax ? $aPos[1] : $yMax
    If $aCurrent[0] = $aPos[0] And $aCurrent[1] = $aPos[1] Then $bFound = True
  Next
  If $bFound Then WinMove($hCurrent, "", $xMax + 30, $yMax + 30)
EndFunc   ;==>MoveNew

Func _GetHwndFromPID($PID, $sClass)
  Local $aList = WinList($sClass)
  For $i = 1 To $aList[0][0]
    If WinGetProcess($aList[$i][1]) = $PID Then Return $aList[$i][1]
  Next
  Return 0
EndFunc   ;==>_GetHwndFromPID

That is supposing that users cannot change the position of a window.

Link to post
Share on other sites
Posted (edited)

Thank you for doing this! It seems to work perfectly when I tested it with vDos, but I don't understand what it means to say that "users cannot change the position of a window." When I tested your code, I sometimes moved the vDos window after launching it, and the next time I ran your code, the next vDos window appeared correctly 30 pixels to the right and 30 pixels below the previous one. I think I'm missing something important. Could you let me know more? (I know I'm asking for more after you've already given a lot.)

By the way, I originally wanted to use some method of calculating a maximum setting, but could not figure out how to do. I'm very grateful to have your example!

 

Edited by emendelson
Link to post
Share on other sites

If a user changes the position of a window (by dragging the title bar for example) and puts the window at the very bottom of the screen, the next window could be partly hidden because it would exceed the screen size.  It is not important but just want to let you know.

Link to post
Share on other sites

Ah - I see. Thank you. I suppose I could add some code that tested the current screen dimensions, and changed the window position if the next window would be in a completely inconvenient location. I hadn't thought of that, but it should be fairly easy. Thank you again!

Link to post
Share on other sites

You are welcome.

Yes, it is not a big problem and users can understand that they need to change position to make it more appropriate anyway.

 

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
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By CarlD
      Tsk is a CLI task lister that includes PIDs, process names, hWnds and window titles. The listing can be limited by supplying a substring of the process name or window title. Here is the usage:
      TSK.exe: TaSK Lister|Switcher [CLD rev.2021-03-27] Usage ----- TSK [sub$tring] List running tasks: all tasks [tasks with process_names|window_titles matching sub$tring] TSK /SW window_title(sub$tring)|PID|hWnd Switch focus to window with matching window_title(sub$tring)|PID|hWnd TSK /?|/H Show this Help And here's the code (compiled executable is HERE):
      #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Outfile_type=exe #AutoIt3Wrapper_Outfile=tsk.exe #AutoIt3Wrapper_UseUpx=y #AutoIt3Wrapper_Change2CUI=y #AutoIt3Wrapper_Run_Au3Stripper=y #AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 4 -w 5 -w 6 -d #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** ; ; CLD rev.2021-03-27 AutoItSetOption("WinTitleMatchMode", -2) Global $sSub = "", $sOut = "", $iC = 0, $aW, $bSwW = 0 Global $aWinList = WinList() If $CmdLine[0] > 0 Then If StringInStr($CmdLineRaw, "/?") Or StringInStr($CmdLineRaw, "/H") Then Exit _ShowHelp() ElseIf StringInStr($CmdLineRaw, "/sw") Then $bSwW = 1 Else $sSub = $CmdLine[1] EndIf EndIf If $CmdLine[0] > 1 Then For $i = 1 To 2 If $CmdLine[$i] = "/sw" Then ContinueLoop Else $sSub = $CmdLine[$i] EndIf Next EndIf If $bSwW = 1 Then If StringInStr($sSub, "0x") = 1 Then WinActivate(HWnd($sSub)) ElseIf StringIsDigit($sSub) Then WinActivate(_GetHwndFromPID($sSub)) Else $aW = WinList($sSub) If $aW[0][0] > 1 Then WinActivate($aW[2][1]) Else ConsoleWrite("No matching window title for """ & $sSub & """" & @CRLF) EndIf EndIf Exit EndIf Global $aP = ProcessList() Global $aW[1 + $aP[0][0]][1 + $aP[0][0]] For $j = 1 To $aP[0][0] If String($aP[$j][1]) <> "" Then $aW[$j][0] = _GetHwndFromPID($aP[$j][1]) $aW[$j][1] = WinGetTitle($aW[$j][0]) Else $aW[$j][0] = "" $aW[$j][1] = "" EndIf Next Global $iX = 10 For $k = 1 To $aP[0][0] If $sSub Then If StringInStr($aP[$k][0], $sSub) = 0 Then If $aP[$k][1] Then If StringInStr($aW[$k][1], $sSub) = 0 Then ContinueLoop Else ContinueLoop EndIf EndIf EndIf If StringLen($aP[$k][0]) >= $iX Then $iX = 2 + StringLen($aP[$k][0]) Next Global $sHdr = StringFormat("%7s", "PID") & " " & StringFormat("%-" & $iX & "s", "Process") & StringFormat("%-12s", "hWnd") & "Window Title" & @CRLF For $i = 1 To $aP[0][0] If $sSub Then If StringInStr($aP[$i][0], $sSub) = 0 Then If $aW[$i][0] Then If StringInStr($aW[$i][1], $sSub) = 0 Then ContinueLoop Else ContinueLoop EndIf EndIf EndIf $iC += 1 $sOut &= StringFormat("%7s", $aP[$i][1]) & " " & StringFormat("%-" & $iX & "s", $aP[$i][0]) & StringFormat("%-12s", $aW[$i][0]) & $aW[$i][1] & @CRLF Next If $iC > 0 Then If $CmdLine[0] = 0 Then $sOut &= @CRLF & "Command " & StringUpper(StringTrimRight(@ScriptName, 4)) & StringLower(StringRight(@ScriptName, 4)) & " /? for usage" & @CRLF ConsoleWrite($sHdr & $sOut) Else ConsoleWrite("No matches" & @CRLF) EndIf Exit Func _GetHwndFromPID($PID) Local $hWnd = 0 Local $stPID = DllStructCreate("int") For $i = 1 To $aWinList[0][0] If $aWinList[$i][0] <> "" Then DllCall("user32.dll", "int", "GetWindowThreadProcessId", "hwnd", $aWinList[$i][1], "ptr", DllStructGetPtr($stPID)) If DllStructGetData($stPID, 1) = $PID Then Return $aWinList[$i][1] EndIf Next Return $hWnd EndFunc ;==>_GetHwndFromPID Func _ShowHelp() Local $sTxt = StringUpper(StringTrimRight(@ScriptName, 4)) & StringLower(StringRight(@ScriptName, 4)) & ": TaSK Lister|Switcher [CLD rev.2021-03-27]" & @CRLF & @CRLF & "Usage" & @CRLF & "-----" & @CRLF & StringUpper(StringTrimRight(@ScriptName, 4)) & " [sub$tring]" & @CRLF & " List running tasks: all tasks [tasks with process_names|window_titles matching sub$tring]" & @CRLF & StringUpper(StringTrimRight(@ScriptName, 4)) & " /SW window_title(sub$tring)|PID|hWnd" & @CRLF & " Switch focus to window with matching window_title(sub$tring)|PID|hWnd" & @CRLF & StringUpper(StringTrimRight(@ScriptName, 4)) & " /?|/H" & @CRLF & " Show this Help" ConsoleWrite($sTxt & @CRLF) EndFunc ;==>_ShowHelp  
    • By gspino
      I hoping some of you young people can help an old man get off the nickel...  I have a small project I'd like to complete before I retire.  My problem is that on a terminal server environment I need to be able to detect the PID of a process by 'process name' AND 'process owner' so I can kill that specific process and not affect others who may be running the same process in another session.    I can seem to do one or the other but not both.  Can anyone please point me in the right direction?  Thanks very much in advance. -Glen
    • By TryWare90Days
      I'm trying to kill a malware process, that I can't remove with my www.sophus.com/hom antivirus.

      The malware is known as coinminer,config and my Sophus only creates popups of blocking the malware.

      I know that the malware is constantly launching a svchost *32.exe processes, where the svchost.exe processes are from my Windows 7 operating system.
      I have with no luck tried to do this:
      Global $_bStatus = False
      While $_bStatus = False
                 Global $_iPid
                 Global $_sActiveTitleNew = "svchost *32.exe"
                 $_iPid = WinGetProcess($_sActiveTitleNew)
                 If $_iPid <> -1 Then $_bStatus = ProcessClose($_iPid)   
      Wend
      EXIT
       
      But the $_iPid doesn't ever show anything else than  -1, even if I can see the svchost *32.exe process in my TaskManager
       
      YES - I know I shouldn't EXIT after killing the first malware detection, but it is easier to explain the above for you, so I can get a solution.
    • By BlazerV60
      Hello all,
      I've written the code below which launches chrome in incognito mode and then proceeds to go to the autoit website.
      From my understanding, the Run() command is also supposed to output the PID number related to the application that got launched from the Run command.
      However when I run the below lines, it outputs a PID number that is different from the newly launched chrome browser's PID number, does anyone know why and possibly explain how I could retrieve the accurate PID number associated with the newly launched browser?
      Global $iPid = Run(@ComSpec & ' /c start chrome.exe https://www.autoitscript.com/forum/ -incognito' ,"", "") msgbox(0,"",$iPid) Thank you,
      Brian
    • By Progh0st
      Is it posible to get Internet traffic from a PID, like download and upload speeds. I did some research but nothing useful. ty
×
×
  • Create New...