1 (изменено: stealzy, 2015-02-24 14:05:48)

Тема: AHK: Универсальная функция получения информации об окнах

Из-за разнообразия названий команд получения информации об окнах, забываю как именно пишутся нек. команды ( то ли [Win%X%, Var, Title], то ли [WinGet, Var, %X%, Title], или IfWin%X% ).

Плюс раздражала смена опций DetectHiddenWindows, SetTitleMatchMode, когда меняешь их ради одной команды, а потом меняешь обратно. Если меняешь их в функции, то надо еще и сохранять старые значения и восстанавливать их потом.

Задумка: одна универсальная функция для получения информации об окнах, опции DHW и STMM в параметрах. (на выходе восстанавливаются)

WinGetI(Cmd[, ahk_x_name, DetectHiddenWindows, SetTitleMatchMode, WinText,  ExcludeTitle, ExcludeText])

+ Все параметры Cmd

Exist, Active, Title, Class, Text, Pos, ID, IDLast, PID, ProcessName, Count, List, MinMax, Style, ExStyle, Transparent, TransColor, ControlList, ControlListHwnd; OwnerID, ClientPos, CommandLine

+ source code

;Все возможные параметры: Exist, Active, Title, Class, Text, Pos, ID, IDLast, PID, ProcessName, Count, List, MinMax, Style, ExStyle, Transparent, TransColor, ControlList, ControlListHwnd; OwnerID - возвращает Id окна-владельца, ClientPos - координаты клиентской области окна в нумерованном массиве, CommandLine - путь и параметры процесса.
;Если окно не существует, возвращает "".
;Примеры:
;windowID := WinGetI("Id, XTitle AHK_class TMainForm, on")
;windowID := WinGetI("ID", "XTitle AHK_class TMainForm", "On")
;procPID := WinGetI("pid, AHK_id " . windowID . ", On")
;XWinPos := WinGetI("pos, XTitle")
;MsgBox %XWinPos[1]% %XWinPos[2]% %XWinPos[3]% %XWinPos[4]%

WinGetI(Cmd, ahk_x_name="", DetectHiddenWindows="", SetTitleMatchMode="", WinText="",  ExcludeTitle="", ExcludeText="") {
    if InStr(Cmd, ",") { ; парсим 1 параметр, если он содержит запятые
        ParamArray := StrSplit(Cmd, ",", " `t")
        Cmd                 := ParamArray[1]
        ahk_x_name             := ParamArray[2]
        DetectHiddenWindows := ParamArray[3]
        SetTitleMatchMode     := ParamArray[4]
        WinText             := ParamArray[5]
        ExcludeTitle         := ParamArray[6]
        ExcludeText         := ParamArray[7]
    }
    if (DetectHiddenWindows!="On" && DetectHiddenWindows!="Off" && DetectHiddenWindows!="")
        Return BadParam("DetectHiddenWindows", DetectHiddenWindows)
    if (SetTitleMatchMode!="1" && SetTitleMatchMode!="2" && SetTitleMatchMode!="3" && SetTitleMatchMode!="RegEx" && SetTitleMatchMode!="")
        Return BadParam("SetTitleMatchMode", SetTitleMatchMode)
        
    Old_DetectHiddenWindows:=A_DetectHiddenWindows
    Old_SetTitleMatchMode:=A_TitleMatchMode
    if DetectHiddenWindows
        DetectHiddenWindows, %DetectHiddenWindows%
    if SetTitleMatchMode
        SetTitleMatchMode, %SetTitleMatchMode%
    
    Value:=WinGetIRefined(Cmd, ahk_x_name, WinText, ExcludeTitle, ExcludeText)
    
    if DetectHiddenWindows
        DetectHiddenWindows, %Old_DetectHiddenWindows%
    if SetTitleMatchMode
        SetTitleMatchMode, %Old_SetTitleMatchMode%
        
    Return Value
}

WinGetIRefined(Cmd, ahk_x_name, WinText="",  ExcludeTitle="", ExcludeText="") {
    Static WinGetParamList:={} ; параметры ф-ии WinGet()
    WinGetParamList:=[ "ID", "IDLast", "PID", "ProcessName"
    , "Count", "List", "MinMax", "Style", "ExStyle", "Transparent", "TransColor"
    , "ControlList", "ControlListHwnd",    "ProcessPath"]
    for k, v in WinGetParamList
        if (Cmd=WinGetParamList[k]) {
            WinGet, Value, %Cmd%, %ahk_x_name%, %WinText%,  %ExcludeTitle%, %ExcludeText%
            if (Cmd="List") {
                i:=0
                Loop %Value% {
                    if ! i++    ; в первом цикле Value из переменной становиться массивом
                        Value:={}
                    Value[A_Index] := (Value%A_Index%)
                }
            }
            Return Value
        }
    
    if (Cmd="Exist")
        Value:=WinExist(ahk_x_name, WinText, ExcludeTitle, ExcludeText)
    else if (Cmd="Active")
        Value:=WinActive(ahk_x_name, WinText, ExcludeTitle, ExcludeText)
    else if (Cmd="Title")
        WinGetTitle, Value, %ahk_x_name%, %WinText%, %ExcludeTitle%, %ExcludeText%
    else if (Cmd="Class")
        WinGetClass, Value, %ahk_x_name%, %WinText%, %ExcludeTitle%, %ExcludeText%
    else if (Cmd="Text")
        WinGetText, Value, %ahk_x_name%, %WinText%, %ExcludeTitle%, %ExcludeText%
    else if (Cmd="Pos") {
        WinGetPos, X, Y, Width, Height, %ahk_x_name%, %WinText%, %ExcludeTitle%, %ExcludeText%
        Value:={}
        Value:=[X, Y, Width, Height]
    } else if InStr(Cmd, "Own") {
        WinID := WinExist(ahk_x_name, WinText, ExcludeTitle, ExcludeText)
        Value := DllCall("GetWindow", Ptr, WinID, UInt, GW_OWNER := 4, Ptr)
    } else if (Cmd="CommandLine") {
        WinGet, pid, pid, %ahk_x_name%, %WinText%,  %ExcludeTitle%, %ExcludeText%
        ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process WHERE ProcessId = " . pid)._NewEnum.next(x)
        Value := x.CommandLine
    } else if InStr(Cmd, "Client") {
        if !Hwnd:=WinExist(ahk_x_name)
            Return
        VarSetCapacity(pt, 16)
        NumPut(x, pt, 0)
        NumPut(y, pt, 4)
        NumPut(w, pt, 8)
        NumPut(h, pt, 12)
        if (!DllCall("GetClientRect", "uint", hwnd, "uint", &pt))
            Return
        if (!DllCall("ClientToScreen", "uint", hwnd, "uint", &pt))
            Return
        x := NumGet(pt, 0, "int")
        y := NumGet(pt, 4, "int")
        w := NumGet(pt, 8, "int")
        h := NumGet(pt, 12, "int")
        Value:={}
        Value:=[x, y, w, h]
    } else
        Return BadParam("Cmd", Cmd)
    
    Return Value
}
BadParam(name, Cmd) {
    MsgBox,16, WinGetI, Parameter %name%="%Cmd%" is not support
    Return
}

+Можно забыть про зоопарк из 9 команд: IfWinActive, IfWinExist, WinGet, WinGetClass, WinGetPos, WinGetTitle, WinGetText, WinGetActiveStats, WinGetActiveTitle.
+OwnerID - возвращает Id окна-владельца,
+ClientPos - координаты клиентской области окна.
ClientCoord:=WinGetI("clientpos") ; x:=ClientCoord[1], width:=ClientCoord[3]
+CommandLine - путь и параметры с которыми запущен процесс окна
"C:\Windows\calc.exe"
/solve_ferma_theorem

+Валидация параметров.

+ Примечания

Применение фунции с параметром Pos возвращает нумер. массив, ассоциативный, возможно будет понятнее (winPos["y"] vs winPos[2]), но лень писать кавычки;
Параметры Exist и ID эквиваленты;
Нестрогий синтаксис ahk_x abcd. Теоретически, название окна может содержать ahk_x либо запятые.
Посмотрел, как это сделано в AutoIt - эти параметры передаются в ф-ию асс. массивом:
f(..., Title: abcd, ...) если несколько условий, то: f(..., [Title: abcd, Class: xyzw] ...)

----------------------------
fixed: с параметром List возвращает в переменную массив контролов.

2

Re: AHK: Универсальная функция получения информации об окнах

Ну только информация об окнах не ограничивается ID, POS и PID. Ещё часто могут понадобиться ClientCoords, Style/ExStyle, ProcessName, CommandLine, OwnerID, hIcon — это так, навскидку, что первое в голову пришло. Так что тут ещё целое поле непаханное для работы.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

3 (изменено: stealzy, 2015-02-10 14:13:13)

Re: AHK: Универсальная функция получения информации об окнах

Style/ExStyle, ProcessName - уже включены.
ClientCoords - все таки к Controls относиться, хотя несложно включить.
CommandLine, hIcon - с этими зверями не сталкивался. У окна есть CommandLine?
OwnerID - нужная вещь.

4

Re: AHK: Универсальная функция получения информации об окнах

stealzy пишет:

ClientCoords - все таки к Controls относиться

Нет, я имел в виду координаты клиентской части.

У окна есть CommandLine?

CommandLine есть у процесса окна, нужно, чтобы узнать, как именно был запущен процесс. hIcon — хэндл иконки окна, чтобы можно было скопировать её в своё окно. Ну, это, правда, не так уж часто нужно.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

5 (изменено: stealzy, 2015-02-10 14:59:39)

Re: AHK: Универсальная функция получения информации об окнах

ClientCoord и OwnerID добавил.
Написание параметров произвольное, нужно лишь, чтобы они содержали строку Client или Own соответственно.
Для получения Commandline и hIcon рабочего кода не нашел.
Если есть, поделитесь, добавим.
------------------------------------
Irbis, спасибо!

6

Re: AHK: Универсальная функция получения информации об окнах

CommandLine.

7

Re: AHK: Универсальная функция получения информации об окнах

Проще:

PID := DllCall("GetCurrentProcessId")
MsgBox, % ComObjGet("winmgmts:").Get("Win32_Process.Handle=" PID).CommandLine
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

8 (изменено: stealzy, 2015-02-11 14:05:31)

Re: AHK: Универсальная функция получения информации об окнах

Чтобы воспользоваться DllCall("GetCurrentProcessId"), нужно сначала выполнить что-нибудь с окном, типа WinExist, чтобы оно стало LastFound.
А это уже 3 строчки кода, вместо 2 сейчас в скрипте .
--------------------------------------------------------------
Если так, то OK.

9

Re: AHK: Универсальная функция получения информации об окнах

Я вижу три:

        WinGet, pid, pid, %ahk_x_name%, %WinText%,  %ExcludeTitle%, %ExcludeText%
        ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process WHERE ProcessId = " . pid)._NewEnum.next(x)
        Value := x.CommandLine

С моим вариантом было бы две:

WinGet, pid, pid, %ahk_x_name%, %WinText%,  %ExcludeTitle%, %ExcludeText%
Value := ComObjGet("winmgmts:").Get("Win32_Process.Handle=" PID).CommandLine
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder