;-- TIME_STAMP   2021-10-12 15:59:03   v 1.0

#Region    ;************ Includes ************
#include-once
#include <WindowsConstants.au3>
#include <Date.au3>
#include <GuiComboBoxEx.au3>
#include <GuiListBox.au3>
#include <GuiListView.au3>
#include <WinAPIProc.au3>
#include <WinAPISysWin.au3>
#EndRegion ;************ Includes ************

Global Enum $WGC_SHOWALL, $WGC_SHOWVISIBLE, $WGC_SHOWHIDDEN

Global $g_WGC_sHeader_ProcessInfo = 'Count|PID|ProcessName|CommandLine|User|Wow64|WorkingDir|RunTime|PIDParentProcess|ParentProcessName|ParentProcessWindows|ProcessList'
Global $g_WGC_sHeader_Controls = 'HWND|CLASS|NN|ID|AU3|Visible|xPos|yPos|width|hight|Title|Text'
Global Enum $eHWND, $eCLASS, $eNN, $eID, $eAU3, $eVisible, $exPos, $eyPos, $ewidth, $ehight, $eTitle, $eText
Global Enum $eName, $eErw, $eSize, $eDatum, $eAttr
Global Enum $eHeader_ProcessInfo, $eHeader_Controls, $eHeader_Both

; #FUNCTION# ================================================================================================================
; Name...........: _WinGetControls
; Description ...: Liefert ein 2D-Array mit den Controls eines Fensters.
; Syntax.........: _WinGetControls($hWnd[, $iVisible = False[, $bProcessInfo = True[, $bExtended = False[, $iMaxTextLen = -1]]]])
; Parameters ....: $hWnd         - HWND des Fensters (z.B. Rückgabewert von GUICreate)
;                  $iVisible     - [optional] $WGC_SHOWALL (0) = alle, $WGC_SHOWVISIBLE (1) = nur sichtbare, $WGC_SHOWHIDDEN (2) = nur unsichtbare Controls übergeben
;                  $bProcessInfo - [optional] wenn True, werden in den ersten beiden Zeilen Informationen über den Process übergeben, dem das Window ($hWnd) gehört,
;                                             und darunter eine Leerzeile zur Trennung eingefügt.
;                  $bExtended    - [optional] wenn True, wird der Inhalt von Listboxen und ListViews als 2D-Array in der Spalte Text übergeben
;                  $iMaxTextLen  - [optional] a integer value. Default is -1 (2147483647), -2 = nur erste Zeile
; Return values .: Erfolg:       - 2D-Array mit den Controls eines Fensters.
;                                - [0][ 0]         - Anzahl der Controls
;           $bProcessInfo = True - [0][ 1-11]      - iPID|sProcessName|sCommandLine|sUser|bWow64|sWorkingDir|sRunTime|iPIDParentProcess|sParentProcessName|aParentProcessWindows|aProcessList
;                                - [n][ 0] HWND    - HWND des Controls
;                                - [n][ 1] CLASS   - Klasse des Controls
;                                - [n][ 2] NN      - ClassNN des Controls
;                                - [n][ 3] ID      - ID des Controls
;                                - [n][ 4] AU3     - AU3-Bezeichnung des Controls
;                                - [n][ 5] Visible - Sichtbar? 1 = ja, 0 = nein
;                                - [n][ 6] xPos    - Horizontale Position des Controls
;                                - [n][ 7] yPos    - Vertikale Position des Controls
;                                - [n][ 8] width   - Breite des Controls
;                                - [n][ 9] hight   - Höhe des Controls
;                                - [n][10] Title   - Titel des Windows/Controls
;                                - [n][11] Text    - Text des Controls
;                  Fehler:       - False, @error = 1
; Author ........: Großater & progandy & UEZ (www.autoit.de)
; Modified.......: Bitnugger
; Remarks .......: ProcessInfo funktioniert mom. nur bei einem Top-Window
; Related .......:
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _WinGetControls($hWnd, $iVisible = False, $bProcessInfo = True, $bExtended = False, $iMaxTextLen = -1)
	If Not IsHWnd($hWnd) Then Return SetError(1, 0, False)
	Local $hParent = _WinAPI_GetAncestor($hWnd, $GA_ROOT)
	If IsHWnd($hParent) And ($hParent <> $hWnd) Then
		ConsoleWrite('! $hWnd is a Child-Window! ClassName = ' & _WinAPI_GetClassName($hWnd) & @CRLF)
		$hWnd = $hParent
	EndIf

	If $iMaxTextLen = Default Or $iMaxTextLen = -1 Or $iMaxTextLen > 2147483647 Then $iMaxTextLen = 2147483647 ; Max. Länge des Textes für die Spalten Title und Text (Col 10 und Col 11)

	Local $iUBoundControls = 100
	Local $iUBoundClasses = 50
	Local $aControls[$iUBoundControls + 1][12] = [[0]]
	Local $aClasses[$iUBoundClasses + 1][2]    = [[0]]
	Local $aResult, $sAU3, $iClassesCount, $iControlsCount, $sClass, $bClassExist, $hControl, $iControlID, $iControlNN, $iStyles
	Local $aClassList = StringSplit(StringStripWS(WinGetClassList($hWnd), 2), @LF)

	For $i = 1 To $aClassList[0]
		If $aClassList[$i] = '' Then ContinueLoop

		$sClass = $aClassList[$i]
		$bClassExist = False
		$iClassesCount = $aClasses[0][0]
		For $j = 1 To $iClassesCount
			If $aClasses[$j][0] = $sClass Then
				$iControlNN = $aClasses[$j][1] + 1
				$aClasses[$j][1] = $iControlNN
				$bClassExist = True
				ExitLoop
			EndIf
		Next
		If Not $bClassExist Then
			$iControlNN = 1
			$iClassesCount += 1
			If $iClassesCount > $iUBoundClasses Then
				$iUBoundClasses += 50
				ReDim $aClasses[$iUBoundClasses + 1][2]
			EndIf
			$aClasses[0][0] = $iClassesCount
			$aClasses[$iClassesCount][0] = $sClass
			$aClasses[$iClassesCount][1] = $iControlNN
		EndIf
		$hControl = ControlGetHandle($hWnd, "", $sClass & $iControlNN)
		If Not IsHWnd($hControl) Then ContinueLoop

		$aResult = DllCall("User32.dll", "Int", "GetDlgCtrlID", "HWND", $hControl)
		$iControlID = (@error Or $aResult[0] = 0) ? "" : $aResult[0]
		$iControlsCount = $aControls[0][0] + 1
		If $iControlsCount > $iUBoundControls Then
			$iUBoundControls += 100
			ReDim $aControls[$iUBoundControls + 1][12]
		EndIf

    	; Ausgeliehen aus der WinAPI.au3
    	$aResult = DllCall("User32.dll", "LONG_PTR", (@AutoItX64 ? "GetWindowLongPtrW" : "GetWindowLongW"), "HWND", $hControl, "INT", $GWL_STYLE) ; Styles ermitteln
    	$iStyles = $aResult[0]

		; Erweiterung nach Vorschlag von UEZ - AutoIt interne Bezeichnung des ClassName ermitteln
		$sAU3 = __WGC_GetAU3ClassName($iStyles, $sClass, $bExtended, $aControls, $iControlsCount, $hControl)

		Local $sWinTitle = '', $sControlText = '' ;, $sEditText = ''
		;                  $iVisible     - [optional] $WGC_SHOWALL (0) = alle, $WGC_SHOWVISIBLE (1) = nur sichtbare, $WGC_SHOWHIDDEN (2) = nur unsichtbare Controls übergeben
		If $iVisible = $WGC_SHOWVISIBLE And ControlCommand($hControl, '', '', "IsVisible", "") = 0 Then ContinueLoop	; nur sichtbare Controls anzeigen?
		If $iVisible = $WGC_SHOWHIDDEN  And ControlCommand($hControl, '', '', "IsVisible", "") = 1 Then ContinueLoop	; nur unsichtbare Controls anzeigen?
		Local $aRx, $aControlPos = ControlGetPos($hControl, '', '')
		$sControlText = ControlGetText($hControl, '', '')
		$sWinTitle = WinGetTitle($hControl)
		If $iMaxTextLen = -2 Then
			$aRx = StringRegExp($sControlText, '(.+)(?:\R)?', 3)
			$sControlText = UBound($aRx) ? $aRx[0] : $sControlText
			$aRx = StringRegExp($sWinTitle, '(.+)(?:\R)?', 3)
			$sWinTitle = UBound($aRx) ? $aRx[0] : $sWinTitle
		Else
			$sControlText = StringLeft($sControlText, $iMaxTextLen)
			$sWinTitle = StringLeft($sWinTitle, $iMaxTextLen)
		EndIf
		$aControls[0][0] = $iControlsCount
		$aControls[$iControlsCount][0] = $hControl
		$aControls[$iControlsCount][1] = $sClass
		$aControls[$iControlsCount][2] = $iControlNN
		$aControls[$iControlsCount][3] = $iControlID
    	$aControls[$iControlsCount][4] = $sAU3
		$aControls[$iControlsCount][5] = ControlCommand($hControl, '', '', "IsVisible", "")
		$aControls[$iControlsCount][6] = $aControlPos[0]
		$aControls[$iControlsCount][7] = $aControlPos[1]
		$aControls[$iControlsCount][8] = $aControlPos[2]
		$aControls[$iControlsCount][9] = $aControlPos[3]
		$aControls[$iControlsCount][10] = $sWinTitle
		If $aControls[$iControlsCount][11] = '' And $aControls[$iControlsCount][10] <> $sControlText Then $aControls[$iControlsCount][11] = $sControlText
	Next
	$iControlsCount = $aControls[0][0] + 1
	If $hControl = "" Then $iControlsCount -= 1
	ReDim $aControls[$iControlsCount][12]

	If UBound($aControls) And $bProcessInfo Then
		Local $aProcessInfo = _WGC_GetProcessInfo($hParent)
		For $p = 1 To UBound($aControls, 2) -1 Step 1
			$aControls[0][$p] = $aProcessInfo[$p -1]
		Next
		_ArrayInsert($aControls, 0, $g_WGC_sHeader_ProcessInfo)
		_ArrayInsert($aControls, 2)
		_ArrayInsert($aControls, 3, $g_WGC_sHeader_Controls)
	Else
		_ArrayInsert($aControls, 0, $g_WGC_sHeader_Controls)
	EndIf

	Return $aControls
EndFunc   ;==>_WinGetControls
; ===============================================================================================================================

Func _WGC_GetProcessInfo($hWnd)
	Local $iPID = WinGetProcess($hWnd)
	Local $sProcessName = _WinAPI_GetProcessName($iPID)
	Local $sProcessCommandLine = _WinAPI_GetProcessCommandLine($iPID)
	Local $aProcessUser = _WinAPI_GetProcessUser($iPID)
	Local $bIsWow64Process = _WinAPI_IsWow64Process($iPID)
	Local $sProcessWorkingDirectory = _WinAPI_GetProcessWorkingDirectory($iPID)
	Local $aFT = _WinAPI_GetProcessTimes($iPID)
	Local $tFT = _Date_Time_FileTimeToLocalFileTime($aFT[0])
	Local $tST = _Date_Time_FileTimeToSystemTime($tFT)
	Local $sProcessRunTime = _WinAPI_GetTimeFormat(0, $tST)
	Local $iPIDParentProcess = _WinAPI_GetParentProcess($iPID)
	Local $sParentProcessName = _WinAPI_GetProcessName($iPIDParentProcess)
	Local $aParentProcessWindows = _WinAPI_EnumProcessWindows($iPIDParentProcess, True)
	Local $aProcessList = ProcessList($sParentProcessName)
	Local $aProcessInfo = [$iPID, $sProcessName, $sProcessCommandLine, _ArrayToString($aProcessUser, '@'), $bIsWow64Process, $sProcessWorkingDirectory, $sProcessRunTime, $iPIDParentProcess, $sParentProcessName, $aParentProcessWindows, $aProcessList]
	Return $aProcessInfo
EndFunc

Func _WGC_GetListViewItems($hWnd)
	Local $aListViewItems, $iItemCount = _GUICtrlListView_GetItemCount($hWnd), $iColumnCount = _GUICtrlListView_GetColumnCount($hWnd), $aItem, $aListViewItems[$iItemCount][$iColumnCount]
	If $iItemCount > 0 Then
		For $i = 0 To $iItemCount -1 Step 1
			$aItem = _GUICtrlListView_GetItemTextArray($hWnd, $i)
			For $j = 0 To $iColumnCount -1 Step 1
				ConsoleWrite(StringFormat('$i = %i, $j = %i\r', $i, $j))
				$aListViewItems[$i][$j] = $aItem[$j]
			Next
		Next
		Return $aListViewItems
	EndIf
EndFunc

Func _WGC_GetListBoxItems($hWnd)
	Local $iListBoxItemsCount = _GUICtrlListBox_GetCount($hWnd), $aListBoxItems[$iListBoxItemsCount]
	If $iListBoxItemsCount <> -1 Then
		For $i = 0 To $iListBoxItemsCount -1 Step 1
			$aListBoxItems[$i] = _GUICtrlListBox_GetText($hWnd, $i)
		Next
		Return $aListBoxItems
	EndIf
EndFunc

Func _WGC_GetHeader($iHeader = 1)
	Switch $iHeader
		Case $eHeader_ProcessInfo ; 0
			Return $g_WGC_sHeader_ProcessInfo
		Case $eHeader_Controls ; 1
			Return $g_WGC_sHeader_Controls
		Case $eHeader_Both ; 2
			Local $vReturn = [$g_WGC_sHeader_ProcessInfo, $g_WGC_sHeader_Controls]
			Return $vReturn
		Case Else
			Return SetError(1, 0, False)
	EndSwitch
EndFunc

Func __WGC_GetAU3ClassName($iStyles, $sClass, $bExtended, ByRef $aControls, $iControlsCount, $hControl)
;~ 	Local Const $GWL_STYLE = 0xFFFFFFF0

	Local Const $BS_AUTOCHECKBOX = 0x0003
	Local Const $BS_CHECKBOX = 0x0002
	Local Const $BS_GROUPBOX = 0x0007
	Local Const $BS_RADIOBUTTON = 0x0004
	Local Const $BS_AUTORADIOBUTTON = 0x0009
;~ 	Local Const $ES_MULTILINE = 4
	Local Const $ES_WANTRETURN = 4096
	Local Const $SS_ICON = 0x3
	Local Const $SS_BITMAP = 0xE
	Local Const $WS_VSCROLL = 0x00200000
	Local Const $ES_EDIT = BitOR($ES_WANTRETURN, $WS_VSCROLL)

	Switch $sClass
       	Case "Button"
           	If BitAND($iStyles, $BS_GROUPBOX) = $BS_GROUPBOX Then
               	Return "Group"
           	ElseIf BitAND($iStyles, $BS_CHECKBOX) = $BS_CHECKBOX Then
               	Return "Checkbox"
           	ElseIf BitAND($iStyles, $BS_AUTOCHECKBOX) = $BS_AUTOCHECKBOX Then
               	Return "Checkbox"
           	ElseIf BitAND($iStyles, $BS_RADIOBUTTON) = $BS_RADIOBUTTON Then
               	Return "Radio"
           	ElseIf BitAND($iStyles, $BS_AUTORADIOBUTTON) = $BS_AUTORADIOBUTTON Then
               	Return "Radio"
           	Else
               	Return "Button"
           	EndIf
       	Case "Static"
           	If BitAND($iStyles, $SS_ICON) = $SS_ICON Then
               	Return "Icon"
           	ElseIf BitAND($iStyles, $SS_BITMAP) = $SS_BITMAP Then
               	Return "Pic"
           	Else
               	Return "Label"
				If $bExtended = True Then $aControls[$iControlsCount][11] = ControlGetText($hControl, '', '')
           	EndIf
       	Case "Edit", "TPathPanel" ; Total Commander
           	If BitAND($iStyles, $ES_EDIT) = $ES_EDIT Then
               	Return "Edit"
           	Else
               	Return "Input"
           	EndIf
			If $bExtended = True Then $aControls[$iControlsCount][11] = ControlGetText($hControl, '', '')
       	Case "SysAnimate32"
           	Return "AVI"
       	Case "ComboBox", "TMyComboBox" ; Total Commander
           	Return "Combo"
			If $bExtended = True Then $aControls[$iControlsCount][11] = _GUICtrlComboBoxEx_GetList($hControl)
       	Case "SysDateTimePick32"
           	Return "Date"
       	Case "SysHeader32"
           	Return "Header"
       	Case "ListBox", "TMyListBox" ; Total Commander
           	Return "List"
			If $bExtended = True Then $aControls[$iControlsCount][11] = _WGC_GetListBoxItems($hControl)
       	Case "SysListView32"
           	Return "ListView"
			If $bExtended = True Then $aControls[$iControlsCount][11] = _WGC_GetListViewItems($hControl)
       	Case "SysMonthCal32"
           	Return "MonthCal"
       	Case "msctls_progress32"
           	Return "Progress"
       	Case "msctls_trackbar32"
           	Return "Slider"
       	Case "SysTabControl32", "SciTeTabCtrl" ; SciTE
           	Return "Tab"
       	Case "SysTreeView32"
           	Return "TreeView"
       	Case "msctls_updown32"
           	Return "UpDown"
		Case "msctls_statusbar32"
			Return "Statusbar"
       	Case Else
           	Return ""
	EndSwitch
EndFunc
