﻿;-- TIME_STAMP   2018-12-05 17:33:40   v 0.1

#include-once

#include <Array.au3>
#include <WinAPI.au3>

; #FUNCTION# ====================================================================================================================
; Name ..........: GetAllWindowsControls
; Description ...:
; Syntax ........: GetAllWindowsControls($hCallersWindow[, $bOnlyVisible = False[, $sStringIncludes = ""[, $sClass = ""[, $iMaxTextLen = -1]]]])
; Parameters ....: $hCallersWindow      - a handle value.
;                  $iVisible            - [optional] a integer value. 0 = all (Default), 1 = only visible, 2 = only hidden
;                  $sStringIncludes     - [optional] a string value.  Default is ""
;                  $sClass              - [optional] a string value.  Default is ""
;                  $iMaxTextLen         - [optional] a integer value. Default is -1 (2147483647)
; Return values .: String with Controls descriptions.
; Author ........: jdelaney
; Modified ......: mLipok, Bitnugger
; Remarks .......:
; Related .......:
; Link ..........: https://www.autoitscript.com/forum/topic/164226-get-all-windows-controls/
; Example .......: No
; ===============================================================================================================================
Func GetAllWindowsControls($hCallersWindow, $iVisible = Default, $sStringIncludes = Default, $sClass = Default, $iMaxTextLen = Default)
    If Not IsHWnd($hCallersWindow) Then
        ConsoleWrite("$hCallersWindow must be a handle...provided=[" & $hCallersWindow & "]" & @CRLF)
        Return False
    EndIf

    ; Get all list of controls
    If $iVisible = Default Then $iVisible = 0
    If $sStringIncludes = Default Then $sStringIncludes = ""
    If $sClass = Default Then $sClass = ""
	If $iMaxTextLen = Default Or $iMaxTextLen = -1 Or $iMaxTextLen > 2147483647 Then $iMaxTextLen = 2147483647

    Local $sClassList = WinGetClassList($hCallersWindow)

    ; Create array
    Local $aClassList = StringSplit(StringTrimRight($sClassList, 1), @LF, 2)

    ; Sort array
    _ArraySort($aClassList)

    ; Loop
    Local $sCurrentClass = ""
    Local $iCurrentCount = 1
    Local $iTotalCounter = 1

    If StringLen($sClass) > 0 Then
        For $i = UBound($aClassList) - 1 To 0 Step -1
            If $aClassList[$i] <> $sClass Then
                _ArrayDelete($aClassList, $i)
            EndIf
        Next
    EndIf

    Local $hControl = Null, $aControlPos
    Local $sControlText = ''
    Local $iControlID = 0
    Local $bIsVisible = False
    Local $sResult = ''
	Local $iTextLen
	Local $aClosed = ['+++', '+++', '+++', '+++']

    For $iClass_idx = 0 To UBound($aClassList) - 1
        If $aClassList[$iClass_idx] = $sCurrentClass Then
            $iCurrentCount += 1
        Else
            $sCurrentClass = $aClassList[$iClass_idx]
            $iCurrentCount = 1
        EndIf

        $hControl = ControlGetHandle($hCallersWindow, "", "[CLASSNN:" & $sCurrentClass & $iCurrentCount & "]")
        $sControlText = StringRegExpReplace(ControlGetText($hCallersWindow, "", $hControl), "[\n\r]", "{@CRLF}")
		$iTextLen = StringLen($sControlText)
		$sControlText = StringLen($sControlText) <= $iMaxTextLen ? $sControlText: StringLeft($sControlText, $iMaxTextLen) & '...'
        $aControlPos = ControlGetPos($hCallersWindow, "", $hControl)
        $iControlID = _WinAPI_GetDlgCtrlID($hControl)
        $bIsVisible = ControlCommand($hCallersWindow, "", $hControl, "IsVisible")
        Switch True
			Case $iVisible = 1 And Not $bIsVisible, $iVisible = 2 And $bIsVisible, StringLen($sStringIncludes) > 0 And Not StringInStr($sControlText, $sStringIncludes)
            $iTotalCounter += 1
            ContinueLoop
		EndSwitch

		$aControlPos = IsArray($aControlPos) ? $aControlPos: $aClosed
		$sResult &= StringFormat("Func=[GetAllWindowsControls]: ControlCounter=[%3s] ControlID=[%6s] Handle=[%10s] ClassNN=[%-19s] XPos=[%5s] YPos=[%5s] Width=[%5s] Height=[%5s] IsVisible=[%s] Text(%010i)=[%s]\r\n", _
			$iTotalCounter, $iControlID, $hControl, $sCurrentClass & $iCurrentCount, $aControlPos[0], $aControlPos[1], $aControlPos[2], $aControlPos[3], $bIsVisible, $iTextLen, $sControlText)

        If Not WinExists($hCallersWindow) Then ExitLoop
        $iTotalCounter += 1
    Next

    Local $aRx = StringRegExp($sResult, 'Text\([0]+', 3)
	StringReplace(UBound($aRx) ? $aRx[_ArrayMinIndex($aRx)] : '', '0', '')
	Local $sReplace = StringLeft('0000000000', @extended)
	If $sReplace Then $sResult = StringRegExpReplace($sResult, '(Text\()' & $sReplace, '\1')
	Do
		$sResult = StringRegExpReplace($sResult, '(Text\((\s+)?)0([0-9]+\))', '\1 \3')
	Until @extended = 0
	$aRx = StringRegExp($sResult, '(?:ClassNN=\[)([[:alnum:]]+)', 3)
	If UBound($aRx) Then
		Local $iMaxLen = 0, $iLen
		For $i = 0 To UBound($aRx) -1 Step 1
			$iLen = StringLen($aRx[$i])
			$iMaxLen = $iLen > $iMaxLen ? $iLen : $iMaxLen
		Next
		ConsoleWrite("@@ Debug line" & @TAB & @ScriptLineNumber & "   var: $iMaxLen --> " & $iMaxLen & @CRLF)
		$sReplace = StringLeft('0000000000000000000', 19 - $iMaxLen)
		$sResult = StringRegExpReplace($sResult, '(ClassNN=\[[[:alnum:]|_|\s]{1,'&$iMaxLen&'})', '\1')
	EndIf

	Return $sResult
EndFunc   ;==>GetAllWindowsControls
