#include-once Global $VARIABLE_UDF_COMPILE If @Compiled And Not $VARIABLE_UDF_COMPILE Then MsgBox(0x30, 'Variable.au3 UDF', 'You have compiled your application with the Variable UDF included.' & @LF & 'If this was intentional, declare "Global $VARIABLE_UDF_COMPILE = True" above the #include.') ; #INDEX# ======================================================================================================================= ; Title .........: Variable ; AutoIt Version : 3.2.13.5+ ; Language ......: English ; Description ...: Functions for dumping variable information. ; Author(s) .....: Rob Saunders (rksaunders (at) gmail (dot) com) ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== ; _VarDump ; _ExprDump ; =============================================================================================================================== ; #INTERNAL_USE_ONLY#============================================================================================================ ; _VarDumpArray ; _VarDumpStruct ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name...........: _VarDump ; Description ...: This function returns information about a variable. Does not reset @error or @extended. ; Syntax.........: _VarDump(ByRef Const $vVar, $vDumpType = Default) ; Parameters ....: $vVar - The variable to analyze. ; $vDumpType - How to display the information. See Notes for keywords. ; Return values .: String: Information about the variable. This is returned regardless of the $vDumpType parameter. ; Author ........: Rob Saunders (rksaunders (at) gmail (dot) com) ; Remarks .......: $vVar is passed by reference. If you want to pass an expression use the wrapper function provided: _ExprDump() ; Use one of the following keywords for the $vDumpType parameter: ; 1, ConsoleWrite, Console, CW = ConsoleWrite() ; 2, MsgBox, Msg, Box, MB = MsgBox() ; 3, ToolTip, Tip, TT = ToolTip() ; 4, Clipboard, Clip, CB = ClipPut() ; 5, GUI, Window, Text = Display in an edit control in a GUI window created on the fly ; You can add an asterisk "*" to the keyword to also return @ScriptLineNumber, @error, and @extended values. ie: "cw*" ; =============================================================================================================================== Func _VarDump(ByRef Const $vVar, $vDumpType = '', $sIndent = '', $iLineNum = @ScriptLineNumber, $iError = @error, $iExtended = @extended) Local $sVarDump, $sVarInfo $vDumpType = StringReplace($vDumpType, '*', '') If @extended Then $sVarInfo = '*** Line: ' & $iLineNum & ', @error: ' & $iError & ', @extended: ' & $iExtended EndIf Local $sVarType = VarGetType($vVar) $sVarDump &= $sVarType Switch $sVarType Case 'Array' $sVarDump &= '(' & @CRLF & _VarDumpArray($vVar, $sIndent & @TAB) & @CRLF & $sIndent & ')' Case 'DllStruct' $sVarDump &= '(' & @CRLF & _VarDumpStruct($vVar, $sIndent & @TAB) & @CRLF & $sIndent & ')' Case 'Binary' $sVarDump &= '(' & BinaryLen($vVar) & ') ' & $vVar Case 'Object' $sVarDump &= '(' & ObjName($vVar) & ')' Case 'String' $sVarDump &= '(' & StringLen($vVar) & ') ' & $vVar Case Else If IsHWnd($vVar) Then $sVarDump &= '/HWnd' $sVarDump &= '(' & $vVar & ')' EndSwitch If $sVarInfo And StringRegExp($sVarDump, '[\r\n]') Then $sVarDump = $sVarInfo & @CRLF & $sVarDump ElseIf $sVarInfo Then $sVarDump = $sVarDump & ' ' & $sVarInfo EndIf Switch $vDumpType Case 1, 'ConsoleWrite', 'Console', 'CW' ConsoleWrite($sVarDump & @CRLF) Case 2, 'MsgBox', 'Msg', 'Box', 'MB' MsgBox(0x2040, 'VarDump', $sVarDump) Case 3, 'ToolTip', 'Tip', 'TT' ToolTip($sVarDump) Case 4, 'Clipboard', 'Clip', 'CB' ClipPut($sVarDump) Case 5, 'GUI', 'Window', 'Text' Local $iGUIOnEventMode = Opt('GUIOnEventMode', 0) Local $guiVarDump = GUICreate('VarDump', 300, 200, Default, Default, 0xCF0000) ; $WS_OVERLAPPEDWINDOW GUICtrlCreateEdit($sVarDump, 0, 0, 300, 200) GUICtrlSetResizing(-1, 102) ; $GUI_DOCKBORDERS GUISetState(@SW_SHOW, $guiVarDump) Do Until GUIGetMsg() = -3 ; $GUI_EVENT_CLOSE GUIDelete($guiVarDump) Opt('GUIOnEventMode', $iGUIOnEventMode) EndSwitch Return SetError($iError, $iExtended, StringReplace($sVarDump, Chr(0), ' ')) EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: _ExprDump ; Description ...: This function returns information about an expression/variable. Does not reset @error or @extended. ; Syntax.........: _ExprDump(ByRef $vVar, $vDumpType = Default) ; Parameters ....: $vVar - The variable/expression to analyze. ; $vDumpType - How to display the information. See _VarDump remarks for keywords. ; Return values .: String: Information about the expression/variable. This is returned regardless of the $vDumpType parameter. ; Author ........: Rob Saunders (rksaunders (at) gmail (dot) com) ; Remarks .......: If you want to analyze an expression instead of a variable use this function. Otherwise use _VarDump(). ; =============================================================================================================================== Func _ExprDump($vVar, $vDumpType = Default, $iLineNum = @ScriptLineNumber, $iError = @error, $iExtended = @extended) Local $vReturn = _VarDump($vVar, $vDumpType, '', $iLineNum, $iError, $iExtended) Return SetError(@error, @extended, $vReturn) EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name...........: _VarDumpArray ; Description ...: Details an array variable. ; Syntax.........: _VarDumpArray(ByRef Const $aArray) ; Parameters ....: $aArray - array to analyze. ; Return values .: String: Structured output of array contents. ; Author ........: Rob Saunders (rksaunders (at) gmail (dot) com) ; =============================================================================================================================== Func _VarDumpArray(ByRef Const $aArray, $sIndent = '') If Not IsArray($aArray) Then ; This should only happen if end user calls function directly on non-array Return $sIndent & '!! Variable is not array' EndIf Local $iDimensions = UBound($aArray, 0) ; How many dimensions in array If $iDimensions < 1 Then ; This should be impossible, but error check for safety ; -> As of 3.3.9.6 this (ie: Dim $array[0]) became possible Return $sIndent & '!! Array has 0 dimensions' EndIf Local $aIndexes[$iDimensions] ; Tracker for reading indexes Local $aUBounds[$iDimensions] ; List of dimension sizes For $i = 0 To $iDimensions - 1 $aIndexes[$i] = 0 $aUBounds[$i] = UBound($aArray, $i + 1) ; Store each dimension size If $aUBounds[$i] < 1 Then Return $sIndent & '!! Array dimension [' & $i + 1 & '] size is ' & $aUBounds[$i] EndIf Next Local $sArrayIndex ; Indexing string for individual item reading (ie: "[1][2][3]") Local $sArrayRead ; Value of array item Local $bDone ; Indicates if overall array has finished parsing Local $sDump ; Output string While 1 $bDone = True ; Default to true, flag false if dimension read is not done ; Reset and build indexing string $sArrayIndex = '' For $i = 0 To $iDimensions - 1 $sArrayIndex &= '[' & $aIndexes[$i] & ']' If $aIndexes[$i] < $aUBounds[$i] - 1 Then $bDone = False ; Indexing has not reached end of dimension: NOT done Next $sArrayRead = Execute('$aArray' & $sArrayIndex) ; Read the darn value already! If @error Then ; Item read failed, cancel the whole listing $sDump &= $sIndent & $sArrayIndex & ' !! Error reading index' ExitLoop Else ; Add the index and value to the output string $sDump &= $sIndent & $sArrayIndex & ' => ' & _VarDump($sArrayRead, '', $sIndent) If $bDone Then Return $sDump Else ; If not done, line break and loop again $sDump &= @CRLF EndIf EndIf ; Ok, I didn't comment this before and it took me forever to figure out what was going on so this is going to be verbose. ; The reason this FOR loop goes backwards is because it's stepping through the last dimension first and working it's way back. ; Just like when you increase a number, you increment the right-most digit first, ie: the "one's place". ; So for example, if we have an array of [X][X][X] - it starts with the third dimension [ ][ ][X] and steps through it one at a time, ; like this: [0][0][0], [0][0][1], [0][0][2], etc. If the index hasn't hit the dimension's ubound then the FOR loop exits, so all that ; gets incremented is that one dimension index. However, if it has met or exceeded that dimension's ubound, then it resets it to 0 and ; the FOR loop gets to continue to the next dimension up (ie: [ ][X][ ]), and now we get [0][1][0], [0][1][1], [0][1][2], etc. For $i = $iDimensions - 1 To 0 Step -1 $aIndexes[$i] += 1 If $aIndexes[$i] >= $aUBounds[$i] Then $aIndexes[$i] = 0 If $i = $iDimensions - 1 Then $sDump &= @CRLF ; The above line puts an extra line break between groups of the last dimension. ie: ; [0][0][0] => String(0) ; [0][0][1] => String(0) ; [0][0][2] => String(0) ; ; [0][1][0] => String(0) ; [0][1][1] => String(0) ; [0][1][2] => String(0) Else ExitLoop EndIf Next WEnd Return $sDump EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name...........: _VarDumpStruct ; Description ...: Details a struct variable. ; Syntax.........: VarDumpStruct(ByRef $tStruct) ; Parameters ....: $tStruct - struct to analyze. ; Return values .: String: Structured output of struct details/contents. ; Author ........: Rob Saunders (rksaunders (at) gmail (dot) com) ; =============================================================================================================================== Func _VarDumpStruct(ByRef Const $tStruct, $sIndent = '') Local $iElement = 1, $vRead, $vTest ; Do the initial $sDump contents - Standard fare for any struct Local $sDump = _ $sIndent & '[Size] => ' & DllStructGetSize($tStruct) & @CRLF & _ $sIndent & '[Ptr] => ' & DllStructGetPtr($tStruct) While 1 $vRead = DllStructGetData($tStruct, $iElement) If @error = 2 Then ExitLoop ; If we've overstepped $iElement we're done $vTest = VarGetType($vRead) If $vTest = 'String' Or $vTest = 'Binary' Then ; Test the vartype for String or Binary, in which case we dump now because we already have the full contents $sDump &= @CRLF & $sIndent & '[' & $iElement & '] => ' & _VarDump($vRead, '', $sIndent) Else ; Here we'll test to see if the element is an array by looking for an index of 2. DllStructGetData($tStruct, $iElement, 2) If @error Then ; @error means no index, which means no array, which means we can just dump the stored $vRead from above $sDump &= @CRLF & $sIndent & '[' & $iElement & '] => ' & _VarDump($vRead, '', $sIndent) Else ; If we get no @error then that means that index 2 was valid, so we'll just start from 1 and work our way up til we @error again Local $sSubDump, $iIndex = 1, $iCount = 0, $iNonEmpties = 0 While 1 $vRead = DllStructGetData($tStruct, $iElement, $iIndex) If @error Then ExitLoop ; And that's the limit of this array, so we're done. If $vRead Then ; We're skipping empty indices just to cut down on some of the clutter from large structs $sSubDump &= @CRLF & @TAB & $sIndent & '[' & $iIndex & '] => ' & _VarDump($vRead) $iNonEmpties += 1 EndIf $iIndex += 1 WEnd $iIndex -= 1 $sDump &= @CRLF & $sIndent & '[' & $iElement & '] => Array(' If $iNonEmpties < $iIndex Then $sDump &= @CRLF & $sIndent & @TAB & '> Skipping empty indices (' & ($iIndex-$iNonEmpties) & '/' & $iIndex & ')' EndIf $sDump &= $sSubDump & @CRLF & $sIndent & ')' EndIf EndIf $iElement += 1 WEnd Return $sDump EndFunc