Jump to content

Recommended Posts

Posted

Okay, I am trying to create a script that will allow me to toggle minimize/restore on a select group of open windows as shown in my taskbar. In poking around I was able to locate a script that showed ALL open windows in the taskbar and I've tried modifying it by paring that list down to only those windows whose parent process ID matches that of the program that spawned them. However, I haven't been able to get it to work. I'm quite new so I'm probably making an obvious mistake but I want to understand what's going on and haven't been able to get any further. Here is what I have so far:

#Include <Array.au3>
#Include <WinAPI.au3>
#Include <WindowsConstants.au3>
#include <MsgBoxConstants.au3>

Local $aWinInTaskBar[1][2]
Local $bMTparentWindows[1][2]
$iCount = 0
$nCount = 0

$aList = WinList()

For $i = 1 To $aList[0][0]
    $iExStyle = _WinAPI_GetWindowLong($aList[$i][1], $GWL_EXSTYLE) ; get the extended style of each Window

    If NOT BitAND($iExStyle, $WS_EX_TOOLWINDOW) AND _  ; Search for windows without $WS_EX_TOOLWINDOW extended style
       BitAND(WinGetState($aList[$i][1]), 2 ) Then     ; And only visible windows
        $iCount += 1
        Redim $aWinInTaskBar[ $iCount + 1][2]
        $aWinInTaskBar[ $iCount][0] = $aList[$i][0]
        $aWinInTaskBar[ $iCount][1] = $aList[$i][1]
        ; MsgBox($MB_OK, "VALUE", "This is the value:", $aWinInTaskBar[$iCount][0])
    EndIf
 Next

 For $n = 1 To $aWinInTaskBar[0][0]
    $nParentWindow = _WinAPI_GetParent($aWinInTaskBar[$n][1]) ; get the parent of each Window

    MsgBox($MB_OK, "VALUE", "This is the value:", & $aWinInTaskBar[$n][1])
    If (WinGetProcess ($nParentWindow) ==  9464) Then ; Search for windows whose parent ID equals main process ID
        $nCount += 1
        Redim $bMTparentWindows[ $nCount + 1][2]
        $bMTparentWindows[ $nCount][0] = $aWinInTaskBar[$n][0]
        $bMTparentWindows[ $nCount][1] = $aWinInTaskBar[$n][1]
    EndIf
 Next

$aWinInTaskBar[0][0] = UBound($aWinInTaskBar) - 1
$bMTparentWindows[0][0] = UBound($bMTparentWindows) - 1
_ArrayDisplay($aWinInTaskBar)
_ArrayDisplay($bMTparentWindows)

Now the first FOR loop correctly shows the list of opened windows in my task bar but my progress is complicated by the fact that I can't even get MsgBox to display items from the arrays for testing. The second FOR loop is my adaptation. It produces a box showing the @bMTparentWindows array but it's entirely devoid of any values. My thinking was that this would be a good first step to reaching my ultimate goal and I was planning on expanding it to include the toggle function and to combine the FOR loops and eliminate the usage of Redim. Is there is a simpler way? Why is this not working? Any help would be much appreciated!

Posted

The last comma in both Msgbox is unwanted
The 2nd For loop doesn't run because you define the $aWinInTaskBar[0][0] value after this loop  :)

I don't know exactly what you mean with "parent process" , WinGetProcess should be enough

Posted
12 hours ago, mikell said:

The last comma in both Msgbox is unwanted
The 2nd For loop doesn't run because you define the $aWinInTaskBar[0][0] value after this loop  :)

I don't know exactly what you mean with "parent process" , WinGetProcess should be enough

Okay, I removed the extra comma there, thanks. I'm not sure what you mean though about $aWinInTaskBar[0][0] being defined after the second loop. My thinking was that $aWinInTaskBar[0][0] was defined on this line in the first FOR loop:

 

23 hours ago, Bagel said:

        $aWinInTaskBar[ $iCount][0] = $aList[$i][0]

I had thought that $aWinInTaskBar was the array created by the first loop and my idea was to cycle through the elements in that array with the second loop as $n iterates from 1 to the end of the array.  I then wanted to determine the process ID of the parent window of each item in the array so that I can compare it against the process ID of a particular program. The first loop produces a list of all the open windows on my taskbar but I need a subset of that list that returns only the windows associated with a particular program so that I can control just those windows. I don't know of any way to tell WinGetProcess to do that. Each window associated with the program I want to filter for has a different name, the names can change and some of the windows will have the same titles as other windows. So my idea was that every window associated with that program would have the same "parent" window so I went with _WinAPI_GetParent.

I can confirm using Msgbox that indeed the second FOR loop never executes, I just don't understand how :)  After the first FOR loop $aWinInTaskBar is definitely a populated array that can be displayed and so shouldn't it's value $aWinInTaskBar[0][0] already be defined?

Thanks a lot for the feedback!

Posted

Well what I meant is written in the comments in the code below
BTW a process id can be different each time you launch it, so it's better to get this ID in the script  :)

#Include <Array.au3>
#Include <WinAPI.au3>
#Include <WindowsConstants.au3>
#include <MsgBoxConstants.au3>

$aList = WinList()

Local $aWinInTaskBar[$aList[0][0]+1][2] ; <<<<<<<give an initial size to the array
$iCount = 0

For $i = 1 To $aList[0][0]
    $iExStyle = _WinAPI_GetWindowLong($aList[$i][1], $GWL_EXSTYLE) ; get the extended style of each Window

    If NOT BitAND($iExStyle, $WS_EX_TOOLWINDOW) AND _  ; Search for windows without $WS_EX_TOOLWINDOW extended style
       BitAND(WinGetState($aList[$i][1]), 2 ) Then     ; And only visible windows
        $iCount += 1
        $aWinInTaskBar[ $iCount][0] = $aList[$i][0]
        $aWinInTaskBar[ $iCount][1] = $aList[$i][1]
        ; MsgBox($MB_OK, "VALUE", "This is the value: " & $aWinInTaskBar[$iCount][0])
    EndIf
 Next
Redim $aWinInTaskBar[ $iCount + 1][2]    ;<<<<<<<<<<<<<<Redim only once
$aWinInTaskBar[0][0] = UBound($aWinInTaskBar) - 1   ;<<<<<write the value at index 0
_ArrayDisplay($aWinInTaskBar)


; Then you can safely go for the 2nd For loop
Local $bMTparentWindows[$aWinInTaskBar[0][0]+1][2]
$nCount = 0

 For $n = 1 To $aWinInTaskBar[0][0]
   ; MsgBox($MB_OK, "VALUE", "This is the value: " & $aWinInTaskBar[$n][1])
    $PID = ProcessExists("firefox.exe")    ;<<<<<<<<<<<<<<<get the PID of the process
    If $PID <> 0 Then
       If (WinGetProcess ($aWinInTaskBar[$n][1]) = $PID) Then
           $nCount += 1
           $bMTparentWindows[ $nCount][0] = $aWinInTaskBar[$n][0]
           $bMTparentWindows[ $nCount][1] = $aWinInTaskBar[$n][1]
       EndIf
    EndIf
 Next
Redim $bMTparentWindows[ $nCount + 1][2]
$bMTparentWindows[0][0] = UBound($bMTparentWindows) - 1
_ArrayDisplay($bMTparentWindows)

 

Posted (edited)

Hi Bagel,

To refresh :  You can control a group of windows by their class group

*  for example, list them into a comboBox with other additional action buttons as in close, restore , minimize .etc
the rest is too easy  .. 

#include <Array.au3>
#include <WinAPISysWin.au3>
#include <WindowsConstants.au3>

Local $aWin = _WinAPI_EnumWindowsTop()
$aWinU = _ArrayExtract($aWin, 2, _ArraySearch($aWin, "") - 2)
For $i = UBound($aWinU) - 1 To 0 Step -1
    If Not WinGetTitle($aWinU[$i][0], "") Then _ArrayDelete($aWinU, $i)
Next
If UBound($aWinU) - 1 < 3 Then Exit

_ArrayDisplay($aWinU, "Desktop windows")

$aGroups = _ArrayUnique($aWinU, 1)
_ArrayDisplay($aGroups, "Choose a group")

Deye

Edited by Deye
Typo
Posted
On 10/9/2018 at 5:47 AM, Deye said:

Hi Bagel,

To refresh :  You can control a group of windows by their class group

*  for example, list them into a comboBox with other additional action buttons as in close, restore , minimize .etc
the rest is too easy  .. 

#include <Array.au3>
#include <WinAPISysWin.au3>
#include <WindowsConstants.au3>

Local $aWin = _WinAPI_EnumWindowsTop()
$aWinU = _ArrayExtract($aWin, 2, _ArraySearch($aWin, "") - 2)
For $i = UBound($aWinU) - 1 To 0 Step -1
    If Not WinGetTitle($aWinU[$i][0], "") Then _ArrayDelete($aWinU, $i)
Next
If UBound($aWinU) - 1 < 3 Then Exit

_ArrayDisplay($aWinU, "Desktop windows")

$aGroups = _ArrayUnique($aWinU, 1)
_ArrayDisplay($aGroups, "Choose a group")

Deye

Okay, thanks! I really like this approach, it's very close to what I'm looking for and much faster than my other approach but now I need to extract one window from $aWinU whose title always contains two words. Here is my attempt but I haven't been able to get it to work and I don't know why. I also can't even get MsgBox to work here to troubleshoot and I can't figure that out either:
 

#include <Array.au3>
#include <WinAPISysWin.au3>
#include <WindowsConstants.au3>
#include <MsgBoxConstants.au3>

Local $aWin = _WinAPI_EnumWindowsTop()
;WindowsForms10.Window.8.app.0.1ca0192_r6_ad1
$aWinU = _ArrayExtract($aWin, 2, _ArraySearch($aWin, "") - 2)
For $i = UBound($aWinU) - 1 To 0 Step -1
    If Not WinGetTitle($aWinU[$i][0], "") And WinGetTitle($aWinU[$i][0], "two words") Then _ArrayDelete($aWinU, $i)
       MsgBox($MB_OK, & $aWinU([$i][0])
Next
If UBound($aWinU) - 1 < 3 Then Exit

_ArrayDisplay($aWinU, "Desktop windows")

$aGroups = _ArrayUnique($aWinU, 1)
;_ArrayDisplay($aGroups, "Choose a group")

 

Posted

Here is an example where you can use StringRegExp to match any of words (two words|two|words|.etc)

 

Local $aWin = _WinAPI_EnumWindowsTop()

$aWinU = _ArrayExtract($aWin, 2, _ArraySearch($aWin, "") - 2)
For $i = UBound($aWinU) - 1 To 0 Step -1
    If Not WinGetTitle($aWinU[$i][0], "") Then
        _ArrayDelete($aWinU, $i)
    ElseIf StringRegExp(WinGetTitle($aWinU[$i][0], ""), "(?i)(Scite|AutoIt General Help and Support|.etc)", 0) Then
        MsgBox(0, "Deleting - " & $aWinU[$i][1], WinGetTitle($aWinU[$i][0], ""), 3)
        _ArrayDelete($aWinU, $i)
    EndIf
Next
If UBound($aWinU) < 3 Then Exit
_ArrayDisplay($aWinU, "Desktop windows")

Deye

Posted

Okay, it has occurred to me that there might be a way to make this faster. I thought it might be easier if we could extract all of the elements from $aWin that have a class that matches a specific string, then use the StringRegExp function to eliminate the one undesirable element. Here is my idea:
 

#include <Array.au3>
#include <WinAPISysWin.au3>
#include <WindowsConstants.au3>
#include <MsgBoxConstants.au3>

Local $aWin = _WinAPI_EnumWindowsTop()
Local $mtClass = "WindowsForms10.Window.8.app.0.1ca0192_r6_ad1"
$aWinU = _ArrayExtract($aWin, 2, _ArraySearch($aWin, $mtClass) - 2)
For $i = UBound($aWinU) - 1 To 0 Step -1
    If Not WinGetTitle($aWinU[$i][0], "") Then
        _ArrayDelete($aWinU, $i)
    ElseIf StringRegExp(WinGetTitle($aWinU[$i][0], ""), "MT", 0) Then
        MsgBox(0, "Deleting - " & $aWinU[$i][1], WinGetTitle($aWinU[$i][0], ""), 3)
        _ArrayDelete($aWinU, $i)
    EndIf
Next
If UBound($aWinU) < 3 Then Exit
_ArrayDisplay($aWinU, "Desktop windows")

From what I understand about _ArraySearch I expect it to enter the string $mtClass as the matching criteria to test against every entry in $aWin creating an array in $aWinU that only has those class values. But it's not working and I can't see why. Thanks a lot for your help.

Posted

In this example:

Using _ArraySort will glue together all rows containing $mtClass 

Create a range that will be used  with  _ArrayDelete :
With _ArraySearch  find the first instance of $mtClass searching from the beginning of the array (from) , And  (to)  find the first instance reading from the end of the array 

#include <Array.au3>
#include <WinAPISysWin.au3>

Local $aWin = _WinAPI_EnumWindowsTop()
Local $mtClass = "WindowsForms10.Window.8.app.0.1ca0192_r6_ad1"
$aWinU = _ArrayExtract($aWin, 2, _ArraySearch($aWin, "") - 2)
_ArraySort($aWinU, 0, 0, 0, 1) ; $iSubItem 1

Local $i = _ArraySearch($aWinU, $mtClass, Default, Default, Default, 2, Default, 1) ; searches the array from beginning to end
If Not @error Then
    Local $byRange = $i & "-" & _ArraySearch($aWinU, $mtClass, Default, Default, Default, 2, 0, 1) ;searches the array from end to beginning
    _ArrayDisplay($aWinU, "Rows From\To " & $byRange & " will be gone")
    _ArrayDelete($aWinU, $byRange)
EndIf

_ArrayDisplay($aWinU, "Desktop windows")

 

Posted

Okay, thank you very much! Putting some of this together, this is what I came up with:

Quote

Local $aWin = _WinAPI_EnumWindowsTop()
Local $mtClass = "WindowsForms10.Window.8.app.0.1ca0192_r6_ad1"

$aWinU = _ArrayExtract($aWin, _ArraySearch($aWin, $mtClass, Default, Default, Default, 2, Default, Default), _ArraySearch($aWin, $mtClass, Default, Default, Default, 2, 0, Default))
;_ArrayDisplay($aWinU, "Desktop windows")

For $i = UBound($aWinU) - 1 To 0 Step -1
    If StringRegExp(WinGetTitle($aWinU[$i][0], ""), "MT", 0) Then
        _ArrayDelete($aWinU, $i)
    EndIf
 Next
;_ArrayDisplay($aWinU, "Desktop windows")

It seems on my system that I don't need to do any sorting as the windows I want are all grouped together already.

Now for the next step, I need to loop through the final array and toggle between minimizing and restoring each window, or all of them simultaneously if possible. But I need to be able to do this quickly. The above code executes in about 3 tenths of a second but is there a way I can store and reuse this final array so that every time I trigger this toggling operation the above code doesn't re-execute?

Posted

So in long short form this is all you are after ?

#include <Array.au3>
$aWin = WinList("[CLASS:WindowsForms10.Window.8.app.0.1ca0192_r6_ad1]")
_ArrayDisplay($aWin)

 

1 hour ago, Bagel said:

toggle between minimizing and restoring each window, or all of them simultaneously

At this point I cannot tell because I never tried that maybe a better approach for you is to find out how to automate a taskbar group where you could toggle between minimizing .. all at once

try looking here

Deye

Posted
12 minutes ago, Deye said:

So in long short form this is all you are after ?


#include <Array.au3>
$aWin = WinList("[CLASS:WindowsForms10.Window.8.app.0.1ca0192_r6_ad1]")
_ArrayDisplay($aWin)

 

At this point I cannot tell because I never tried that maybe a better approach for you is to find out how to automate a taskbar group where you could toggle between minimizing .. all at once

try looking here

Deye

Unfortunately, that's all that I think I needed for this stage. But in the beginning because of my earlier attempt and reading about parent and child ID's ( I was trying to find a way to do it in Powershell and C# ) I thought I had to work with them and didn't know I could obtain fine-grained control by using the window class. At least I'm learning quite a bit more about AutoIT scripting. Thanks for the suggestion but what that link leads too is a bit too much overhead for my needs at this point. I'll start another topic about the rest.

Thank you very much for your help! And thanks to mikell as well!

Posted (edited)

@Bagel

Had a spare moment to see what I can come up with ..

#include <WinAPISysWin.au3>
#include <Array.au3>
$aWin = WinList("[CLASS:WindowsForms10.Window.8.app.0.1ca0192_r6_ad1]")
$tRET = _WinAPI_GetWindowPlacement($aWin[1][1])
$retore = (DllStructGetData($tRET, "showCmd") = 2 ? 1 : 2) ; Toggle accordingly to the state of the top last active window of the group
For $i = UBound($aWin) - 1 To 0 Step -1
    $tRET = _WinAPI_GetWindowPlacement($aWin[$i][1])
    DllStructSetData($tRET, "showCmd", $retore)
    _WinAPI_SetWindowPlacement($aWin[$i][1], $tRET)
Next
Quick enough for you, I hope ;)

Deye

Edited by Deye
changed to maintain windows Z order
Posted

Amazing! Not only is it very fast but it's working more consistently than what I had. I was using WinSetState but found that it wasn't grabbing the right windows, sometimes it would work and sometimes it wouldn't... Driving me nuts. Then found _WinAPI_EnumProcessWindows which was working slowly but more consistently and grabbing the proper windows. SetWindowPlacement seems to be both consistent and very fast. Only now I'm running into a problem where it will grab too many of the windows with that specified class so I'm looking into how I can pare the list down to the proper windows more efficiently. I'm thinking that a lot of functions in my previous codes that aren't WinAPI specific are causing the slowdowns but not sure how to refine the filter process for the windows using the WinAPI. I can locate some documentation on specific WinAPI functions (and haven't figured out quite yet how your code here works) but it's hard to get a broader picture of what kind of functions are out there that pertain to window elements that might allow me to make the selection part of the code more accurate. I continue working on it as I can. Thanks for another big piece of the puzzle!

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...