Jump to content

Recommended Posts

Posted

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.

 

Posted (edited)
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
Posted
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.

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
Posted

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.

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
Posted

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.

Posted

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!

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
×
×
  • Create New...