#include-once #cs maps #AutoIt3Wrapper_Version=B ; beta 3.3.15.0 or greater is mandatory #ce maps ; #INDEX# ============================================================================================================ ; Title .........: cDebug ; AutoIt Version : v3.3.15.0 or higher ; Language ......: English ; Description ...: Dumps values of variables and expressions, with structure, to GUI, Console or Clipboard ; Remarks .......: ; Note ..........: See cDebug.pdf for documentation ; Version 1.15.3 ; Author(s) .....: c.haslam - thanks to jchd, Melba23, ProgAndy and Kafu ; ==================================================================================================================== ; #CURRENT# ========================================================================================================== ; _ClipDebug Dumps the values of variables and expressions to the Clipboard ; _ConsDebug Dumps the values of variables and expressions to the Console and Clipboard ; _FormatValsForDebug Dumps the values of variables and expressions to a @CRLF-delimted string ; _GuiDebug Dumps the values of variables and expressions to a GUI and Clipboard ; _ChangeElementLimitForDebug Sets maximum number of array and struct elements to display ; _MsgDebug (deprecated) Dumps the value of variables and expressions to a GUI and Clipboard ; ==================================================================================================================== ; #INTERNAL_USE_ONLY#================================================================================================= ; _cDebug_ArrayQuickSort1D ; _cDebug_AvoidHidingCodeInSciTE ; _cDebug_ComparePaddedTags ; _cDebug_DetectTag ; _cDebug_DlgChangeLimit ; _cDebug_DumpDetectedStruct ; _cDebug_DumpElementData ; _cDebug_DumpStr ; _cDebug_DumpStruct ; _cDebug_DumpUserStruct ; _cDebug_EvaluateGlobalVar ; _cDebug_Example ; _cDebug_ExpandSliceSubscripts ; _cDebug_ExpandSliceSubscripts_From ; _cDebug_ExpandSliceSubscripts_FromTo ; _cDebug_ExpandSliceSubscripts_Periods ; _cDebug_ExpandSliceSubscripts_To ; _cDebug_ExpandSliceSubscripts_VarOrVal ; _cDebug_FmtNameVal ; _cDebug_FmtNameVal_2dArraySlice ; _cDebug_FmtNameVal_3dArraySlice #cs maps ; _cDebug_FmtNameVal_MapSlice ; _cDebug_FmtNameVal_WholeMap #ce maps ; _cDebug_FmtNameVal_VectorSlice ; _cDebug_FmtNameVal_Whole2dArray ; _cDebug_FmtNameVal_Whole3dArray ; _cDebug_FmtNameVal_WholeVector ; _cDebug_GetPosOfFirstUnquotedStringInString ; _cDebug_GetValOfSubscriptVarOrConst ; _cDebug_GetValOfSubscriptVarOrConst_Verify ; _cDebug_GUICtrlGetFont #cs maps ; _cDebug_MapKeys #ce maps ; _cDebug_OutputStructNote ; _cDebug_ParseTag ; _cDebug_ReportCodingErrorAndExit ; _cDebug_ReportErrorAndExit ; _cDebug_ReportScalar ; _cDebug_ReportTypeAndValue ; _cDebug_ReportWarning #cs maps ; _cDebug_SortMapKeys #ce maps ; _cDebug_StringSize ; _cDebug_StringSize_DefaultFontName ; _cDebug_StringSize_Error_Close ; _cDebug_StringSplitonUnquotedString ; _cDebug_UpdateClipboard ; _cDebug_UpdateListOfDllElements ; _cDebug_VarSizeDialog ; ==================================================================================================================== #include #include #include #include #include #include #include Opt("MustDeclareVars",1) Opt("TrayIconDebug",1) OnAutoItExitRegister('_cDebug_FinishUp') ; External If IsDeclared('g_cDebug_ShowStructComparisonAlways')=$DECLARED_UNKNOWN Then Global $g_cDebug_ShowStructComparisonAlways = True EndIf If IsDeclared('g_cDebug_elementLimitDefault')=$DECLARED_UNKNOWN Then Global $g_cDebug_elementLimitDefault = 30 EndIf If IsDeclared('g_cDebug_bRetainElementLimit')=$DECLARED_UNKNOWN Then Global $g_cDebug_bRetainElementLimit = True EndIf ;~ Global $g_cDebug_bRetainElementLimit = True If IsDeclared('g_cDebug_LargeElementLimit')=$DECLARED_UNKNOWN Then Global $g_cDebug_LargeElementLimit = 1000 EndIf ;~ Global $g_cDebug_LargeElementLimit = 1000 If IsDeclared('g_cDebug_Indent')=$DECLARED_UNKNOWN Then Global $g_cDebug_Indent = 6 EndIf ;~ Global $g_cDebug_Indent = 6 If IsDeclared('g_cDebug_stringDelim')=$DECLARED_UNKNOWN Then Global $g_cDebug_stringDelim = "'" EndIf ;~ Global $g_cDebug_stringDelim = "'" If IsDeclared('g_cDebug_bDoLineBreaksInStrings')=$DECLARED_UNKNOWN Then Global $g_cDebug_bDoLineBreaksInStrings = True EndIf ;~ Global $g_cDebug_bDoLineBreaksInStrings = True If IsDeclared('$g_cDebug_iniFolder')=$DECLARED_UNKNOWN Then Global $g_cDebug_iniFolder = '' ; default: where your script resides EndIf ;~ Global $g_cDebug_iniFolder = '' ; default: where your script resides If IsDeclared('g_cDebug_bAlwaysAskClearClipboard')=$DECLARED_UNKNOWN Then Global $g_cDebug_bAlwaysAskClearClipboard = False EndIf ; Internal If $g_cDebug_Indent<1 Or $g_cDebug_Indent>9 Then MsgBox($MB_TASKMODAL,'cDebug error','$g_cDebug_Indent must be between 1 and 9') Exit EndIf Global $g_cDebug_tab = StringFormat('%'&$g_cDebug_Indent&'s','') Global $g_cDebug_identsVec[3] Global $g_cDebug_namesVec[0],$g_cDebug_valsVec[0] Global $g_cDebug_sStructElementTypes='',$g_cDebug_bCompareStructs Global $g_cDebug_elementLimit Global $g_cDebug_iniFS Global $g_cDebug_bMainUDFcalled=False Global $g_cDebug_bMultiLevel=False,$g_cDebug_nMultiLevels If $g_cDebug_iniFolder='' Then $g_cDebug_iniFS = 'cDebug.ini' Else DirGetSize($g_cDebug_iniFolder) If @error Then MsgBox($MB_TASKMODAL,'cDebug error', _ 'Attempt to specify non-existent folder "'&$g_cDebug_iniFolder&'" as location for cDebug.ini') Exit EndIf If StringRight($g_cDebug_iniFolder,1)='\' Then $g_cDebug_iniFS = $g_cDebug_iniFolder&'cDebug.ini' Else $g_cDebug_iniFS = $g_cDebug_iniFolder&'\cDebug.ini' EndIf EndIf If $g_cDebug_bRetainElementLimit Then If FileExists($g_cDebug_iniFS) Then $g_cDebug_elementLimit = Int(IniRead($g_cDebug_iniFS,'ElementLimit','Quantity',$g_cDebug_elementLimit)) Else $g_cDebug_elementLimit = $g_cDebug_elementLimitDefault EndIf Else $g_cDebug_elementLimit = $g_cDebug_elementLimitDefault If FileExists($g_cDebug_iniFS) Then FileDelete($g_cDebug_iniFS) EndIf EndIf ; Modified from _WinAPI_DisplayStruct Thanks to Yashied, jpm ; Local Enum $eTqUtype=0,$eTqSize,$eTqSigned,$eTqDtype Global Const $g_cDebug_typeQuantumSignedsAr = _ ;[29][4] = _ [['byte',1,False,'byte'],['boolean',1,False,'byte'],['char', 1,False,'char'],['wchar', 2,False,'wchar'], _ ['short',2,True,'short'], ['ushort', 2,False,'ushort'],['word', 2,False,'ushort'],['int', 4,True,'int'], _ ['long',4,True,'uint'],['bool',4,True,'int'],['uint',4,False,'uint'],['ulong', 4,False,'uint'], _ ['dword',4,False,'uint'],['int64',8,True,'int64'], _ ['uint64', 8,False,'int64'],['ptr',@AutoItX64 ? 8: 4,False,'ptr'],['hwnd',@AutoItX64 ? 8 : 4,False,'ptr'], _ ['handle', @AutoItX64 ? 8 : 4,False,'ptr'],['float', 4,True,'float'],['double', 8,True,'double'], _ ['int_ptr',@AutoItX64 ? 8 : 4,True,'int'], _ ['long_ptr',@AutoItX64 ? 8 : 4,True,'int'],['lresult', @AutoItX64 ? 8 : 4,True,'int'], _ ['lparam', @AutoItX64 ? 8 : 4,True,'lparam'], _ ['uint_ptr',@AutoItX64 ? 8 : 4,False,'uint'],['ulong_ptr', @AutoItX64 ? 8 : 4,False,'uint'], _ ['dword_ptr',@AutoItX64 ? 8 : 4,False,'uint'],['wparam',@AutoItX64 ? 8 : 4,False,'uint'], _ ['ubyte',1,False,'byte']] ; #FUNCTION# ==================================================================================================================== ; Name ..........: _ConsDebug ; Description ...: Dumps the value of variables and expressions to the Console ; Syntax ........: _ConsDebug($location, $names, $val1 [, $val2 [, $val3 [, $val4 [, $val5 [, ; $val6 [, $val7 [, $val8 [, $val9 [, $val10 [, $val11 [, $val12 [, $val13 ,[ ; $val14 ,[ $val15 [, $val16 [, $val17 [, $val18 [, $val19]]]]]]]]]]]]]]]]]] ) ; Parameters ....: $location - a string: title ; If ^ is in the string, the dump is also sent to the Clipboard ; $names - comma-separted names to be shown in the dump, one per value ; If | is the first character, dumped strings start and end with ; Char(166), a broken bar ; '[controls][:]name1,name2, ...' ; $val1 - a variant value. ; $val2 thru $val19 - [optional] a variant value. Default is not used ; Return values .: None ; Author ........: c.haslam at ieee dot org ; Modified ......: ; Remarks .......See cDebug.pdf for details of functionality ; Related .......: _MsgDebug,_ClipDebug ; Link ..........: ; Example .......: _ConsDebug('Line '&@ScriptLineNumber','$bInt,$ar,StringInStr($str,":")',$bInt,$ar,StringInStr($str,':')) ; =============================================================================================================================== Func _ConsDebug($location,$names,$val1,$val2=1e308,$val3=1e308,$val4=1e308,$val5=1e308,$val6=1e308,$val7=1e308,$val8=1e308 _ ,$val9=1e308,$val10=1e308,$val11=1e308,$val12=1e308,$val13=1e308,$val14=1e308,$val15=1e308,$val16=1e308,$val17=1e308, _ $val18=1e308,$val19=1e308) Local $bToClipboard = StringInStr($location,'^')<>'' If $bToClipboard Then $location = StringReplace($location,'^','') ; all EndIf $g_cDebug_bCompareStructs = True Local $t = '***'&$location&'-------------------------'&@CRLF& _ _FormatValsForDebug($location,$names,$val1,$val2,$val3,$val4,$val5,$val6,$val7,$val8, _ $val9,$val10,$val11,$val12,$val13,$val14,$val15,$val16,$val17,$val18,$val19) ConsoleWrite($t) If $bToClipboard Then _cDebug_UpdateClipboard($t) EndIf EndFunc ; #FUNCTION# ==================================================================================================================== ; Name ..........: _ClipDebug ; Description ...: Dumps the value of variables and expressions to the Clipboard ; Syntax ........: _ClipDebug($location, $names, $val1 [, $val2 [, $val3 [, $val4 [, $val5 [, ; $val6 [, $val7 [, $val8 [, $val9 [, $val10 [, $val11 [, $val12 [, $val13 ,[ ; $val14 ,[ $val15 [, $val16 [, $val17 [, $val18 [, $val19]]]]]]]]]]]]]]]]]] ) ; Parameters ....: $location - a string: title ; If ^ is in the string, it is ignored ; $names - comma-separted names to be shown in the dump, one per value ; If | is the first character, dumped strings start and end with ; Char(166), a broken bar ; '[controls][<title>:]name1,name2, ...' ; $val1 - a variant value. ; $val2 thru $val19 - [optional] a variant value. Default is not used ; Return values .: None ; Author ........: c.haslam at ieee dot org ; Modified ......: ; Remarks .......: See _ConsDebug() ; Related .......: _MsgDebug,_ConsDebug ; Link ..........: ; Example .......: _ClipDebug('Line '&@ScriptLineNumber&','$bInt,$ar,StringLen($str)',$bInt,$ar,StringILen($str)) ; =============================================================================================================================== Func _ClipDebug($location,$names,$val1,$val2=1e308,$val3=1e308,$val4=1e308,$val5=1e308,$val6=1e308,$val7=1e308,$val8=1e308 _ ,$val9=1e308,$val10=1e308,$val11=1e308,$val12=1e308,$val13=1e308,$val14=1e308,$val15=1e308,$val16=1e308,$val17=1e308, _ $val18=1e308,$val19=1e308) $location = StringReplace($location,'^','') ; all $g_cDebug_bCompareStructs = True Local $t = '***'&$location&'-------------------------'&@CRLF& _ _FormatValsForDebug($location,$names,$val1,$val2,$val3,$val4,$val5,$val6,$val7,$val8, _ $val9,$val10,$val11,$val12,$val13,$val14,$val15,$val16,$val17,$val18,$val19) _cDebug_UpdateClipboard($t) EndFunc ; #FUNCTION# ==================================================================================================================== ; Name ..........: _GuiDebug ; Description ...: Dumps the value of variables and expressions to a GUI ; Syntax ........: _GuiDebug($location, $names, $val1 [, $val2 [, $val3 [, $val4 [, $val5 [, ; $val6 [, $val7 [, $val8 [, $val9 [, $val10 [, $val11 [, $val12 [, $val13 ,[ ; $val14 ,[ $val15 [, $val16 [, $val17 [, $val18 [, $val19]]]]]]]]]]]]]]]]]] ) ; Parameters ....: $location - a string: title ; If ^ is in the string, the dump is also sent to the Clipboard ; $names - comma-separted names to be shown in the dump, one per value ; If | is the first character, dumped strings start and end with ; Char(166), a broken bar ; '[controls][<title>:]name1,name2, ...' ; $val1 - a variant value. ; $val2 thru $val19 - [optional] a variant value. Default is not used ; Return values .: None ; Author ........: c.haslam at ieee dot org ; Modified ......: ; Remarks .......: See _ConsDebug() ; Related .......: _MsgDebug, _ConsDebug, _ClipDebug, _FormatValsForDebug ; Link ..........: ; Example .......: _GuiDebug('Line '&@ScriptLineNumber&':'$bInt,$ar,StringLen($str)',$bInt,$ar,StringLen($str)) ; =============================================================================================================================== Func _GuiDebug($location,$names,$val1,$val2=1e308,$val3=1e308,$val4=1e308,$val5=1e308,$val6=1e308,$val7=1e308,$val8=1e308 _ ,$val9=1e308,$val10=1e308,$val11=1e308,$val12=1e308,$val13=1e308,$val14=1e308,$val15=1e308,$val16=1e308,$val17=1e308, _ $val18=1e308,$val19=1e308) Local $n Local $bToClipboard = StringInStr($location,'^')<>'' If $bToClipboard Then $location = StringReplace($location,'^','') ; all EndIf Local $bEndit If $g_cDebug_elementLimit=0 Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,'$g_cDebug_elementLimit=0') ElseIf $g_cDebug_elementLimit='' Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,"$g_cDebug_elementLimit=''") EndIf Local $oldElLimit = $g_cDebug_elementLimit Local $text $bEndit =False Local $bChanged = True $g_cDebug_bCompareStructs = True While (Not $bEndit) Or $bChanged If $bChanged Then $text = _FormatValsForDebug($location,$names,$val1,$val2,$val3,$val4,$val5,$val6,$val7,$val8, _ $val9,$val10,$val11,$val12,$val13,$val14,$val15,$val16,$val17,$val18,$val19) $g_cDebug_bCompareStructs = False EndIf $n = $oldElLimit $bEndit = _cDebug_VarSizeDialog($location,$text,'le',$n) ; Change element limit $bChanged = $n<>$oldElLimit If $bChanged Then $oldElLimit = $n $g_cDebug_ElementLimit = $n EndIf WEnd If $g_cDebug_elementLimit=0 Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,'$g_cDebug_elementLimit=0') ElseIf $g_cDebug_elementLimit='' Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,"$g_cDebug_elementLimit=''") EndIf EndFunc Func _cDebug_FinishUp() ; Prevent cDebug.ini being create/updated if user does F5 rather than Ctrl_F5 when cDebug*.ini is active in SciTE If StringLeft(@ScriptName,6)='cDebug' Then Return If $g_cDebug_bMainUDFcalled And $g_cDebug_bRetainElementLimit Then If $g_cDebug_elementLimit=0 Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,'$g_cDebug_elementLimit=0') ElseIf $g_cDebug_elementLimit='' Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,"$g_cDebug_elementLimit=''") EndIf If FileExists($g_cDebug_iniFS) Then Local $n = Int(IniRead($g_cDebug_iniFS,'ElementLimit','Quantity',-1)) If $g_cDebug_elementLimit<>$n Then IniWrite($g_cDebug_iniFS,'ElementLimit','Quantity',$g_cDebug_elementLimit) EndIf Else IniWrite($g_cDebug_iniFS,'ElementLimit','Quantity',$g_cDebug_elementLimit) EndIf EndIf EndFunc ; #FUNCTION# ==================================================================================================================== ; Name ..........: _MsgDebug ; Description ...: Dumps the value of variables and expressions to a GUI ; Syntax ........: _MsgDebug($location, $names, $val1 [, $val2 [, $val3 [, $val4 [, $val5 [, ; $val6 [, $val7 [, $val8 [, $val9 [, $val10 [, $val11 [, $val12 [, $val13 ,[ ; $val14 ,[ $val15 [, $val16 [, $val17 [, $val18 [, $val19]]]]]]]]]]]]]]]]]] ) ; Parameters ....: $location - a string: title ; If ^ is in the string, the dump is also sent to the Clipboard ; $names - comma-separted names to be shown in the dump, one per value ; If | is the first character, dumped strings start and end with ; Char(166), a broken bar ; '[controls][<title>:]name1,name2, ...' ; $val1 - a variant value. ; $val2 thru $val19 - [optional] a variant value. Default is not used ; Return values .: None ; Author ........: c.haslam at ieee dot org ; Modified ......: ; Remarks .......: See _ConsDebug() ; Related .......: _GuiDebug, _ConsDebug, _ClipDebug, _FormatValsForDebug ; Link ..........: ; Example .......: _MsgDebug('Line '&@ScriptLineNumber&':'$bInt,$ar,StringLen($str)',$bInt,$ar,StringLen($str)) ; =============================================================================================================================== Func _MsgDebug($location,$names,$val1,$val2=1e308,$val3=1e308,$val4=1e308,$val5=1e308,$val6=1e308,$val7=1e308,$val8=1e308 _ ,$val9=1e308,$val10=1e308,$val11=1e308,$val12=1e308,$val13=1e308,$val14=1e308,$val15=1e308,$val16=1e308,$val17=1e308, _ $val18=1e308,$val19=1e308) _GuiDebug($location,$names,$val1,$val2,$val3,$val4,$val5,$val6,$val7,$val8,$val9,$val10,$val11, _ $val12,$val13,$val14,$val15,$val16,$val17,$val18,$val19) EndFunc ; #FUNCTION# ==================================================================================================================== ; Name ..........: _FormatValsForDebug ; Description ...: Dumps the value of variables and expressions to a @CRLF-delimted string ; Syntax ........: _FormatValsForDebug($location, $names, $val1 [, $val2 [, $val3 [, $val4 [, $val5 [, ; $val6 [, $val7 [, $val8 [, $val9 [, $val10 [, $val11 [, $val12 [, $val13 ,[ ; $val14 ,[ $val15 [, $val16 [, $val17 [, $val18 [, $val19]]]]]]]]]]]]]]]]]] ) ; Parameters ....: $location - a string: title ; If ^ is in the string, the dump is also sent to the Clipboard ; $names - comma-separted names to be shown in the dump, one per value ; If | is the first character, dumped strings start and end with ; Char(166), a broken bar ; '[controls][<title>:]name1,name2, ...' ; $val1 - a variant value. ; $val2 thru $val19 - [optional] a variant value. Default is not used ; Return values .: None ; Author ........: c.haslam ; Modified ......: ; Remarks .......: See _ConsDebug() ; Related .......: _GuiDebug, _ConsDebug, _ClipDebug, _MsgDebug ; Link ..........: ; Example .......: __FormatValsForDebug('Line '&@ScriptLineNumber&':'$bInt,$ar,StringLen($str)',$bInt,$ar,StringLen($str)) ; =============================================================================================================================== Func _FormatValsForDebug($location,$names,$val1,$val2=1e308,$val3=1e308,$val4=1e308,$val5=1e308,$val6=1e308,$val7=1e308,$val8=1e308 _ ,$val9=1e308,$val10=1e308,$val11=1e308,$val12=1e308,$val13=1e308,$val14=1e308,$val15=1e308,$val16=1e308,$val17=1e308, _ $val18=1e308,$val19=1e308) Local $pos $g_cDebug_stringDelim = "'" ReDim $g_cDebug_namesVec[0] ReDim $g_cDebug_valsVec[0] $g_cDebug_identsVec[2] = '' $g_cDebug_sStructElementTypes = '' $g_cDebug_identsVec[0] = $location $g_cDebug_identsVec[1] = $names If VarGetType($names)<>'String' Then _cDebug_ReportErrorAndExit('The second argument, $names, must be a string') EndIf ;~ If StringLeft($names,1)=',' Then $names = StringMid($names,2) ; tolerate leading comma If $names="" Then _cDebug_ReportErrorAndExit('The second argument, $names, is empty') ;~ _cDebug_ReportErrorAndExit('Names element is empty') EndIf If StringLeft($names,1)='|' Then $g_cDebug_stringDelim = Chr(166) ; broken bar $names = StringMid($names,2) EndIf If VarGetType($names)<>'String' Then _cDebug_ReportErrorAndExit('The $names argument must be a string') EndIf If $names="" Then _cDebug_ReportErrorAndExit('Variable names are missing') EndIf Local $nParLvl,$nBrLvl,$ch,$j,$n,$t,$bInCurly,$i $names &= ',' $i = 0 While True $i += 1 If $i>StringLen($names) Then ExitLoop EndIf $ch = StringMid($names,$i,1) Switch $ch Case '"',"'" $n = StringInStr($names,$ch,0,1,$i+1) ; case_insens,first,start at $i+1 If $n = 0 Then $t = $ch='"' ? "'" : '"' _cDebug_ReportErrorAndExit('Matching '&$t&$ch&$t&' not found') EndIf $i = $n Case '{' If $bInCurly Then _cDebug_ReportErrorAndExit('Two {s') EndIf $bInCurly = True Case '}' If Not $bInCurly Then _cDebug_ReportErrorAndExit('} without preceding {') EndIf $bInCurly = False Case '(' $nParlvl += 1 Case ')' $nParLvl -= 1 If $nParLvl<0 Then _cDebug_ReportErrorAndExit('Attempt to close parentheses that are not open') EndIf Case '[' $nBrLvl += 1 Case ']' $nBrLvl -= 1 If $nBrLvl<0 Then _cDebug_ReportErrorAndExit('Attempt to close square brackets that are not open') EndIf Case ',' If $nParLvl=0 And $nBrLvl=0 And Not $bInCurly Then $n = UBound($g_cDebug_namesVec) ReDim $g_cDebug_namesVec[$n+1] If $i=1 Then _cDebug_ReportErrorAndExit('A name element is missing') EndIf $g_cDebug_namesVec[$n] = StringLeft($names,$i-1) $names = StringMid($names,$i+1) If $names='' Then ExitLoop EndIf $i = 0 EndIf EndSwitch WEnd If $bInCurly Then _cDebug_ReportErrorAndExit('{ not closed') EndIf If $nParLvl>0 Then _cDebug_ReportErrorAndExit('( not closed') EndIf If $nBrLvl>0 Then _cDebug_ReportErrorAndExit('[ not closed') EndIf Local $vec = [$val1,$val2,$val3,$val4,$val5,$val6,$val7,$val8,$val9,$val10,$val11,$val12, _ $val13,$val14,$val15,$val16,$val17,$val18,$val19] For $i = 0 To UBound($vec) If IsFloat($vec[$i]) And $vec[$i]=1e308 Then ExitLoop EndIf Next ReDim $vec[$i] $g_cDebug_valsVec = $vec $names = StringStripWS($names,1+2) ; left and right If StringLeft($names,1)=',' Then _cDebug_ReportErrorAndExit('The names argument begins with a comma') EndIf If StringRight($names,1)=',' Then _cDebug_ReportErrorAndExit('The names argument ends with a comma') EndIf If UBound($g_cDebug_valsVec)>UBound($g_cDebug_namesVec) Then $t = 'There are more value arguments than names, so values of some value arguments '& _ 'will not be reported' _cDebug_ReportWarning($t) EndIf If UBound($g_cDebug_valsVec)<UBound($g_cDebug_namesVec) Then _cDebug_ReportErrorAndExit('There are more names than value arguments') EndIf Local $tagsVec[UBound($g_cDebug_namesVec)] For $i = 0 To UBound($g_cDebug_namesVec)-1 $pos = StringInStr($g_cDebug_namesVec[$i],'{') If $pos<>0 Then $tagsVec[$i] = StringTrimRight(StringMid($g_cDebug_namesVec[$i],$pos+1),1) If StringLeft($tagsVec[$i],1)='!' Then $t = StringTrimLeft($tagsVec[$i],1) Else $t = $tagsVec[$i] EndIf DllStructCreate($t) If @error Then _cDebug_ReportErrorAndExit('Invalid tag: "'&$tagsVec[$i]&'"') Else $t = 0 ; release memory EndIf $g_cDebug_namesVec[$i] =StringMid($g_cDebug_namesVec[$i],1,$pos-1) EndIf Next Local $ret='' For $i = 0 To UBound($g_cDebug_namesVec)-1 $g_cDebug_identsVec[2] = $g_cDebug_namesVec[$i] $g_cDebug_bMultiLevel = _cDebug_GetPosOfFirstUnquotedStringInString($g_cDebug_namesVec[$i],'->')<>0 $ret &= _cDebug_FmtNameVal($location,$g_cDebug_tab,$g_cDebug_namesVec[$i],$g_cDebug_valsVec[$i], _ $tagsVec[$i]) Next $ret = StringTrimRight($ret,2) ; drop @CRLF at end $ret &= _cDebug_OutputStructNote() $g_cDebug_bMainUDFcalled = True Return $ret EndFunc Func _cDebug_FmtNameVal($location,$indent,$wholeName,$val,$tag) Local $ret,$p,$name,$restName,$vec,$t,$b,$m Local $curlvl If $g_cDebug_bMultiLevel Then If $indent=$g_cDebug_tab Then ; if called by _FormatValsForDebug() $g_cDebug_nMultiLevels = UBound(StringSplit($wholeName,'->',1+2)) EndIf EndIf If $g_cDebug_bMultiLevel Then $p = _cDebug_GetPosOfFirstUnquotedStringInString($wholeName,'->') If $p<>0 Then $name = StringLeft($wholeName,$p-1) $restName = StringMid($wholeName,$p+2) Else $name = $wholeName $restName = '' EndIf If $indent=$g_cDebug_tab Then ; if called by _FormatValsForDebug() $ret &= $wholeName&@CRLF EndIf Else If IsArray($val) Or _cDebug_IsMap($val) Then $name = $wholeName Else $name = '' EndIf $restName = '' If $indent=$g_cDebug_tab Then ; if called by _FormatValsForDebug() If IsArray($val) Or _cDebug_IsMap($val) Then $ret &= $wholeName&@CRLF Else $ret &= $wholeName EndIf EndIf EndIf ; A partial vector, array or map has [ ]s in $name Local $brsVec = StringSplit($name,'[]',0+2) ; char,0-based [0]: name, [1] ist subscript, [3] 2nd Local $qNameDims = Floor(UBound($brsVec)/2) If $qNameDims>3 Then _cDebug_ReportErrorAndExit('Name '&$name&' has more than 3 dimensions') EndIf Local $sub If IsArray($val) Then Switch UBound($val,0) ; quantity of subscripts Case 3 If $qNameDims=0 Then $ret &= _cDebug_FmtNameVal_Whole3dArray($location,$indent,$name,$restName,$val,$tag) ElseIf $qNameDims=2 Then _cDebug_ReportErrorAndExit('Name '&$name&' expects a 2-d array value but value is a 3-d array') ElseIf $qNameDims=1 Then _cDebug_ReportErrorAndExit('Name '&$name&' expects a 1-d array value but value is a 3-d array') Else $ret &= _cDebug_FmtNameVal_3dArraySlice($location,$indent,$name,$restName,$val,$tag) EndIf Case 2 If $qNameDims=0 Then $ret &= _cDebug_FmtNameVal_Whole2dArray($location,$indent,$name,$restName,$val,$tag) ElseIf $qNameDims=3 Then _cDebug_ReportErrorAndExit('Name '&$name&' expects a 3-d array value but value is a 2-d array') ElseIf $qNameDims=1 Then _cDebug_ReportErrorAndExit('Name '&$name&' expects a 1-d array value but value is a 2-d array') Else $ret &= _cDebug_FmtNameVal_2dArraySlice($location,$indent,$name,$restName,$val,$tag) EndIf Case 1 If $qNameDims=0 Then $ret &= _cDebug_FmtNameVal_WholeVector($location,$indent,$name,$restName,$val,$tag) ElseIf $qNameDims=3 Then _cDebug_ReportErrorAndExit('Name '&$name&' expects 3-d array value but value is a 1-d array') ElseIf $qNameDims=2 Then _cDebug_ReportErrorAndExit('Name '&$name&' expects 2-d array value but value is a 1-d array') Else $sub = _cDebug_FmtNameVal_VectorSlice($location,$indent,$name,$restName,$val,$tag) If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $ret &= $sub EndIf EndIf Case Else _cDebug_ReportErrorAndExit('The value for '&$name&' has '&UBound($val,0)&' dimensions. '& _ 'cDebug''s limit is 3') EndSwitch #cs maps ElseIf IsMap($val) Then If $qNameDims=1 Then $ret &= _cDebug_FmtNameVal_MapSlice($location,$indent,$name,$restName,$val,$tag) ElseIf $qNameDims=3 Then _cDebug_ReportErrorAndExit('Value is a map, but name has 3 pairs of square brackets') ElseIf $qNameDims=2 Then _cDebug_ReportErrorAndExit('Value is a map, but name has 2 pairs of square brackets') Else $ret &= _cDebug_FmtNameVal_WholeMap($location,$indent,$name,$restName,$val,$tag) EndIf #ce maps Else If $g_cDebug_bMultiLevel Then $curlvl = Int(StringLen($indent)/StringLen($g_cDebug_tab)) If $curlvl<=$g_cDebug_nMultiLevels Then ; if terminates before $names exhausted Return '' Endif EndIf $t = $indent=$g_cDebug_tab ? ' => ' : '' ; if called by _FormatValsForDebug() $ret &= _cDebug_ReportScalar($name&$t,$val,$tag)&@CRLF EndIf If $indent=$g_cDebug_tab Then If $g_cDebug_bMultiLevel And $ret=$wholeName&@CRLF Then $ret &= '-- no matches with element limit of '&$g_cDebug_ElementLimit&' --' EndIf $ret &= @CRLF EndIf Return $ret EndFunc #cs maps Func _cDebug_FilterMap($subscript,$name,$map) If StringInStr($subscript,'regexp:') Then If StringLen($subscript)>7 Then Local $regexp = StringMid($subscript,8) Local $tmap[] Local $mapKeys = _cDebug_MapKeys($map,@ScriptLineNumber) For $key In $mapKeys If StringRegExp($key,$regexp,0) Then $tmap[$key] = $map[$key] EndIf Next Else _cDebug_ReportErrorAndExit('"regexp:" requires a regular expression') EndIf Else Local $vec = _cDebug_StringSplitonUnquotedString($subscript,',') Local $userNumExprsVec[UBound($vec)],$userStrExprsVec[UBound($vec)],$ubN=0,$ubS=0 Local $chL,$chR For $i = 0 To UBound($vec)-1 $vec[$i] = StringStripWS($vec[$i],1+2) ; left,right $chL = StringLeft($vec[$i],1) $chR = StringRight($vec[$i],1) If $chL='"' Or $chL="'" Or $chR='"' Or $chR="'" Then $userStrExprsVec[$ubS] = $vec[$i] $ubS += 1 Else $userNumExprsVec[$ubN] = $vec[$i] $ubN += 1 EndIf Next ReDim $userNumExprsVec[$ubN] ReDim $userStrExprsVec[$ubS] Local $keysVec = _cDebug_MapKeys($map,@ScriptLineNumber) Local $numKeysVec[UBound($keysVec)],$strKeysVec[UBound($keysVec)] $ubN = 0 $ubS = 0 For $i=0 To UBound($KeysVec)-1 If VarGetType($KeysVec[$i])='String' Then $strKeysVec[$ubS] = $KeysVec[$i] $ubS += 1 Else $numKeysVec[$ubN] = $KeysVec[$i] $ubN += 1 EndIf Next ReDim $numKeysVec[$ubN] ReDim $strKeysVec[$ubS] Local $tmap[],$expr Local $allUserIxsVec[0],$allNumIxsVec[0] If UBound($userNumExprsVec)<>0 Then _cDebug_ArrayQuickSort1D($numKeysVec,0,UBound($numKeysVec)-1,0) $expr = '' For $i = 0 To UBound($userNumExprsVec)-1 $expr &= ','&$userNumExprsVec[$i] Next $expr = StringMid($expr,2) _cDebug_ExpandSliceSubscripts($expr,0,'key',$name,'mn', _ $numKeysVec, $allUserIxsVec, $allNumIxsVec) For $i = 0 To UBound($allUserIxsVec)-1 $tmap[$allUserIxsVec[$i]] = $map[$allNumIxsVec[$i]] Next EndIf If UBound($userStrExprsVec)<>0 Then _cDebug_ArrayQuickSort1D($strKeysVec,0,UBound($strKeysVec)-1,0) $expr = '' For $i = 0 To UBound($userStrExprsVec)-1 $expr &= ','&$userStrExprsVec[$i] Next $expr = StringMid($expr,2) Local $uVec[0],$nVec[0] _cDebug_ExpandSliceSubscripts($expr,0,'key',$name,'ms', $strKeysVec, $uVec, $nVec) For $i = 0 To UBound($uVec)-1 $tmap[$uVec[$i]] = $map[$nVec[$i]] Next EndIf EndIf Return $tmap EndFunc #ce maps ; $opBtns: ; 'l' Change element limit ; 'e' Exit script Func _cDebug_VarSizeDialog($title,$text,$optBtns, ByRef $elLimit) Local $n,$widDelta Local $fontNameEdt = 'Lucida Console' Local $fontSize = 8.5 Local $fontWeightEdt = 400 ;~ _StringSize($sText[, $iSize[, $iWeight[, $iAttrib[, $sName[, $iWidth[, $hWnd]]]]]] Local $vec = _cDebug_StringSize($text&@CRLF&@CRLF&@CRLF,$fontSize,$fontWeightEdt,0,$fontNameEdt,0,0) Local $widText = $vec[2] Local $htText = $vec[3]*1.05 ; kludge Local $widEdt = $widText + 20 + 10 ; kludge! Local $widBtns = (552-256) + 49 If $widEdt<$widBtns Then $widEdt = $widBtns Local $widClient = $widEdt + 20 Local $hwin = GUICreate('temp') Local $lbl = GUICtrlCreateLabel('tmep',1,1) Local $vec = _cDebug_GUICtrlGetFont($lbl) Local $fontNameTit = $vec[3] Local $fontSizeTit = $vec[0] GUIDelete($hwin) $vec = _cDebug_StringSize($title&'',$fontSizeTit,700,0,$fontNameTit,0,0); font size is a guess! bolded Local $widTitle = $vec[2] If $widTitle+80>$widClient Then Local $deltaTit = $widTitle+80 - $widClient $widEdt += $deltaTit $widClient += $deltaTit EndIf Local $leftOK = 10 + $widEdt - 49 Local $leftCopy = $leftOK - (552 - 472) If StringInStr($optBtns,'e') Then Local $leftExit = $leftCopy - (472 - 392) Else Local $leftExit = 0 EndIf If StringInStr($optBtns,'l') Then Local $leftLimit = $leftExit - (392 - 256) Else Local $leftLimit = 0 EndIf Local $widWin = $widClient + 10 If $widWin>@DesktopWidth Then $widDelta = $widWin - @DesktopWidth $widEdt -= $widDelta $widClient -= $widDelta $leftOK -= $widDelta $leftCopy -= $widDelta If StringInStr($optBtns,'e') Then $leftExit -= $widDelta EndIf If StringInStr($optBtns,'l') Then $leftLimit -= $widDelta EndIf EndIf Local $htEdt = $htText - 20 If $htEdt<126 Then $htEdt = 126 Local $htClient = 10 + $htEdt + 20 + 25 Local $topBtn = 10 + $htEdt + 10 Local $htWin = $htClient + 10 If $htWin>@DesktopHeight-50 Then Local $htDelta = $htWin - (@DesktopHeight-50) $htEdt -= $htDelta $htClient -= $htDelta $topBtn -= $htDelta EndIf Local $leftClient Local $winState = WinGetState('[CLASS:SciTEWindow]') Local $WIN_STATE_EXISTS=1,$WIN_STATE_VISIBLE=2,$WIN_STATE_ENABLED=4,$WIN_STATE_ACTIVE=8,$WIN_STATE_MINIMIZED=16 Local $WIN_STATE_MAXIMIZED=32 $n = $WIN_STATE_EXISTS+$WIN_STATE_VISIBLE+$WIN_STATE_ENABLED+$WIN_STATE_ACTIVE If BitAND($winState,$n)=$n And BitAND($winState,$WIN_STATE_MINIMIZED)=0 Then _cDebug_AvoidHidingCodeInSciTE($optBtns, $leftClient, $widClient, $widEdt, $leftOK, $leftCopy _ , $leftExit, $leftLimit) Else $leftClient = -1 ; centred on Desktop EndIf Local $Form1 = GUICreate($title, $widClient, $htClient+20, $leftClient, -1,BitOR($WS_SIZEBOX,$WS_MAXIMIZEBOX)) Local $edt = GUICtrlCreateEdit("", 8, 8, $widEdt, $htEdt, BitOR($WS_HSCROLL,$WS_VSCROLL)) GUICtrlSetFont(-1,$fontSize,$fontWeightEdt,0,$fontNameEdt) GUICtrlSetBkColor(-1, 0xFFFBF0) ; cream Local $btnOK = GUICtrlCreateButton("OK", $leftOK, $topBtn, 49, 25, $BS_DEFPUSHBUTTON) Local $btnCopyData = GUICtrlCreateButton("Copy data", $leftCopy, $topBtn, 65, 25) If StringInStr($optBtns,'e') Then Local $btnExit = GUICtrlCreateButton("Exit script", $leftExit, $topBtn, 65, 25) EndIf If StringInStr($optBtns,'l') Then Local $btnChangeLimit = GUICtrlCreateButton("Change element limit", $leftLimit, $topBtn, 121, 25) EndIf Local $btnWidth = GUICtrlCreateButton("Full width", $leftCopy-(472-176), $topBtn, 65, 25) #Region ### START Koda GUI section ### Form=F:\AutoIt scripts\cDebug main.kxf MODIFIED ;~ Local $Form1_1 = GUICreate($location, 623, 452, -1, -1, BitOR($GUI_SS_DEFAULT_GUI,$WS_SIZEBOX,$WS_THICKFRAME)) ;~ Local $edt = GUICtrlCreateEdit("", 8, 8, 601, 393, BitOR($WS_HSCROLL,$WS_VSCROLL)) ;~ GUICtrlSetData(-1, "edt") ;~ GUICtrlSetBkColor(-1, 0xFFFBF0) ;~ Local $btnOK = GUICtrlCreateButton("OK", 552, 416, 49, 25, $BS_DEFPUSHBUTTON) ;~ Local $btnCopyData = GUICtrlCreateButton("Copy data", 472, 416, 65, 25) ;~ Local $btnExit = GUICtrlCreateButton("Exit script", 392, 416, 65, 25) ;~ Local $btnChangeLimit = GUICtrlCreateButton("Change element limit", 256, 416, 121, 25) ;~ Local $btnWidth = GUICtrlCreateButton("Full width", 176, 416, 65, 25) Local $bWide = $widClient>=(@DesktopWidth/2-21) If Not $bWide Then GUICtrlSetState($btnWidth,$GUI_HIDE) EndIf GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### GUICtrlSetData($edt,$text) Local $initWinPosVec = WinGetPos($Form1) Local $nMsg,$bEndit=False,$bWidNormal=True While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE,$btnOK $bEndit = true ExitLoop Case $btnCopyData GUICtrlSetState($btnCopyData,$GUI_DISABLE) _cDebug_UpdateClipboard('***'&$title&'-------------------------'&@CRLF&$text) Case $btnWidth If $bWidNormal Then WinMove($Form1,'',1,$initWinPosVec[1],@DesktopWidth,$htClient,0) GUICtrlSetData($btnWidth,'Half width') $bWidNormal = False Else WinMove($Form1,'',$initWinPosVec[0],$initWinPosVec[1],$initWinPosVec[2],$initWinPosVec[3]) GUICtrlSetData($btnWidth,'Full width') $bWidNormal = True EndIf Case Else If StringInStr($optBtns,'l') And $nMsg=$btnChangeLimit Then If $g_cDebug_elementLimit=0 Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,'$g_cDebug_elementLimit=0') ElseIf $g_cDebug_elementLimit='' Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,"$g_cDebug_elementLimit=''") EndIf Local $n = $g_cDebug_elementLimit GUISetState(@SW_DISABLE,$Form1) _cDebug_DlgChangeLimit($Form1, $elLimit) GUISetState(@SW_ENABLE,$Form1) ExitLoop EndIf If StringInStr($optBtns,'e') And $nMsg=$btnExit Then Exit EndIf EndSwitch WEnd GUIDelete($Form1) Return $bEndit EndFunc Func _cDebug_FmtNameVal_Whole3dArray($location,$indent,$thisName,$restName,$val,$tag) Local $t,$ret,$n,$q,$id,$vec Local $qShts = UBound($val, 1) Local $qRows = UBound($val, 3) Local $qCols = UBound($val, 5) Local $wid = StringLen('['&($qShts-1)&']['&($qRows-1)&']['&($qCols-1)&']') $t = StringIsSpace($thisName) ? '' : $thisName Local $hdg = $thisName&' Array: '&$qShts&' sheet'&($qShts=1 ? '' : 's')&' '& _ $qRows&' row'&($qRows=1 ? '' : 's')&' '&$qcols&' column'&($qCols=1 ? '' : 's')&@CRLF Local $qShtsDone=0,$qRowsDone,$qColsDone,$sub For $i = 0 To $qShts-1 $qRowsDone = 0 For $j = 0 To $qRows-1 $qColsDone = 0 For $k = 0 To $qCols-1 $id = StringFormat('%-'&$wid&'s', "["&$i&"]["&$j&"]["&$k&"]") $id &= ' =>' $sub = _cDebug_FmtNameVal($location,$indent&$g_cDebug_tab,$restName,$val[$i][$j][$k],$tag) If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $ret &= $indent&$id&$sub EndIf $qColsDone += 1 If $qColsDone>=$g_cDebug_elementLimit Then $q = $qCols-$qColsDone If $q>0 Then $ret &= $indent&'... '&$q&' more column'&($q=1 ? '' : 's')&@CRLF ExitLoop EndIf EndIf Next $qRowsDone += 1 If $qRowsDone>=$g_cDebug_elementLimit Then $q = $qRows-$qRowsDone If $q>0 Then $ret &= $indent&'... '&$q&' more row'&($q=1 ? '' : 's')&@CRLF ExitLoop EndIf EndIf Next $qShtsDone += 1 If $qShtsDone>=$g_cDebug_elementLimit Then $q = $qShts-$qShtsDone If $q>0 Then $ret &= $indent&'... '&$q&' more sheet'&($q=1 ? '' : 's')&@CRLF ExitLoop EndIf EndIf Next If ($g_cDebug_bMultiLevel And $ret<>'') Or Not $g_cDebug_bMultiLevel Then $ret = $hdg&$ret EndIf Return $ret EndFunc Func _cDebug_FmtNameVal_Whole2dArray($location,$indent,$thisName,$restName,$val,$tag) Local $t,$ret,$n,$q,$id,$vec Local $qRows = UBound($val, 1) Local $qCols = UBound($val, 2) Local $wid = StringLen('['&($qRows-1)&']['&($qCols-1)&']') ; 2015-06-11 $t = StringIsSpace($thisName) ? '' : $thisName Local $hdg = $thisName&' Array: '&$qRows&' row'&($qRows=1 ? '' : 's')&' '&$qcols&' column'&($qCols=1 ? '' : 's')&@CRLF Local $qRowsDone=0,$qColsDone,$sub For $j = 0 To $qRows-1 $qColsDone = 0 For $k = 0 To $qCols-1 $id = StringFormat('%-'&$wid&'s', "["&$j&"]["&$k&"]") $id &= ' =>' $sub = _cDebug_FmtNameVal($location,$indent&$g_cDebug_tab,$restName,$val[$j][$k],$tag) If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $ret &= $indent&$id&$sub EndIf $qColsDone += 1 If $qColsDone>=$g_cDebug_elementLimit Then $q = $qCols-$qColsDone If $q>0 Then $ret &= $indent&'... '&$q&' more column'&($q=1 ? '' : 's')&@CRLF ExitLoop EndIf EndIf Next $qRowsDone += 1 If $qRowsDone>=$g_cDebug_elementLimit Then $q = $qRows-$qRowsDone If $q>0 Then $ret &= $indent&'... '&$q&' more row'&($q=1 ? '' : 's')&@CRLF ExitLoop EndIf EndIf Next If ($g_cDebug_bMultiLevel And $ret<>'') Or Not $g_cDebug_bMultiLevel Then $ret = $hdg&$ret EndIf Return $ret EndFunc Func _cDebug_FmtNameVal_3dArraySlice($location,$indent,$thisName,$restName,$val,$tag) Local $t,$ret,$n,$q,$id,$vec Local $brsVec = StringSplit($thisName,'[]',0+2) ; char,0-based Local $qShts = UBound($val,1) Local $qRows = UBound($val,2) Local $qCols = UBound($val,3) Local $hdg = $thisName&' Array: '&$qShts&' sheet'&($qShts=1 ? ' ' : 's')&' '& _ $qRows&' row'&($qRows=1 ? '' : 's')&' '& _ $qCols&' column'&($qCols=1 ? '' : 's')&' total'&@CRLF Local $shtStrIxsVec[0],$shtNumIxsVec[0] _cDebug_ExpandSliceSubscripts($brsVec[1],$qShts,'sheet',$thisName,'a',0, $shtStrIxsVec, $shtNumIxsVec) Local $rowStrIxsVec[0],$rowNumIxsVec[0] _cDebug_ExpandSliceSubscripts($brsVec[3],$qRows,'row',$thisName,'a',0, $rowStrIxsVec, $rowNumIxsVec) Local $colStrIxsVec[0],$colNumIxsVec[0] _cDebug_ExpandSliceSubscripts($brsVec[5],$qCols,'column',$thisName,'a',0, $colStrIxsVec,$colNumIxsVec) $t = StringIsSpace($thisName) ? '' : $thisName $vec = StringSplit($thisName,'[',0+2) ; char,0-based Local $shtWid,$rowWid,$colWid If $brsVec[1]='..' Then ; if first subscript is .. $rowWid = StringLen($qShts-1) Else $shtWid = 0 For $j = 0 To UBound($shtStrIxsVec)-1 $n = StringLen($shtStrIxsVec[$j]) If $n>$shtWid Then $shtWid = $n $n = StringLen($shtNumIxsVec[$j]) If $n>$shtWid Then $shtWid = $n Next EndIf If $brsVec[3]='..' Then ; if first subscript is .. $rowWid = StringLen($qRows-1) Else $rowWid = 0 For $j = 0 To UBound($rowStrIxsVec)-1 $n = StringLen($rowStrIxsVec[$j]) If $n>$rowWid Then $rowWid = $n $n = StringLen($rowNumIxsVec[$j]) If $n>$rowWid Then $rowWid = $n Next EndIf If $brsVec[5]='..' Then ; If second subscript is .. $colWid = StringLen($qcols-1) Else $colWid = 0 For $j = 0 To UBound($colStrIxsVec)-1 $n = StringLen($colStrIxsVec[$j]) If $n>$colWid Then $colWid = $n $n = StringLen($colNumIxsVec[$j]) If $n>$colWid Then $colWid = $n Next EndIf Local $wid = $shtWid+$rowWid+$colWid+6 ; '[][][]' Local $nSht,$nRow,$nCol,$bShtAtLimit=False,$bRowAtLimit,$bColAtLimit,$qMoreElsInCol,$qMoreRowsWithSelEls $qShts = UBound($shtNumIxsVec) $qRows = UBound($rowNumIxsVec) $qcols = UBound($colNumIxsVec) Local $qShtsRptd=0,$qRowsRptd,$qColsRptd,$sub For $i = 0 To UBound($shtNumIxsVec)-1 $nSht = $shtNumIxsVec[$i] $qRowsRptd = 0 For $j = 0 To UBound($rowNumIxsVec)-1 $nRow = $rowNumIxsVec[$j] $bColAtLimit = False $qColsRptd = 0 $qMoreElsInCol = 0 For $k = 0 To UBound($colNumIxsVec)-1 $nCol = $colNumIxsVec[$k] $sub = _cDebug_FmtNameVal($location,$indent&$g_cDebug_tab,$restName,$val[$nSht][$nRow][$nCol],$tag) If Not $bColAtLimit Then $id = StringFormat('%-'&$wid&'s', "["&$nSht&"]["&$nRow&"]["&$nCol&"]") $id &= ' => ' If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $ret &= $indent&$id&$sub $qColsRptd += 1 $bColAtLimit = $qColsRptd>=$g_cDebug_elementLimit EndIf Else If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $qMoreElsInCol += 1 EndIf EndIf Next If $qMoreElsInCol>0 Then $ret &= $indent&'... '&$qMoreElsInCol&' more selected element'& _ ($qMoreElsInCol=1 ? '' : 's')&' in this column'&@CRLF EndIf If $qColsRptd>0 Then $qRowsRptd += 1 If $qRowsRptd>=$g_cDebug_elementLimit Then ExitLoop EndIf EndIf Next If $g_cDebug_bMultiLevel Then $qMoreRowsWithSelEls = 0 For $j = $j+1 To UBound($rowNumIxsVec)-1 $nRow = $rowNumIxsVec[$j] For $k = 0 To UBound($colNumIxsVec)-1 $nCol = $colNumIxsVec[$k] $sub = _cDebug_FmtNameVal($location,$indent&$g_cDebug_tab,$restName,$val[$nSht][$nRow][$nCol],$tag) If $sub<>'' Then $qMoreRowsWithSelEls += 1 ExitLoop 1 EndIf Next Next Else $qMoreRowsWithSelEls = UBound($rowNumIxsVec) - $qRowsRptd EndIf If $qMoreRowsWithSelEls>0 Then $ret &= $indent&'... '&$qMoreRowsWithSelEls&' more row'&($qMoreRowsWithSelEls=1 ? '' : 's')& _ ' in this sheet ha'&($qMoreRowsWithSelEls=1 ? 's' : 've')&' selected element(s)'&@CRLF EndIf $qShtsRptd += 1 $bShtAtLimit = $qShtsRptd>=$g_cDebug_elementLimit If $bShtAtLimit Then ExitLoop EndIf Next Local $qMoreShtsWithSelEls If $g_cDebug_bMultiLevel Then $qMoreShtsWithSelEls = 0 For $i = $i+1 To UBound($shtNumIxsVec)-1 $nSht = $shtNumIxsVec[$i] For $j = 0 To UBound($rowNumIxsVec)-1 $nRow = $rowNumIxsVec[$j] For $k = 0 To UBound($colNumIxsVec)-1 $nCol = $colNumIxsVec[$k] $sub = _cDebug_FmtNameVal($location,$indent&$g_cDebug_tab,$restName, _ $val[$nSht][$nRow][$nCol],$tag) If $sub<>'' Then $qMoreShtsWithSelEls += 1 ExitLoop 2 EndIf Next Next Next Else $qMoreShtsWithSelEls = UBound($shtNumIxsVec) - $qShtsRptd EndIf If $qMoreShtsWithSelEls>0 Then $ret &= $indent&'... '&$qMoreShtsWithSelEls&' more sheet'&($qMoreShtsWithSelEls=1 ? '' : 's')& _ ' ha'&($qMoreShtsWithSelEls=1 ? 's' : 've')&' selected element(s)'&@CRLF EndIf If ($g_cDebug_bMultiLevel And $ret<>'') Or Not $g_cDebug_bMultiLevel Then $ret = $hdg&$ret EndIf Return $ret EndFunc Func _cDebug_FmtNameVal_2dArraySlice($location,$indent,$thisName,$restName,$val,$tag) Local $t,$ret,$n,$q,$id,$vec Local $brsVec = StringSplit($thisName,'[]',0+2) ; char,0-based Local $qRows = UBound($val,1) Local $qCols = UBound($val,2) Local $hdg = $brsVec[0]&' Array: '&$qRows&' row'&($qRows=1 ? '' : 's')&' '& _ $qcols&' column'&($qcols=1 ? '' : 's')&' total'&@CRLF Local $rowStrIxsVec[0],$rowNumIxsVec[0] _cDebug_ExpandSliceSubscripts($brsVec[1],$qRows,'row',$thisName,'a',0, $rowStrIxsVec, $rowNumIxsVec) If UBound($brsVec)=3 then _cDebug_ReportErrorAndExit( _ 'Attempt to get value of an element of 2-D array with one subscript failed') endif Local $colStrIxsVec[0],$colNumIxsVec[0] _cDebug_ExpandSliceSubscripts($brsVec[3],$qCols,'column',$thisName,'a',0, $colStrIxsVec,$colNumIxsVec) $t = StringIsSpace($thisName) ? '' : $thisName $vec = StringSplit($thisName,'[',0+2) ; char,0-based Local $rowWid,$colWid If $brsVec[1]='..' Then ; if first subscript is .. $rowWid = StringLen($qRows-1) Else $rowWid = 0 For $j = 0 To UBound($rowStrIxsVec)-1 $n = StringLen($rowStrIxsVec[$j]) If $n>$rowWid Then $rowWid = $n $n = StringLen($rowNumIxsVec[$j]) If $n>$rowWid Then $rowWid = $n Next EndIf If $brsVec[3]='..' Then ; If second subscript is .. $colWid = StringLen($qcols-1) Else $colWid = 0 For $j = 0 To UBound($colStrIxsVec)-1 $n = StringLen($colStrIxsVec[$j]) If $n>$colWid Then $colWid = $n $n = StringLen($colNumIxsVec[$j]) If $n>$colWid Then $colWid = $n Next EndIf Local $wid = $rowWid+$colWid+StringLen('[][]') Local $nRow,$bRowAtLimit=False,$nCol,$bColAtLimit,$qMoreElsInCol $qRows = UBound($rowNumIxsVec) $qcols = UBound($colNumIxsVec) Local $qRowsRptd=0,$qColsRptd,$sub For $j = 0 To UBound($rowNumIxsVec)-1 $nRow = $rowNumIxsVec[$j] $bColAtLimit = False $qColsRptd = 0 $qMoreElsInCol = 0 For $k = 0 To UBound($colNumIxsVec)-1 $nCol = $colNumIxsVec[$k] $sub = _cDebug_FmtNameVal($location,$indent&$g_cDebug_tab,$restName,$val[$nRow][$nCol],$tag) If Not $bColAtLimit Then $id = StringFormat('%-'&$wid&'s', "["&$nRow&"]["&$nCol&"]") $id &= ' => ' If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $ret &= $indent&$id&$sub $qColsRptd += 1 $bColAtLimit = $qColsRptd>=$g_cDebug_elementLimit EndIf Else If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $qMoreElsInCol += 1 EndIf EndIf Next If $qMoreElsInCol>0 Then $ret &= $indent&'... '&$qMoreElsInCol&' more selected element'& _ ($qMoreElsInCol=1 ? '' : 's')&' in this column'&@CRLF EndIf $qRowsRptd += 1 $bRowAtLimit = $qRowsRptd>=$g_cDebug_elementLimit If $bRowAtLimit Then ExitLoop EndIf Next Local $qMoreRowsWithSelEls=0 If $g_cDebug_bMultiLevel Then For $j = $j+1 To UBound($rowNumIxsVec)-1 $nRow = $rowNumIxsVec[$j] For $k = 0 To UBound($colNumIxsVec)-1 $nCol = $colNumIxsVec[$k] $sub = _cDebug_FmtNameVal($location,$indent&$g_cDebug_tab,$restName,$val[$nRow][$nCol],$tag) If $sub<>'' Then $qMoreRowsWithSelEls += 1 ExitLoop EndIf Next Next Else $qMoreRowsWithSelEls = $qRows - $qRowsRptd EndIf If $qMoreRowsWithSelEls>0 Then $ret &= $indent&'... '&$qMoreRowsWithSelEls&' more row'&($qMoreRowsWithSelEls=1 ? '' : 's')& _ ' ha'&($qMoreRowsWithSelEls=1 ? 's' : 've')&' selected element(s)'&@CRLF EndIf If ($g_cDebug_bMultiLevel And $ret<>'') Or Not $g_cDebug_bMultiLevel Then $ret = $hdg&$ret EndIf Return $ret EndFunc #cs maps Func _cDebug_FmtNameVal_WholeMap($location,$indent,$thisName,$restName,$map,$tag) Local $t,$ret,$key,$n Local $qEls = UBound($map) Local $brsVec = StringSplit($thisName,'[]',0+2) ; char,0-based $t = StringIsSpace($brsVec[0]) ? '' : $brsVec[0] Local $hdg = $t&' <Map> '&$qEls&' element'&($qEls<>1 ? 's' : '')&@CRLF Local $keysVec = _cDebug_MapKeys($map,@ScriptLineNumber) If UBound($keysVec)>1 Then $keysVec = _cDebug_SortMapKeys($keysVec) EndIf Local $wid=0,$bAllNum=True For $key In $keysVec $n = StringLen($key) If $n>$wid Then $wid = $n EndIf $bAllNum = $bAllNum And IsNumber($key) Next $wid += 2 If Not $bAllNum Then $wid += 2 EndIf Local $qDone=0,$id,$sub For $key In $keysVec If IsNumber($key) Then $t = StringFormat('%'&$wid&'s','['&$key&']') Else $t = StringFormat('%-'&$wid&'s', "['"&$key&"']") EndIf $id = $t $id &= ' => ' $sub = _cDebug_FmtNameVal($location,$indent&$g_cDebug_tab,$restName,$map[$key],$tag) If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $ret &= $indent&$id&$sub EndIf $qDone += 1 If $qDone>=$g_cDebug_elementLimit Then $n = $qEls-$qDone If $n>0 Then $ret &= $indent&'... '&$n&' more element'&($n>1 ? 's' : '')&@CRLF EndIf ExitLoop EndIf Next If ($g_cDebug_bMultiLevel And $ret<>'') Or Not $g_cDebug_bMultiLevel Then $ret = $hdg&$ret EndIf Return $ret EndFunc #ce maps #cs maps Func _cDebug_FmtNameVal_MapSlice($location,$indent,$thisName,$restName,$map,$tag) Local $t,$ret,$key,$n Local $qEls = UBound($map) Local $brsVec = StringSplit($thisName,'[]',0+2) ; char,0-based $t = StringIsSpace($brsVec[0]) ? '' : $brsVec[0] Local $hdg = $t&' Map: '&$qEls&' element'&($qEls=1 ? '' : 's')&' total'&@CRLF Local $tmap = _cDebug_FilterMap($brsVec[1],$thisName,$map) Local $keysVec = _cDebug_MapKeys($tmap,@ScriptLineNumber) If UBound($keysVec)>1 Then $keysVec = _cDebug_SortMapKeys($keysVec) EndIf Local $wid = 0,$qEls = 0,$bAllNum=True For $key In $keysVec $n = StringLen($key) If $n>$wid Then $wid = $n EndIf $bAllNum = $bAllNum And IsNumber($key) Next $wid += 2 If Not $bAllNum Then ; not all numeric $wid += 2 EndIf Local $qEls = UBound($tmap) If $qEls=0 And Not $g_cDebug_bMainUDFcalled Then $ret &= $indent&'-- No specified elements found --'&@CRLF EndIf Local $qElsDone=0,$id,$sub,$bAtLimit=False,$qMoreEls=0 For $key In $keysVec $sub = _cDebug_FmtNameVal($location,$indent&$g_cDebug_tab,$restName,$tmap[$key],$tag) If Not $bAtLimit Then If IsNumber($key) Then $id = StringFormat('%'&$wid&'s','['&$key&']') Else $id = StringFormat('%-'&$wid&'s', "['"&$key&"']") EndIf $id &= ' => ' If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $ret &= $indent&$id&$sub EndIf $qElsDone += 1 $bAtLimit = $qElsDone>=$g_cDebug_elementLimit Else If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $qMoreEls += 1 EndIf EndIf Next If $qMoreEls>0 Then $ret &= $indent&'... '&$qMoreEls&' more selected element'&($qMoreEls>1 ? 's' : '')&@CRLF EndIf If ($g_cDebug_bMultiLevel And $ret<>'') Or Not $g_cDebug_bMultiLevel Then $ret = $hdg&$ret EndIf Return $ret EndFunc #ce maps Func _cDebug_FmtNameVal_WholeVector($location,$indent,$thisName,$restName,$val,$tag) Local $t,$ret,$n,$vec Local $qEls = UBound($val) $t = StringIsSpace($thisName) ? '' : $thisName Local $hdg = $t&' Vector: '&$qEls&' element'&($qEls=1 ? '' : 's')&@CRLF Local $wid = StringLen('['&($qEls-1)&']') Local $qDone=0,$id,$sub For $j = 0 To $qEls-1 $id = StringFormat('%-'&$wid&'s', "["&$j&"]") $id &= ' => ' $sub = _cDebug_FmtNameVal($location,$indent&$g_cDebug_tab,$restName,$val[$j],$tag) If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $ret &= $indent&$id&$sub EndIf $qDone += 1 If $qDone>=$g_cDebug_elementLimit Then $n = $qEls-$qDone If $n>0 Then $ret &= $indent&'... '&$n&' more elememt'&($n>1 ? 's' : '')&@CRLF ExitLoop EndIf EndIf Next If ($g_cDebug_bMultiLevel And $ret<>'') Or Not $g_cDebug_bMultiLevel Then $ret = $hdg&$ret EndIf Return $ret EndFunc Func _cDebug_FmtNameVal_VectorSlice($location,$indent,$thisName,$restName,$val,$tag) Local $n,$t,$ret,$vec Local $qEls = UBound($val) Local $brsVec = StringSplit($thisName,'[]',0+2) ; char,0-based $t = StringIsSpace($brsVec[0]) ? '' : $brsVec[0] Local $hdg = $t&' Vector: '&$qEls&' element'&($qEls=1 ? '' : 's')&' total'&@CRLF Local $strIxsVec[0],$numIxsVec[0] _cDebug_ExpandSliceSubscripts($brsVec[1],$qEls,'element',$brsVec[0],'v',0, $strIxsVec, $numIxsVec) Local $wid = 0 For $j = 0 To UBound($strIxsVec)-1 $n = StringLen($strIxsVec[$j]) If $n>$wid Then $wid = $n $n = StringLen($numIxsVec[$j]) If $n>$wid Then $wid = $n Next $wid += 2 ; '[]' Local $qElsRptd=0,$nEl,$id,$sub,$bAtLimit=False,$qMoreEls=0 For $i = 0 To UBound($numIxsVec)-1 $nEl = $numIxsVec[$i] $sub = _cDebug_FmtNameVal($location,$indent&$g_cDebug_tab,$restName,$val[$nEl],$tag) If Not $bAtLimit Then $id = StringFormat('%-'&$wid&'s', "["&$strIxsVec[$i]&"]") $id &= ' => ' If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $ret &= $indent&$id&$sub $qElsRptd += 1 $bAtLimit = $qElsRptd>=$g_cDebug_elementLimit EndIf Else If ($g_cDebug_bMultiLevel And $sub<>'') Or Not $g_cDebug_bMultiLevel Then $qMoreEls += 1 EndIf EndIf Next If $qMoreEls>0 Then $ret &= $indent&'... '&$qMoreEls&' more selected element'&($qMoreEls>1 ? 's' : '')&@CRLF EndIf If ($g_cDebug_bMultiLevel And $ret<>'') Or Not $g_cDebug_bMultiLevel Then $ret = $hdg&$ret EndIf Return $ret EndFunc ; $arOrMap: 'a','v', 'mn','ms' ; If $arOrMap='a' or 'v', $mapKeysVec is ignored ; If $arOrMap='mn' or 'ms': $qRorC is ignored Func _cDebug_ExpandSliceSubscripts($expr,$qRorC,$rOrC,$arName,$arOrMap, _ $mapKeysVec, ByRef $allUserIxsVec, ByRef $alNumIxsVec) Local Const $reVarOrDigits = '(\$[a-zA-Z0-9_]+|\d+)' Local Const $reVarOrInt = '(\$[a-zA-Z0-9_]+|[-]{0,1}\d+)' Local Const $reVarOrQuotedAnyASCII = '(?s)(\$[a-zA-Z0-9_]+|["''].+["''])' Local $userIxsVec[0],$numIxsVec[0],$regexp If $expr='' Then $expr = '..' EndIf If $arOrMap='a' Then $regexp = $reVarOrDigits ElseIf $arOrMap='v' Then If $g_cDebug_bMultiLevel Then $regexp = $reVarOrInt Else $regexp = $reVarOrDigits EndIf ElseIf $arOrMap='mn' Then $regexp = $reVarOrInt Else $regexp = $reVarOrQuotedAnyASCII EndIf Local $vec = StringSplit($expr,',',0+2) ; char,0-based split on comma For $i = 0 To UBound($vec)-1 Local $subExpr = StringStripWS($vec[$i],1+2) ; left,right If $subExpr='..' And ($arOrMap='a' Or $arOrMap='v') Then ; e.g. vec[..] or vec[] _cDebug_ExpandSliceSubscripts_Periods($qRorC, $userIxsVec, $numIxsVec) ElseIf StringRegExp($subExpr,'^'&$regexp&'\.\.$') Then _cDebug_ExpandSliceSubscripts_From($subExpr,$qRorC,$rOrC,$arName,$arOrMap, _ $mapKeysVec, $userIxsVec, $numIxsVec) ElseIf StringRegExp($subExpr,'^\.\.'&$regexp&'$') Then _cDebug_ExpandSliceSubscripts_To($subExpr,$qRorC,$rOrC,$arName,$arOrMap, _ $mapKeysVec, $userIxsVec, $numIxsVec) ElseIf StringRegExp($subExpr,'^'&$regexp&'\.\.'&$regexp&'$') Then ; e.g. 2..3 or $i..3 or $i .. $j or 2..$j _cDebug_ExpandSliceSubscripts_FromTo($subExpr,$qRorC,$rOrC,$arName,$arOrMap, _ $mapKeysVec, $userIxsVec, $numIxsVec) ElseIf StringRegExp($subExpr,'^'&$regexp&'$') Then _cDebug_ExpandSliceSubscripts_VarOrVal($subExpr,$qRorC,$rOrC,$arName,$arOrMap, _ $mapkeysvec, $userIxsVec, $numIxsVec) Else If $g_cDebug_bMultiLevel And $arOrMap='v' And StringRegExp($expr,'["''].+["'']') Then ; quoted anything ; do nothing Else _cDebug_ReportErrorAndExit('Invalid '&$rOrC&' expression '&$subExpr&' in '&$arName) EndIf EndIf ; append Local $ubOld = UBound($allUserIxsVec) Local $ubNew = $ubOld + UBound($userIxsVec) ReDim $allUserIxsVec[$ubNew] For $j = $ubOld To $ubNew-1 $allUserIxsVec[$j] = $userIxsVec[$j-$ubOld] Next ReDim $alNumIxsVec[$ubNew] For $j = $ubOld To $ubNew-1 $alNumIxsVec[$j] = $numIxsVec[$j-$ubold] Next Next EndFunc Func _cDebug_ExpandSliceSubscripts_Periods($qRorC, ByRef $userIxsVec, ByRef $numIxsVec) ReDim $userIxsVec[$qRorC] For $j = 0 To $qRorC-1 $userIxsVec[$j] = $j Next $numIxsVec = $userIxsVec EndFunc Func _cDebug_ExpandSliceSubscripts_VarOrVal($expr,$qRorC,$rOrC,$arName,$arOrMap,$mapKeysVec, _ ByRef $userIxsVec, ByRef $valIxsVec) Local $val If StringLeft($expr,1)='$' Or StringMid($expr,2,1)='$' Then $val = _cDebug_GetValOfSubscriptVarOrConst($expr,$arName,$arOrMap) Else If $arOrMap='ms' Then $val = StringTrimLeft(StringTrimRight($expr,1),1) ; remove quotes Else $val = $expr EndIf EndIf If $arOrMap='a' Or $arOrMap='v' Then $val = Number($val) If $val>=0 And $val<$qRorC Then ReDim $valIxsVec[1] $valIxsVec[0] = $val ReDim $userIxsVec[1] $userIxsVec[0] = $expr Else If Not $g_cDebug_bMultiLevel Then If $val<0 Then _cDebug_ReportErrorAndExit('In '&$arName&' index cannot be negative') Else If $qRorC=0 Then _cDebug_ReportErrorAndExit($arName&' has no '&$rOrC&'s') Else _cDebug_ReportErrorAndExit('In '&$arName&'['&$expr&'], '&$rOrC&' number exceeds '&($qRorC-1)&', the maximum') EndIf EndIf EndIf EndIf Else ; 'mn','ms' For $i = 0 To UBound($mapkeysVec)-1 If $mapkeysVec[$i]==$val Then ; case-sensitive ReDim $valIxsVec[1] $valIxsVec[0] = $mapkeysVec[$i] ExitLoop EndIf Next $userIxsVec = $valIxsVec EndIf EndFunc Func _cDebug_ExpandSliceSubscripts_From($expr,$qRorC,$rOrC,$arName,$arOrMap,$mapKeysVec, _ ByRef $userIxsVec, ByRef $valIxsVec) Local $t Local $vec = StringSplit($expr,'..',1+2) ; str,0-based Local $valSt If StringLeft($vec[0],1)='$' Then $valSt = _cDebug_GetValOfSubscriptVarOrConst($vec[0],$arName,$arOrMap) Else $valSt = $vec[0] EndIf If $arOrMap='a' Or $arOrMap='v' Then $valSt = Number($valSt) ; relax for multilevel If $g_cDebug_bMultiLevel And $arOrMap='v' Then ; a vector If $valSt<0 Then $valSt = 0 EndIf EndIf If Int($valSt)<$qRorC Then ReDim $valIxsVec[$qRorC-$valSt] For $j = 0 To $qRorC-$valSt-1 $valIxsVec[$j] = $j+$valSt Next $userIXsVec = $valIxsVec If StringLeft($vec[0],1)='$' Then $userIxsVec[0] = $vec[0] EndIf Else If Not $g_cDebug_bMultiLevel Then $t = $valSt<>$vec[0] ? ' ('&$valSt&')' : '' If $qRorC=0 Then _cDebug_ReportErrorAndExit($arName&' has no '&$rOrC&'s') Else _cDebug_ReportErrorAndExit('In '&$arName&'['&$expr&'], '&$rOrC&' number exceeds '&($qRorC-1)&', the maximum') EndIf EndIf EndIf ElseIf $arOrMap='mn' Then ReDim $valIxsVec[UBound($mapKeysVec)] Local $q = 0 For $i = 0 To UBound($mapkeysVec)-1 If $mapkeysvec[$i]>=$valSt Then $valIxsVec[$q] = $mapkeysVec[$i] $q += 1 EndIf Next ReDim $valIxsVec[$q] $userIXsVec = $valIxsVec Else ; 'ms' ReDim $valIxsVec[UBound($mapkeysVec)] Local $q = 0 $valSt = StringTrimLeft(StringTrimRight($valSt,1),1) ; remove quotes For $i = 0 To UBound($mapkeysVec)-1 If StringCompare($mapkeysVec[$i],$valSt,1)>=0 Then ; case-sensitive, >= $valIxsVec[$q] = $mapkeysVec[$i] $q += 1 EndIf Next ReDim $valIxsVec[$q] $userIXsVec = $valIxsVec EndIf EndFunc Func _cDebug_ExpandSliceSubscripts_To($expr,$qRorC,$rOrC,$arName,$arOrMap,$mapKeysVec, _ ByRef $userIxsVec, ByRef $valIxsVec) Local $vec = StringSplit($expr,'..',1+2) ; str,0-based Local $valEnd If StringLeft($vec[1],1)='$' Then $valEnd = _cDebug_GetValOfSubscriptVarOrConst($vec[1],$arName,$arOrMap) Else $valEnd = $vec[1] EndIf If $arOrMap='a' Or $arOrMap='v' Then $valEnd = Number($valEnd) ; relax for multilevel If $g_cDebug_bMultiLevel And $arOrMap='v' Then ; a vector If $valEnd>$qRorC-1 Then $valEnd = $qRorC-1 EndIf EndIf If $valEnd<$qRorC Then ReDim $valIxsVec[$valEnd+1] For $j = 0 To $valEnd $valIxsVec[$j] = $j Next $userIxsVec = $valIxsVec Else If Not $g_cDebug_bMultiLevel Then If $qRorC=0 Then _cDebug_ReportErrorAndExit($arName&' has no '&$rOrC&'s') Else _cDebug_ReportErrorAndExit('In '&$arName&'['&$expr&'], '&$rOrC&' number exceeds '&($qRorC-1)&', the maximum') EndIf EndIf EndIf ElseIf $arOrMap='mn' Then ReDim $valIxsVec[UBound($mapKeysVec)] Local $q = 0 For $i = 0 To UBound($mapkeysVec)-1 If $mapkeysvec[$i]<=$valEnd Then $valIxsVec[$q] = $mapkeysVec[$i] $q += 1 EndIf Next ReDim $valIxsVec[$q] $userIXsVec = $valIxsVec Else ; 'ms' ReDim $valIxsVec[UBound($mapkeysVec)] Local $q = 0 $valEnd = StringTrimLeft(StringTrimRight($valEnd,1),1) ; remove quotes For $i = 0 To UBound($mapkeysVec)-1 If StringCompare($mapkeysVec[$i],$valEnd,1)<=0 Then ; case-sensitive, >= $valIxsVec[$q] = $mapkeysVec[$i] $q += 1 EndIf Next ReDim $valIxsVec[$q] $userIXsVec = $valIxsVec EndIf EndFunc Func _cDebug_ExpandSliceSubscripts_FromTo($expr,$qRorC,$rOrC,$arName,$arOrMap,$mapKeysVec, _ ByRef $userIxsVec, ByRef $valIxsVec) Local $t,$s Local Enum $eSt,$eEnd Local $svec = StringSplit($expr,'..',1+2) ; str,0-based Local $valsVec[2] For $i = $eSt To $eEnd If StringLeft($svec[$i],1)='$' Then $valsVec[$i] = _cDebug_GetValOfSubscriptVarOrConst($sVec[$i],$arName,$arOrMap) Else $valsVec[$i] = $svec[$i] EndIf Next If $arOrMap='a' Or $arOrMap='v' Then $valsVec[$eSt] = Number($valsVec[$eSt]) $valsVec[$eEnd] = Number($valsVec[$eEnd]) ; relax for multilevel If $g_cDebug_bMultiLevel And $arOrMap='v' Then ; a vector If $valsVec[$eSt]<0 Then $valsVec[$eSt] = 0 EndIf If $valsVec[$eEnd]>$qRorC-1 Then $valsVec[$eEnd] = $qRorC-1 EndIf EndIf If $valsVec[$eSt]<$qRorC And $valsVec[$eEnd]<$qRorC And $valsVec[$eEnd]>=$valsVec[$eSt] Then ReDim $valIxsVec[$valsVec[$eEnd]-$valsVec[$eSt]+1] For $i = 0 To UBound($valIxsVec)-1 $valIxsVec[$i] = $valsVec[$eSt] + $i Next $userIxsVec = $valIxsVec If StringLeft($sVec[$eSt],1)='$' Then ; from $userIxsVec[0] = $svec[$eEnd] EndIf If StringLeft($svec[1],1)='$' Then ; to $userIxsVec[UBound($userIxsVec)-1] = $svec[$eEnd] EndIf Else If $valsVec[$eEnd]<$valsVec[$eSt] Then $s = $svec[$eSt]<>$valsVec[$eSt] ? ' ('&$valsVec[$eSt]&')' : '' $t = $svec[$eEnd]<>$valsVec[$eEnd] ? ' ('&$valsVec[$eEnd]&')' : '' _cDebug_ReportErrorAndExit( _ 'The upper limit of range '&$valsVec[$eEnd]&' '&$t&' is less than the lower limit '&$s&' in '&$arName) Else If Not $g_cDebug_bMultiLevel Then For $i = $eSt To $eEnd If $qRorC=0 Then _cDebug_ReportErrorAndExit($arName&' has no '&$rOrC&'s') ElseIf $valsVec[$i]>=$qRorC Then $t = $svec[$i]<>String($valsVec[$i]) ? ' ('&$valsVec[$i]&')' : '' _cDebug_ReportErrorAndExit( _ 'In '&$arName&'['&$expr&'], '&$rOrC&' number exceeds '&($qRorC-1)&', the maximum') EndIf Next EndIf EndIf EndIf ElseIf $arOrMap='mn' Then $valsVec[$eSt] = Number($valsVec[$eSt]) $valsVec[$eEnd] = Number($valsVec[$eEnd]) ReDim $valIxsVec[UBound($mapKeysVec)] Local $q = 0 For $i = 0 To UBound($mapkeysVec)-1 If $mapkeysvec[$i]>=$valsVec[$eSt] And $mapkeysvec[$i]<=$valsVec[$eEnd] Then $valIxsVec[$q] = $mapkeysVec[$i] $q += 1 EndIf Next ReDim $valIxsVec[$q] $userIXsVec = $valIxsVec Else ; 'ms' ReDim $valIxsVec[UBound($mapkeysVec)] Local $q = 0 $valsVec[$eSt] = StringTrimLeft(StringTrimRight($valsVec[$eSt],1),1) ; remove quotes $valsVec[$eEnd] = StringTrimLeft(StringTrimRight($valsVec[$eEnd],1),1) For $i = 0 To UBound($mapkeysVec)-1 ; case-sensitive If StringCompare($mapkeysVec[$i],$valsVec[$eSt],1)>=0 And _ StringCompare($mapkeysVec[$i],$valsVec[$eEnd],1)<=0 Then $valIxsVec[$q] = $mapkeysVec[$i] $q += 1 EndIf Next ReDim $valIxsVec[$q] $userIXsVec = $valIxsVec EndIf EndFunc ; If there is a name that is $strIx, assume that user intended to use it even if a global $strIx exists ; So search $names first. ; If there is value for this name, and it is neither zero nor positive integer => error ; Else look for a global ; Handles, e.g. '6', '$cat', '"$cat"', "'$cat'" Func _cDebug_GetValOfSubscriptVarOrConst($strIx,$arName,$arOrMap) Local $ret,$valArg,$valGlobal,$vec,$constExpected $strIx = StringStripWS($strIx,1+2) ; strip left and right If $arOrMap='a' Or ($arOrMap='v' And Not $g_cDebug_bMultiLevel) Then $constExpected = 'digits' ElseIf ($arOrMap='v' And $g_cDebug_bMultiLevel) Or $arOrMap='mn' Then $constExpected = 'integer' Else $constExpected = 'any' EndIf If $constExpected='digits' And StringRegExp($strIx,'^\d+$') Then $ret = Number($strIx) ElseIf $constExpected='integer' And StringRegExp($strIx,'^[-]{0,1}\d+$') Then $ret = Number($strIx) ElseIf StringRegExp($strIx,'^[''|"|]{0,1}\$[A-Za-z0-9_]+[''|"|]{0,1}$') Then ; an AutoIt variable name $vec = StringRegExp($strIx,'\$[A-Za-z0-9_]+',1) If Not @error Then $strIx = $vec[0] EndIf Local $bFoundArg=False For $j = 0 To UBound($g_cDebug_namesVec)-1 If $g_cDebug_namesVec[$j]=$strIx Then $bFoundArg = True $valArg = $g_cDebug_valsVec[$j] ExitLoop EndIf Next If Not $bFoundArg Then $valGlobal = _cDebug_EvaluateGlobalVar($strIx) Local $bFoundGlobal = @error=0 EndIf If $bFoundArg Then If _cDebug_GetValOfSubscriptVarOrConst_Verify($valArg,$arOrMap,$strIx,'value argument') Then $ret = $valArg EndIf ElseIf $bFoundGlobal Then If _cDebug_GetValOfSubscriptVarOrConst_Verify($valGlobal,$arOrMap,$strIx,'global variable') Then $ret = $valGlobal EndIf Else _cDebug_ReportErrorAndExit($strIx&' in '&$arName&' is not defined'&@CRLF&@CRLF& _ 'Add it to $names and as a value argument, or make it a global variable') EndIf Else _cDebug_ReportErrorAndExit($strIx&' in '&$arName&' is not understood') EndIf Return $ret EndFunc Func _cDebug_GetValOfSubscriptVarOrConst_Verify($val,$arOrMap,$strIx,$scope) If ($arOrMap='a' Or $arOrMap='v') And Not $g_cDebug_bMultiLevel Then If StringLeft(VarGetType($val),3)='Int' And $val>=0 Then Return True Else _cDebug_ReportErrorAndExit( _ 'Found a '&$scope&' for '&$strIx&' but its value is neither zero nor a positive integer') EndIf ElseIf $arOrMap='mn' Or ($arOrMap='a' And $g_cDebug_bMultiLevel) Then If StringLeft(VarGetType($val),3)='Int' Then Return True Else _cDebug_ReportErrorAndExit( _ 'Found a '&$scope&' for '&$strIx&' but its value is not an integer') EndIf ElseIf $arOrMap='ms' Then If VarGetType($val)='String' Then Return True Else _cDebug_ReportErrorAndExit( _ 'Found a '&$scope&' for '&$strIx&' but its value is not a string') EndIf EndIf EndFunc ; Thanks to jchd Func _cDebug_ReportScalar($id,$var,$tag) Local $ret,$t,$len,$s,$n,$vec,$varType,$s $varType = VarGetType($var) Switch $varType Case 'String' If $var='' Or StringLen($var)<>1 Then $t = 'chars' Else $t = 'char' EndIf $id &= '<String> (' & StringLen($var) &' '&$t&') ' $ret &= _cDebug_DumpStr($id,$var) Case 'Binary' $t = BinaryLen($var)=1 ? 'byte' : 'bytes' $ret = $id&'<Binary> (' & BinaryLen($var) &' '&$t&') ' $len = BinaryLen($var) If $len<=$g_cDebug_elementLimit*4 Then $ret &= $var Else $ret &= BinaryMid($var, 1, $g_cDebug_elementLimit*2) & ' ... '& _ StringTrimLeft(BinaryMid($var,$len-$g_cDebug_elementLimit*2),2) EndIf Case 'Keyword' $ret = $id&'<Keyword> ' &' '& (($var=Null) ? 'Null' : 'Default') Case 'Object' $t = @CRLF&'Name: ' & ObjName($var, $OBJ_NAME)&@CRLF $s = ObjName($var, $OBJ_STRING) If Not @error Then $t &= 'Description: ' & $s&@CRLF EndIf $s = ObjName($var, $OBJ_PROGID) If Not @error Then $t &= 'ProgID: ' & $s&@CRLF EndIf $s = ObjName($var, $OBJ_FILE) If Not @error Then $t &= 'Associated file: ' & $s&@CRLF EndIf $s = ObjName($var, $OBJ_MODULE) If Not @error Then $t &= 'Owner/marshaller: ' & $s&@CRLF EndIf $s = ObjName($var, $OBJ_CLSID) If Not @error Then $t &= 'CLSID: ' & $s&@CRLF EndIf $s = ObjName($var, $OBJ_IID) If Not @error Then $t &= 'InterfaceID: ' & $s&@CRLF EndIf $t = StringTrimRight($t,2) ; @CRLF $id &='<Object> ' $ret = _cDebug_DumpStr($id,$t) Case 'Function' $ret = $id&'<'&StringFormat('%-13s',VarGetType($var)&'>')&' '& FuncName($var) Case 'DLLStruct' $ret = $id&_cDebug_DumpStruct($id,$var,$tag) Case 'Int32','Int64' ; drop lead 00 bytes $t = Hex($var) $vec = StringSplit($t,'',0+2) ; char, 0-based $n = 0 For $i = 0 To UBound($vec)-1 If $vec[$i]='0' Then $n += 1 Else ExitLoop EndIf Next If Mod($n,2)=1 Then $n -= 1 EndIf $ret = $id&'<'&StringFormat('%-9s',VarGetType($var)&'>')&' '&$var&' 0x'&StringRight($t,StringLen($t)-$n) Case Else $ret = $id&'<'&StringFormat('%-9s',$varType&'>')&' '&$var EndSwitch Return $ret EndFunc Func _cDebug_DumpStruct($indent,$tStruct,$tagUser) Local $vec #CS ! = force detection (avoids having to remove tag from call) Detect the structure, store a report on it, also return an array containing element and padding data If there is a tag in the cDebug call then If this tag begins with ! then Remove ! Show the detected report Else Generate a per-call report, also return a similar data array Compare the detected and per-call data If they differ then Tell the user that they differ EndIf Show the per-call report EndIf Else Show the detected report Endif If any detected report shown for any of the name-value pairs, append to it limitations of detection #ce Local $detectedElementTypes='',$detectedPaddedTagAr[0][4],$userPaddedTagAr[0][4],$bDetected=False,$report Local $reportToShow Local $detectedReport = _cDebug_DumpDetectedStruct($indent,$tStruct, $detectedElementTypes, _ $detectedPaddedTagAr) ; ,,ByRef,ByRef If $tagUser<>'' Then If StringLeft($tagUser,1)='!' Then $reportToShow = 'd' Else Local $userReport = _cDebug_DumpUserStruct($indent,$tStruct,$tagUser, $userPaddedTagAr) ; ,,,ByRef If $g_cDebug_bCompareStructs Then _cDebug_ComparePaddedTags($userPaddedTagAr,$detectedPaddedTagAr) EndIf $reportToShow ='u' EndIf Else $reportToShow = 'd' EndIf If $reportToShow='d' Then If $detectedElementTypes<>'' Then $vec = StringSplit($detectedElementTypes,',',0+2) ; char,0-based For $i = 0 To UBound($vec)-1 $g_cDebug_sStructElementTypes = _ _cDebug_UpdateListOfDllElements($g_cDebug_sStructElementTypes,$vec[$i]) Next EndIf Return $detectedReport Else Return $userReport EndIf EndFunc Func _cDebug_ComparePaddedTags($userTagAr,$detTagAr) Local Enum $eTagType=0,$eTagMaxIx,$eTagQpads,$eTagText ;,$eTagQuantum,$eTagSigned Local Enum $eTqUtype=0,$eTqSize,$eTqSigned,$eTqDtype Local $n,$s,$t,$msg,$m,$quTagEls,$qdTagEls Local $uUb = UBound($userTagAr,1) Local $dUb = UBound($detTagAr,1) Local $ub = $uUb>$dUb ? $uUb : $dUb ; shorter one will have blank rows ReDim $userTagAr[$ub][4] ReDim $detTagAr[$ub][4] $quTagEls = $uUb $qdTagEls = $dUb Local $bUtypeKnown,$btypesEquiv,$bSubEl,$bPad,$uTypeEquivTo Local $uType,$dType,$uMaxIx,$dMaxIx For $iEl = 0 To $ub-1 $uType = $userTagAr[$iEl][$eTagType] If $uType='' Then $quTagEls = $iEl ExitLoop EndIf $dType = $detTagAr[$iEl][$eTagType] If $dType='' Then $qdTagEls = $iEl ExitLoop EndIf $uMaxIx = $userTagAr[$iEl][$eTagMaxIx] $dMaxIx = $detTagAr[$iEl][$eTagMaxIx] $uTypeEquivTo = '' For $i = 0 To UBound($g_cDebug_typeQuantumSignedsAr,1)-1 If $g_cDebug_typeQuantumSignedsAr[$i][$eTqUtype]=$uType Then $uTypeEquivTo = $g_cDebug_typeQuantumSignedsAr[$i][$eTqDtype] ExitLoop EndIf Next $bUtypeKnown = $uTypeEquivTo<>'' If $bUtypeKnown Then $btypesEquiv = $uTypeEquivTo=$dType Else $btypesEquiv = True ; kluge! EndIf $bSubEl = $detTagAr[$iEl][$eTagMaxIx]=$userTagAr[$iEl][$eTagMaxIx] $bPad = $detTagAr[$iEl][$eTagQpads]=$userTagAr[$iEl][$eTagQpads] If (Not $bUtypeKnown) Or (Not $btypesEquiv) Or (Not $bSubEl) Or _ (Not $bPad) Then $msg &= 'For per-call element '&($iEl+1)&' "'&$userTagAr[$iEl][$eTagText]&'":'&@CRLF If $bUtypeKnown Then If Not $btypesEquiv Then $msg &= ' The call has type "'&$uType& '" but "'&$dType&'" ('&$t&') was detected'&@CRLF EndIf Else $msg &= ' The call has type "'&$uType&' which is unknown to cDebug. '&_ 'Please tell c.haslam that it is missing on the forum' EndIf If Not $bSubEl Then $m = $uMaxIx $n = $dMaxIx $msg &= ' The call has '&$m&' subelement'&($m<>1 ? 's' : '')& _ ' but '&$n&($n>1 ? ' were' :' was')&' detected'&@CRLF EndIf If Not $bPad Then $m = $userTagAr[$iEl][$eTagQpads] $n = $detTagAr[$iEl][$eTagQpads] $msg &= ' There '&($m<>1 ? 'are ' : 'is ')&$m&' padding byte'&($m<>1 ? 's' : '')& _ ' after it but '&$n&' byte'&($n<>1 ? 's were' : ' was')&' detected'&@CRLF EndIf EndIf Next If $quTagEls<>$qdTagEls Then $msg &= 'The call has '&$quTagEls&' element'&($quTagEls<>1 ? 's' : '')& _ ' but '&$qdTagEls&' element'&($qdTagEls<>1 ? 's were' : ' was')&' detected'&@CRLF EndIf If ($msg='' And $g_cDebug_ShowStructComparisonAlways) Or $msg<>'' Then ;~ If $g_cDebug_ShowStructComparisonAlways Then If $msg='' Then $msg = 'The tag in the call creates a structure similar to the structure detected.'&@CRLF& _ 'Due to the limitations of AutoIt, the structures may still differ. See cDebug.pdf for details.' Else $msg &= @CRLF&'There may be other differences.'&@CRLF& _ 'See cDebug.pdf for the limitations of detection of structures.' EndIf $msg &= @CRLF&@CRLF&'Location: '&$g_cDebug_identsVec[0]&@CRLF&@CRLF& _ 'Names: '&$g_cDebug_identsVec[1]&@CRLF&@CRLF $msg &= 'Current name: '&$g_cDebug_identsVec[2] Local $dummy _cDebug_VarSizeDialog('Comparison of detected structure with the one in the call',$msg,'e',$dummy) EndIf EndFunc Func _cDebug_DumpUserStruct($id,$tStruct,$tag, ByRef $paddedTagAr) Local Enum $eElemType=0,$eElemSize,$eElemText Local Enum $eTagType=0,$eTagMaxIx,$eTagQpads,$eTagText Local Enum $eTqUtype=0,$eTqSize,$eTqSigned,$eTqDtype Local $len = DllStructGetSize($tStruct) Local $ptrStruc = DllStructGetPtr($tStruct) Local $ret = '<Struct> (' & $len & ' byte'&($len<>1 ? 's' : '')&') @:' & Hex($ptrStruc) $ret &= ' -*- PER CALL -*-'&@CRLF Local $elemsAr = _cDebug_ParseTag($tag) Local $quantum,$type,$qIxs,$name,$iElGD,$data,$n,$m,$q,$lenPerPtrs,$elsLen=0,$padLen,$t,$size,$iPad=-1 ReDim $paddedTagAr[100][4] Local $widElemNbr = StringLen(UBound($elemsAr,1)-1) Local $widTypeNameSize = 0 For $i = 0 To UBound($elemsAr,1)-1 $type = $elemsAr[$i][$eElemType] If Not ($type='struct' Or $type='endstruct' Or $type='align') Then $n = StringLen($elemsAr[$i][$eElemText]) If $elemsAr[$i][$eElemSize]<>1 Then $n += StringLen('['&$elemsAr[$i][$eElemSize]&']') EndIf If $n>$widTypeNameSize Then $widTypeNameSize = $n EndIf EndIf Next Local $line,$nextPtr,$bExtendsWarned=False,$iElGD=0 Local $ptr = DllStructGetPtr($tstruct) $n = StringLen($id) - StringLen(StringStripWS($id,1)) ; strip left Local $indent = StringFormat('%'&$n&'s','')&$g_cDebug_tab For $iEl = 0 To UBound($elemsAr,1)-1 $line = '' $type = $elemsAr[$iEl][$eElemType] If $type='struct' Or $type='endstruct' Or $type='align' Then $ret &= $indent&StringFormat('%'&($widElemNbr+2)&'s','')&$elemsAr[$iEl][$eElemText]&@CRLF ContinueLoop EndIf $iElGD += 1 $id = $indent&StringFormat('%'&$widElemNbr&'d',$iElGD+1)&' ' $qIxs = $elemsAr[$iEl][$eElemSize] If $qIxs>1 Then $t &= '['&$qIxs&']' EndIf $id &= StringFormat('%-'&$widTypeNameSize&'s',$t) $line &= _cDebug_DumpElementData($indent,$tStruct,$type,$elemsAr[$iel][$eElemText],$qIxs,$iElGD-1,$widElemnbr, _ $widTypenameSize)&@CRLF ; ref 0 $ret &= $line $line = '' $iPad += 1 If $iPad>UBound($paddedTagAr,1)-1 Then ReDim $paddedTagAr[$iPad+100][4] EndIf $paddedTagAr[$iPad][$eTagType] = $type $paddedTagAr[$iPad][$eTagMaxIx] = $qIxs $paddedTagAr[$iPad][$eTagText] = $elemsAr[$iEl][$eElemText] $nextPtr = DllStructGetPtr($tStruct,$iElGD+1) If @error=2 Then ; if element out of range $nextPtr = DllStructGetPtr($tStruct)+DllStructGetSize($tStruct) EndIf $lenPerPtrs = Number($nextPtr-$ptrStruc) ; Find size of type $quantum = -2 For $j = 0 To UBound($g_cDebug_typeQuantumSignedsAr,1)-1 If $g_cDebug_typeQuantumSignedsAr[$j][$eTqUtype]=$type Then $quantum = $g_cDebug_typeQuantumSignedsAr[$j][$eTqSize] ExitLoop EndIf Next If $quantum=-2 Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,'_cDebug_DumpStruct():'&@CRLF& _ 'Size of a '&$type&' unknown') EndIf $elsLen += $quantum*$qIxs $padLen = $lenPerPtrs -$elsLen $paddedTagAr[$iPad][$eTagQpads] = $padLen If (Not $bExtendsWarned) And $padLen<0 Then $ret &= '**?* Element extends beyond structure *?*'&@CRLF&@CRLF _cDebug_ReportWarning('Element '&$iElGD&' "'&$elemsAr[$iEl][$eElemText]&' " extends beyond structure') $bExtendsWarned = True EndIf If $padLen>0 Then $line &= $indent&'<padding> '&$padLen& ' byte'&(($padLen<>1) ? 's' : '') $ret &= $line&@CRLF $line = '' EndIf $elsLen += $padLen Next $ret = StringTrimRight($ret,2) ; remove @CRLF ReDim $paddedTagAr[$iPad+1][4] Return $ret EndFunc Func _cDebug_DumpElementData($indent,$tStruct,$jchdType,$rptType,$qIxs,$iEl,$widElnbr,$widCol2) ; iEl ref 0 Local $data,$ret,$n,$id If $jchdType='char' Or $jchdType='wchar' _ Or (($jchdType='byte' Or $jchdType='ubyte') And $qIxs>$g_cDebug_elementLimit) Then $data = DllStructGetData($tStruct,$iEl+1) If @error Then _cDebug_ReportErrorAndExit('DllStructGetData failed at line '&@ScriptLineNumber&' with @error='& _ @error&' $iEl='&$iEl) EndIf $id = $indent&StringFormat('%'&$widElnbr&'d',$iEl+1) & _ StringFormat(' %-'&$widCol2&'s',$rptType&'['&$qIxs&']')&' => ' $ret = _cDebug_ReportScalar($id,$data,'') Else If $qIxs=1 Then ; scalar $data = DllStructGetData($tStruct,$iEl+1) If @error Then _cDebug_ReportErrorAndExit('DllStructGetData failed at line '&@ScriptLineNumber&' with @error='& _ @error&' $iEl+1='&$iEl+1) EndIf $id = $indent&StringFormat('%'&$widElnbr&'d',$iEl+1) & StringFormat(' %-'&$widCol2&'s',$rptType)&' => ' $ret = _cDebug_ReportScalar($id,$data,'') Else $id = $indent&StringFormat('%'&$widElnbr&'d',$iEl+1) & _ StringFormat(' %-'&$widCol2&'s',$rptType&'['&$qIxs&']') $ret = $id&@CRLF $n = $qIxs If $qIxs>$g_cDebug_elementLimit Then $n = $g_cDebug_elementLimit EndIf Local $widIxs = StringLen($n) For $ix = 1 To $qIxs If $ix > $g_cDebug_elementLimit Then $n = $qIxs-$g_cDebug_elementLimit $ret &= $indent&StringFormat('%'&($widElnbr+$widCol2)&'s','')&' ... '& _ $n& ' more element'&($n>1 ? 's' : '')&@CRLF ExitLoop EndIf $id = $indent&StringFormat('%'&($widElnbr+$widCol2)&'s','') & _ '['&StringFormat('%'&$widIxs&'d',$ix)&'] => ' If @error Then _cDebug_ReportErrorAndExit('DllStructGetData failed at line '&@ScriptLineNumber&' with @error='&@error& _ ' $iEl+1='&($iEl+1)&' $ix='&$ix) EndIf $data = DllStructGetData($tStruct,$iEl+1,$ix) $ret &= _cDebug_ReportScalar($id,$data,'')&@CRLF Next $ret = StringTrimRight($ret,2) ; @CRLF EndIf EndIf Return $ret EndFunc Func _cDebug_ParseTag($tag) If StringRight($tag,1)=';' Then $tag = StringTrimRight($tag,1) EndIf Local $vec = StringSplit($tag,';',0+2) ; char,0-based Local Enum $eElemType=0,$eElemSize,$eElemText ; e.g int a => 'int' 1 int a ; struct => 'struct' 1 struct ; endstruct => 'endstruct' 1 endstruct ; align 4 => 'align' 4 align ; char c[4] => 'char' 4 char c ; char c [4] => 'char' 4 char c ; int64 => 'int64' 12 long ; long [12] => 'long' 12 long ; byte => 'byte' 1 byte Local $resVec[5] $resVec[0] = '^\s*(\w+)\s*$' ; struct,endstruc,byte,align,int64,byte $resVec[1] = '^\s*(\w+)\s+([0-9])+\s*$' ; align 4 $resVec[2] = '^\s*(\w+)\s+(\w+)\s*\[([0-9]+)+\]*\s*$' ; char c[4] $resVec[3] = '^\s*(\w+)\s+(\w+)\s*$' ; int a $resVec[4] = '^\s*(\w+)\s*\[([0-9]+)\]\s*$' ; long[12] Local $capsVec,$elemsAr[UBound($vec)][3],$regExpCase For $iEl = 0 To UBound($vec)-1 $regExpCase = -1 For $j = 0 To UBound($resVec)-1 $regExpCase = -1 $capsVec = StringRegExp($vec[$iEl],$resVec[$j],1) If Not @error Then Switch $j Case 0 $elemsAr[$iEl][$eElemType] = $capsVec[0] $elemsAr[$iEl][$eElemSize] = 1 $elemsAr[$iEl][$eElemText] = $capsVec[0] $regExpCase = 0 Case 1 $elemsAr[$iEl][$eElemType] = $capsVec[0] $elemsAr[$iEl][$eElemSize] = Int($capsVec[1]) $elemsAr[$iEl][$eElemText] = $capsVec[0]&' '&$capsVec[1] $regExpCase = 1 Case 2 $elemsAr[$iEl][$eElemType] = $capsVec[0] $elemsAr[$iEl][$eElemSize] = Int($capsVec[2]) $elemsAr[$iEl][$eElemText] = $capsVec[0]&' '&$capsVec[1] ;~ $elemsAr[$iEl][$eElemText] = $capsVec[0]&' '&$capsVec[1]&'['&$capsVec[2]&']' $regExpCase = 2 Case 3 $elemsAr[$iEl][$eElemType] = $capsVec[0] $elemsAr[$iEl][$eElemSize] = 1 $elemsAr[$iEl][$eElemText] = $capsVec[0]&' '&$capsVec[1] $regExpCase = 3 Case 4 $elemsAr[$iEl][$eElemType] = $capsVec[0] $elemsAr[$iEl][$eElemSize] = Int($capsVec[1]) $elemsAr[$iEl][$eElemText] = $capsVec[0] ;~ $elemsAr[$iEl][$eElemText] = $capsVec[0]&'['&$capsVec[1]&']' $regExpCase = 4 EndSwitch ExitLoop EndIf Next If $regExpCase=-1 Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber, _ 'cDebug_ParseTag():'&@CRLF&'Unhandled struct element "'&$vec[$iEl]) EndIf Next Return $elemsAr EndFunc ; Thanks to jvhd Func _cDebug_DetectTag($tStruct) ; returns ref 0 ; type,maxIdx for Binary, maxIdx is 1 Local $retAr[100][2],$nbElem=1,$irow=-1,$data,$varType,$idx,$incr,$maxIdx,$readValue,$elem,$oldValue While True $data = DllStructGetData($tStruct, $nbElem) If @error = 2 Then ExitLoop ; if element out of range so beyond struct $varType = VarGetType($data) $idx = 1 $incr = 0 ; determine max index of element While 1 DllStructGetData($tStruct, $nbElem, 2 * $idx) If @error = 3 Then ExitLoop ; index out of range or unknown $incr = $idx $idx *= 2 WEnd ; index is in [$idx, (2 * $idx) - 1] $idx += $incr Do DllStructGetData($tStruct, $nbElem, $idx) If @error = 3 Then ; if element is out of range ; approach is asymetric (upper bound is too big) $idx -= ($incr = 1) ? 1 : $incr / 2 Else $idx += Int($incr / 2) EndIf $incr = Int($incr / 2) Until $incr = 0 $maxIdx = $idx Switch $varType Case "Int32", "Int64" $data = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, 0x7777666655554433, 1) $readValue = DllStructGetData($tStruct, $nbElem, 1) Switch $readValue Case 0x7777666655554433 $elem = "int64" ; alias: uint64 ; alias: int_ptr(x64), long_ptr(x64), lresult(x64), lparam(x64) ; alias: uint_ptr(x64), ulong_ptr(x64), dword_ptr(x64), wparam(x64) Case 0x55554433 DllStructSetData($tStruct, $nbElem, 0x88887777, 1) $readValue = DllStructGetData($tStruct, $nbElem, 1) $elem = ($readValue > 0 ? "uint" : "int") ; int aliases: long, bool, int_ptr(x86), long_ptr(x86), lresult(x86), lparam(x86); ; uint aliases: ulong, dword, uint_ptr(x86), ulong_ptr(x86), dword_ptr(x86), wparam(x86) Case 0x4433 DllStructSetData($tStruct, $nbElem, 0x8888, 1) $readValue = DllStructGetData($tStruct, $nbElem, 1) $elem = ($readValue > 0 ? "ushort" : "short") Case 0x33 $elem = "byte" ; alias: ubyte EndSwitch DllStructSetData($tStruct, $nbElem, $data, 1) Case "String" $oldValue = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, ChrW(0x2573), 1) $readValue = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, $oldValue, 1) $elem = ($readValue = ChrW(0x2573) ? "wchar" : "char") Case "Binary" Local $blen = BinaryLen($data) $elem = "byte" $maxIdx = $blen Case "Ptr" $elem = "ptr" ; alias: hwnd, handle Case "Double" $oldValue = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, 10^-15, 1) $readValue = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, $oldValue, 1) $elem = ($readValue = 10^-15 ? "double" : "float") EndSwitch $irow += 1 If $irow>UBound($retAr,1)-1 Then ReDim $retAr[$irow+100][2] EndIf $retAr[$irow][0] = $elem $retAr[$irow][1] = $maxIdx $nbElem += 1 WEnd ReDim $retAr[$irow+1][2] Return $retAr EndFunc Func _cDebug_DumpDetectedStruct($id,$tStruct, ByRef $detectedElementTypes, ByRef $paddedTagAr) Local $n,$ret='',$qIxs,$widElnbr,$t,$iPad=-1,$qPadBytes Local Enum $eTagJchdType=0,$eTagMaxIx,$eTagQpads,$eTagText Local $len = DllStructGetSize($tStruct) Local $ptrStruc = DllStructGetPtr($tStruct) Local $ret = '<Struct> (' & $len & ' byte'&($len<>1 ? 's' : '')&') @:' & Hex($ptrStruc) $ret &= ' -*- DETECTED -*-'&@CRLF Local $tagAr = _cDebug_DetectTag($tStruct) ; base 0 Local $widElnbr = StringLen(UBound($tagAr,1)+1) ReDim $tagAr[UBound($tagAr,1)][$eTagText+1] Local $widTypeSize = 0 For $iEl = 0 To UBound($tagAr,1)-1 Switch $tagAr[$iEl][$eTagJchdType] Case 'byte' $t = 'u1byte (byte)' Case 'ushort' $t = 'u2byte (ushort)' Case 'uint' $t = 'u4byte (uint)' Case 'int' $t = 's4byte (int)' Case 'int64' $t = '~8byte (int64)' Case Else $t = $tagAr[$iEl][$eTagJchdType] EndSwitch $tagAr[$iEl][$eTagText] = $t $n = StringLen($t) + 9 ; e.g. 'u2byte ()' If $tagAr[$iEl][$eTagMaxIx]>1 Then $n += StringLen($tagAr[$iEl][$eTagMaxIx])+2 ; '[...] EndIf If $n>$widTypeSize Then $widTypeSize = $n EndIf Next ReDim $paddedTagAr[100][4] Local $ptr,$typeSize,$nextPtr,$line $ptr = DllStructGetPtr($tStruct) $n = StringLen($id) - StringLen(StringStripWS($id,1)) ; strip left Local $indent = StringFormat('%'&$n&'s','')&$g_cDebug_tab For $iEl = 0 To UBound($tagAr,1)-1 $id = $indent&StringFormat('%'&$widElnbr&'d',$iEl+1)&' ' $t = $tagAr[$iEl][$eTagText] $qIxs = $tagAr[$iEl][$eTagMaxIx] $id &= StringFormat('%-'&$widTypeSize&'s',$t) $line &= _cDebug_DumpElementData($indent,$tStruct,$tagAr[$iEl][$eTagJchdType],$tagAr[$iEl][$eTagText], _ $qIxs,$iEl,$widElnbr,$widTypeSize)&@CRLF ; ref 0 $ret &= $line $line = '' $iPad += 1 If $iPad>UBound($paddedTagAr,1)-1 Then ReDim $paddedTagAr[$iPad+100][4] EndIf $paddedTagAr[$iPad][$eTagJchdType] = $tagAr[$iEl][$eTagJchdType] $paddedTagAr[$iPad][$eTagMaxIx] = $tagAr[$iEl][$eTagMaxIx] $nextPtr = DllStructGetPtr($tStruct,$iEl+2) If @error=2 Then ; out of range $nextPtr = DllStructGetPtr($tStruct)+DllStructGetSize($tStruct) EndIf If StringInStr(',byte,ushort,uint,int,int64,ptr,',','&$tagAr[$iEl][$eTagJchdType]&',') Then $detectedElementTypes = _cDebug_UpdateListOfDllElements($detectedElementTypes,$tagAr[$iEl][$eTagJchdType]) EndIf Local $diffPtrs = Number($nextPtr-$ptr) Switch $tagAr[$iEl][$eTagJchdType] Case 'Int64','double' $typeSize = 8 Case 'int','uint','float' $typeSize = 4 Case 'ushort','short','wchar' $typeSize = 2 Case 'char','byte' $typeSize = 1 Case 'ptr' $typeSize = @AutoItX64 ? 8 : 4 EndSwitch Local $elSize = $tagAr[$iEl][$eTagMaxIx]*$typeSize $qPadBytes = $diffPtrs-$elSize If $qPadBytes<>0 Then $ret &= $indent&'<padding> '&$qPadBytes&' byte'&($qPadBytes<>1 ? 's' : '')&@CRLF EndIf $paddedTagAr[$iPad][$eTagQpads] = $qPadBytes $ptr = $nextPtr Next ReDim $paddedTagAr[$iPad+1][4] $ret = StringTrimRight($ret,2) ; #CRLF Return $ret EndFunc Func _cDebug_DumpStr($id,$var) Local $ret,$n,$vec[0],$indent Local $bStringIsObject = StringInStr($id,'<Object>') Local $len = StringLen($var) If $g_cDebug_bDoLineBreaksInStrings Or $bStringIsObject Then If $var='' Then $ret = $id&$g_cDebug_stringDelim&$g_cDebug_stringDelim ElseIf StringInStr($var,Chr(3)) Then _cDebug_ReportWarning( _ "String contains Chr(3) which is used as a temporary, so value will be reported as ''") $ret = $id&$g_cDebug_stringDelim&$g_cDebug_stringDelim Else $var = StringReplace($var,@CRLF,Chr(3)) $var = StringReplace($var,@CR,Chr(3)) $var = StringReplace($var,@LF,Chr(3)) $var = StringReplace($var,Chr(3),@CRLF) $vec = StringSplit($var,@CRLF,1+2) ; 0-based,string If $bStringIsObject Then $ret = $id&' '&$vec[0] Else $ret = $id&$g_cDebug_stringDelim&$vec[0] EndIf $n = StringLen($id)+1 $indent = StringFormat('%'&$n&'s','') For $i = 1 To UBound($vec)-1 If $i>$g_cDebug_elementLimit-1 Then $n = UBound($vec) - $i $ret &= @CRLF&$indent&'... '&$n&' more line'&($n=1 ? '' : 's') ExitLoop EndIf $ret &= @CRLF&$indent&$vec[$i] Next If Not $bStringIsObject Then $ret &= $g_cDebug_stringDelim endif EndIf Else If $var='' Then $ret = $g_cDebug_stringDelim&$g_cDebug_stringDelim ElseIf StringInStr($var,Chr(255)) Then _cDebug_ReportWarning( _ "String contains Chr(255) which is used as a temporary, so value will be reported as ''") $ret = $g_cDebug_stringDelim&$g_cDebug_stringDelim Else If $len>$g_cDebug_elementLimit*2 Then Local $vec[2] $vec[0] = StringLeft($var,$g_cDebug_elementLimit) $vec[1] = StringRight($var,$g_cDebug_elementLimit) Else Local $vec = [$var] EndIf For $i = 0 To UBound($vec)-1 $vec[$i] = StringReplace($vec[$i],"'",Chr(255)) ; e.g. replace VT with <0x0B> but single quote mark causes $var to be '' $vec[$i] = Execute("'" & StringRegExpReplace( _ $vec[$i], "([\p{Cc}])", "<0x' & Hex(AscW('$1'), 2) & '>") & "'") $vec[$i] = StringReplace($vec[$i],Chr(255),"'") Next $ret = $id&$g_cDebug_stringDelim&$vec[0] If $len>$g_cDebug_elementLimit*2 Then $ret &= ' ... '&$vec[1] EndIf $ret &= $g_cDebug_stringDelim EndIf EndIf Return $ret EndFunc Func _cDebug_EvaluateGlobalVar($cDebug_param) Local $___cDebug_ret If StringLeft($cDebug_param,1)='$' Then $cDebug_param = StringTrimLeft($cDebug_param,1) EndIf If IsDeclared($cDebug_param)=$DECLARED_GLOBAL Then Local $___cDebug_ret = Eval($cDebug_param) Else SetError(1) ; the Help implies that @error from Eval() may not be reliable! EndIf Return $___cDebug_ret EndFunc Func _cDebug_UpdateClipboard($text) Static Local $bAppendToClipboard=False Local $clip,$msg,$clipError,$msg $clip = ClipGet() $clipError = @error If $clipError>=2 Then Switch $clipError Case 2 ; non-text on Clipboard $msg = 'Because the Clipboard contains non-textual data, your results will replace the its contents' MsgBox($MB_ICONINFORMATION+$MB_TASKMODAL,'cDebug warning',$msg) Case 3,4 $msg = 'Because the Clipboard cannot be accessed, your results are not copied to it' MsgBox($MB_ICONINFORMATION+$MB_TASKMODAL,'cDebug warning',$msg) Return EndSwitch EndIf If $bAppendToClipboard Then If $clipError=1 Then ; if empty ClipPut($text) Else ClipPut($clip&@CRLF&$text) EndIf Else If $clipError=2 Then ; non-text on clipboard $bAppendToClipboard = True Else Local $ans = MsgBox($MB_YESNOCANCEL+$MB_ICONQUESTION+$MB_TASKMODAL,"cDebug", _ "Clear the Clipboard before copying to it?") Switch $ans Case 6 ;Yes ClipPut($text) $bAppendToClipboard = Not $g_cDebug_bAlwaysAskClearClipboard Case 7; no ClipPut($clip&@CRLF&$text) $bAppendToClipboard = Not $g_cDebug_bAlwaysAskClearClipboard Case 3 ; cancel ; do nthing EndSwitch EndIf EndIf EndFunc ; Sort numerics before strings Func _cDebug_GetPosOfFirstUnquotedStringInString($str,$substr) Local $ret=0,$ch For $i = 1 To StringLen($str)-StringLen($substr)+1 $ch = StringMid($str,$i,1) If $ch='"' Or $ch="'" Then $i = StringInStr($str,$ch,0,1,$i+1) ; case-insensitive,1st occurence, start at $i+1 If $i=0 Then $ret = 0 ExitLoop EndIf ElseIf StringMid($str,$i,StringLen($substr))=$substr Then $ret = $i ExitLoop EndIf Next Return $ret EndFunc Func _cDebug_StringSplitonUnquotedString($str,$substr) Local $rec='',$pst=1,$ch,$retVec[10],$qEls=0 For $i = 1 To StringLen($str)-StringLen($substr)+1 $ch = StringMid($str,$i,1) If $ch='"' Or $ch="'" Then $i = StringInStr($str,$ch,0,1,$i+1) ; case-insensitive,1st occurence, start at $i+1 If $i=0 Then ExitLoop EndIf ElseIf StringMid($str,$i,StringLen($substr))=$substr Then $qEls += 1 If $qEls>UBound($retvec) Then ReDim $retvec[UBound($retvec)+10] EndIf $retvec[$qEls-1] = StringMid($str,$pst,$i-$pst) $pst = $i+StringLen($substr) EndIf Next $qEls += 1 If $qEls>UBound($retvec) Then ReDim $retvec[UBound($retvec)+10] EndIf $retvec[$qEls-1] = StringMid($str,$pst,$i-$pst) ReDim $retvec[$qEls] Return $retvec EndFunc #cs maps Func _cDebug_SortMapKeys($numStrsVec) Local $numsVec[UBound($numStrsVec)],$strsVec[UBound($numStrsVec)] Local $iN = -1 Local $iS = -1 For $i = 0 To UBound($numStrsVec)-1 If IsNumber($numStrsVec[$i]) Then $iN += 1 $numsVec[$iN] = $numStrsVec[$i] Else $iS += 1 $strsVec[$iS] = $numStrsVec[$i] EndIf Next ReDim $numsVec[$iN+1] ReDim $strsVec[$iS+1] ; determines whether numeric or string sort needed fron one element - sort of! If UBound($numsVec)>1 Then _cDebug_ArrayQuickSort1D($numsVec,0,UBound($numsVec)-1,0) EndIf If UBound($strsVec)>1 Then _cDebug_ArrayQuickSort1D($strsVec,0,UBound($strsVec)-1,$STR_CASESENSE) EndIf Local $retVec[UBound($numStrsVec)] For $i = 0 To $iN $retVec[$i] = $numsVec[$i] Next For $i = 0 To $iS $retVec[$iN+1+$i] = $strsVec[$i] Next Return $retVec EndFunc #ce maps Func _cDebug_ReportWarning($msg) $msg &= @CRLF&@CRLF $msg &= 'Location: '&$g_cDebug_identsVec[0]&@CRLF&@CRLF&'Names: '&$g_cDebug_identsVec[1]&@CRLF&@CRLF If $g_cDebug_identsVec[2]<>'' Then $msg &= 'Current name: '&$g_cDebug_identsVec[2]&@CRLF&@CRLF EndIf Local $dummy _cDebug_VarSizeDialog('cDebug Warning',$msg,'e',$dummy) EndFunc Func _cDebug_ReportErrorAndExit($msg) $msg &= @CRLF&@CRLF $msg &= 'Location: '&$g_cDebug_identsVec[0]&@CRLF&@CRLF&'Names: '&$g_cDebug_identsVec[1]&@CRLF&@CRLF If $g_cDebug_identsVec[2]<>'' Then $msg &= 'Current name: '&$g_cDebug_identsVec[2]&@CRLF&@CRLF EndIf $msg &= 'Aborting the script' Local $dummy _cDebug_VarSizeDialog('cDebug Error',$msg,'',$dummy) Exit EndFunc Func _cDebug_ReportCodingErrorAndExit($line,$msg) $msg = 'At line '&$line&': '&$msg&@CRLF&@CRLF $msg &= 'Please report this error to c.haslam in Example Scripts on the Forum'&@CRLF&@CRLF&'Aborting the script' Local $dummy _cDebug_VarSizeDialog('cDebug Coding Error',$msg,'',$dummy) Exit EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: _cDebug_GUICtrlGetFont ; Description ...: Gets the font of a GUI Control ; Syntax.........: _cDebug_GUICtrlGetFont( [$hWnd] ) ; Parameters ....: $hWnd - [optional] ControlID or Handle of the control. ; Default is last created GUICtrl... (-1) ; ; Return values .: Success - Array[5] with options of font: ; [0] - FontSize (~ approximation) ; [1] - font weight (400 = normal). ; [2] - italic:2 underlined:4 strike:8 char format (styles added together, ; 2+4 = italic and underlined). ; [3] - The name of the font in use. ; [4] - font quality to select (PROOF_QUALITY=2 is default in AutoIt). ; ; Failure - Array[5] with empty fields, @error set to nonzero ; ; Author ........: KaFu, Prog@ndy ; ; Comments.......: The FontSize returned is an approximation of the actual FontSize used for the control. ; The height of the font returned by GetObject is the height of the font's character cell or ; character in logical units. ; The character height value (also known as the em height) is the character cell height value ; minus the internal-leading value. ; The font mapper interprets the value specified in lfHeight. The result returned by the font ; mapper is not easily reversible ; The FontSize calculated below is an approximation of the actual size used for the analyzed ; control, qualified enough to use in another call to the font mapper resulting in the same ; font size as the the original font. ; MSDN.. ........: Windows font Mapping: http://msdn.microsoft.com/en-us/library/ms969909(loband).aspx ; =============================================================================================================================== ; http://www.autoitscript.com/forum/topic/124526-guictrlgetfont Func _cDebug_GUICtrlGetFont($hWnd = -1) Local $aReturn[5], $hObjOrg If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) If Not IsHWnd($hWnd) Then Return SetError(1, 0, $aReturn) Local $hFont = _SendMessage($hWnd, $WM_GETFONT) If Not $hFont Then Return SetError(2, 0, $aReturn) Local $hDC = _WinAPI_GetDC($hWnd) $hObjOrg = _WinAPI_SelectObject($hDC, $hFont) Local $tFONT = DllStructCreate($tagLOGFONT) Local $aRet = DllCall('gdi32.dll', 'int', 'GetObjectW', 'ptr', $hFont, 'int', DllStructGetSize($tFONT), 'ptr', _ DllStructGetPtr($tFONT)) If @error Or $aRet[0] = 0 Then _WinAPI_SelectObject($hDC, $hObjOrg) _WinAPI_ReleaseDC($hWnd, $hDC) Return SetError(3, 0, $aReturn) EndIf ; Need to extract FontFacename separately => DllStructGetData($tFONT, 'FaceName') is only valid if ; FontFacename has been set explicitly! $aRet = DllCall("gdi32.dll", "int", "GetTextFaceW", "handle", $hDC, "int", 0, "ptr", 0) Local $nCount = $aRet[0] Local $tBuffer = DllStructCreate("wchar[" & $aRet[0] & "]") Local $pBuffer = DllStructGetPtr($tBuffer) $aRet = DllCall("Gdi32.dll", "int", "GetTextFaceW", "handle", $hDC, "int", $nCount, "ptr", $pBuffer) If @error Then _WinAPI_SelectObject($hDC, $hObjOrg) _WinAPI_ReleaseDC($hWnd, $hDC) Return SetError(4, 0, $aReturn) EndIf $aReturn[3] = DllStructGetData($tBuffer, 1) ; FontFacename $aReturn[0] = Round((-1 * DllStructGetData($tFONT,'Height'))* 72/_WinAPI_GetDeviceCaps($hDC,90),1) ; $LOGPIXELSY = 90 => DPI aware _WinAPI_SelectObject($hDC, $hObjOrg) _WinAPI_ReleaseDC($hWnd, $hDC) $aReturn[1] = DllStructGetData($tFONT, 'Weight') $aReturn[2] = 2 * (True = DllStructGetData($tFONT, 'Italic')) + 4 * (True = DllStructGetData($tFONT, 'Underline')) + 8 * (True = DllStructGetData($tFONT, 'StrikeOut')) $aReturn[4] = DllStructGetData($tFONT, 'Quality') Return $aReturn EndFunc ;==>_cDebug_GUICtrlGetFont Func _cDebug_UpdateListOfDllElements($types,$element) If Not StringInStr(','&$types&',',',&'&$element&',') Then $types &= ','&$element EndIf Return $types EndFunc Func _cDebug_OutputStructNote() Local $ret = '' If $g_cDebug_sStructElementTypes<>'' Then Local $tStruct = DllStructCreate('int_ptr') Local $bX86 = DllStructGetSize($tStruct)=4 $ret &= @CRLF&'Note'&@CRLF $ret &= '----'&@CRLF $ret &= 'Structs are marked DETECTED if:'&@CRLF $ret &= '- No tag is specified or'&@CRLF $ret &= '- A tag is specified and ! follows {, forcing detection.'&@CRLF $ret &= 'When such structs are detected:'&@CRLF If StringInStr($g_cDebug_sStructElementTypes,'byte') Then $ret &= '- u1byte (unsigned 1-byte) is often byte but it may be boolean'&@CRLF EndIf If StringInStr(','&$g_cDebug_sStructElementTypes&',',',ushort,') Then $ret &= '- u2byte (unsigned 2-byte) is often ushort but may be word'&@CRLF EndIf If StringInStr(','&$g_cDebug_sStructElementTypes&',',',int,') Then $ret &= '- s4byte (signed 4-byte) is often int but may be ' If $bx86 Then $ret &= 'long, bool, int_ptr, long_ptr, lresult or lparam'&@CRLF Else $ret &= 'long or bool'&@CRLF EndIf EndIf If StringInStr(','&$g_cDebug_sStructElementTypes&',',',uint,') Then $ret &= '- u4byte (unsigned 4-byte) is often uint but it may be ' If $bx86 Then $ret &= 'ulong, dword, uint_ptr, ulong_ptr, dword_ptr or wparam'&@CRLF Else $ret &= 'ulong or dword'&@CRLF EndIf EndIf If StringInStr($g_cDebug_sStructElementTypes,'int64') Then $ret &= '- ~8byte (signed or unsigned 8-byte) is often int64, but may be ' If $bX86 Then $ret &= ' uint64'&@CRLF Else $ret = 'uint64, int_ptr, long_ptr, lresult, lparam,int_ptr, ulong_ptr, dword_ptr or wparam'&@CRLF EndIf EndIf If StringInStr(','&$g_cDebug_sStructElementTypes&',',',ptr,') Then $ret &= '- A ptr is '&($bx86 ? 4 : 8)&' bytes. It may be hwnd or handle'&@CRLF EndIf EndIf Return $ret EndFunc ; if possible, move GUI so doesn't cover text in SciTE, possibly moving SciTE Func _cDebug_AvoidHidingCodeInSciTE($optBtns, ByRef $leftClient, ByRef $widClient, ByRef $widEdt, ByRef $leftOK, _ ByRef $leftCopy, ByRef $leftExit, ByRef $leftLimit) Local $n,$widDelta $leftClient = (@DesktopWidth-$widClient)/2 Local $hndlSciTE = WinGetHandle('[CLASS:SciTEWindow]') Local $vec = WinGetPos($hndlSciTE) ; If SciTe maximized, returns -4,-4,1928,1060 ! Local $leftSciTE = $vec[0],$topSciTE = $vec[1], $widSciTE = $vec[2],$htSciTE = $vec[3] Local $bMaxed = BitAND(WinGetState($hndlSciTE),32)=32 ; if SciTE is right of centre and no wider than than half the Desktop Local $bLeftHalfOrLess = ($leftSciTE>0 ? $leftSciTE : 1)+$widSciTE/2 >= @DesktopWidth/2 If $bLeftHalfOrLess And Not $bMaxed Then ; ; $WIN_STATE_MAXIMIZED $leftSciTE = @DesktopWidth-$widSciTE If Not $bMaxed Then WinMove($hndlSciTE,'',$leftSciTE,$topSciTE,$widSciTE) ; move as far right as possible EndIf Local $spaceToLeft = @DesktopWidth- $widSciTE - $widClient If $spaceToLeft>20 Then $leftClient = $leftSciTE - $widClient - 20 Else $leftClient = 1 EndIf Local $space = @DesktopWidth - $leftSciTE - 20 If $space<$widClient Then $n = $widClient $widClient = @DesktopWidth/2 - $leftClient - 20 $widDelta = $n - $widClient $widEdt -= $widDelta $leftOK -= $widDelta $leftCopy -= $widDelta If StringInStr($optBtns,'e') Then $leftExit -= $widDelta EndIf If StringInStr($optBtns,'l') Then $leftLimit -= $widDelta EndIf EndIf Else ; SciTE to left of centre or SciTE maximized If Not $bMaxed Then WinMove($hndlSciTE,'',1,$topSciTE,$widSciTE,$htSciTE) ; move as far left as possible EndIf If $bMaxed Then $leftClient = @DesktopWidth/2+1 Else $leftClient = $widSciTE + 20 EndIf Local $space = @DesktopWidth - $leftClient If $space<$widClient Then $n = $widClient $widClient = @DesktopWidth - $leftClient - 6 $widDelta = $n - $widClient $widEdt -= $widDelta $leftOK -= $widDelta $leftCopy -= $widDelta If StringInStr($optBtns,'e') Then $leftExit -= $widDelta EndIf If StringInStr($optBtns,'l') Then $leftLimit -= $widDelta EndIf EndIf EndIf EndFunc Func _ChangeElementLimitForDebug($limit) If $limit<1 Then MsgBox($MB_ICONERROR+$MB_TASKMODAL,'cDebug','_ChangeDebugArrayElementLimit()'&@CRLF&@CRLF& _ 'Attempt to set limit to '&$limit&' failed'&@CRLF&@CRLF&'Aborting the script') Exit EndIf $g_cDebug_elementLimit = $limit If $g_cDebug_elementLimit=0 Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,'$g_cDebug_elementLimit=0') ElseIf $g_cDebug_elementLimit='' Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,"$g_cDebug_elementLimit=''") EndIf EndFunc ; Only updates $limit if OK clicked Func _cDebug_DlgChangeLimit($parent, ByRef $limit) Local $displayManyElements = 'Display up to '&$g_cDebug_LargeElementLimit&' element'& _ ($g_cDebug_LargeElementLimit>1 ? 's' : '') Local $t If $g_cDebug_ElementLimit=1 Then $t = 'For arrays and structs, the first element is displayed.' Else $t = 'For arrays and structs, the first '&$g_cDebug_ElementLimit&' elements are displayed.' EndIf #Region ### START Koda GUI section ### Form=F:\AutoIt scripts\cDebug ChangeLimit.kxf MODIFIED Local $frmChangeLimit = GUICreate("cDebug - Change element limit", 465, 204, -1, -1) GUICtrlCreateLabel($t, 16, 16, 448, 17) GUICtrlCreateLabel("For arrays, this is on a per-subscript basis.", 16, 40, 199, 17) Local $inp = GUICtrlCreateInput("inp", 136, 96, 49, 21, BitOR($GUI_SS_DEFAULT_INPUT,$ES_RIGHT,$ES_NUMBER)) Local $btnCancel = GUICtrlCreateButton("Cancel", 392, 152, 49, 25) Local $btnOK = GUICtrlCreateButton("OK", 336, 152, 33, 25, $BS_DEFPUSHBUTTON) GUICtrlCreateLabel("The element limit also affects how much of other types of values are shown.", 16, 64, 360, 17) Local $radLimit = GUICtrlCreateRadio("Enter the new limit", 16, 96, 113, 17) Local $radAll = GUICtrlCreateRadio($displayManyElements, 16, 128, 233, 17) GUISetState(@SW_SHOW) ;~ Local $frmChangeLimit = GUICreate("CDebug - Change element limit", 465, 204, -1, -1) ;~ GUICtrlCreateLabel("For elements of arrays and structs, the first "&$g_cDebug_elementLimit&" elements are displayed.", 16, 16, 448, 17) ;~ GUICtrlCreateLabel("For arrays, this is on a per-subscript basis.", 16, 40, 199, 17) ;~ Local $inp = GUICtrlCreateInput("inp", 136, 96, 49, 21, BitOR($GUI_SS_DEFAULT_INPUT,$ES_RIGHT,$ES_NUMBER)) ;~ Local $btnCancel = GUICtrlCreateButton("Cancel", 392, 152, 49, 25) ;~ Local $btnOK = GUICtrlCreateButton("OK", 336, 152, 33, 25, $BS_DEFPUSHBUTTON) ;~ GUICtrlCreateLabel("The element limit also affects how much of other types of values are shown.", 16, 64, 360, 17) ;~ Local $radLimit = GUICtrlCreateRadio("Enter the new limit", 16, 96, 113, 17) ;~ Local $radAll = GUICtrlCreateRadio($displayManyElements, 16, 128, 233,, 17) ;~ GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### Local $bAll = $limit=$g_cDebug_LargeElementLimit If $bAll Then GUICtrlSetData($inp,'') GUICtrlSetState($inp,$GUI_DISABLE) GUICtrlSetState($radAll,$GUI_CHECKED) Else GUICtrlSetState($radLimit,$GUI_CHECKED) GUICtrlSetData($inp,$limit) EndIf ; Returns True for OK, False for Cancel Local $nMsg,$ret,$t,$n While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE,$btnCancel $ret = False ExitLoop Case $btnOK If $bAll Then $limit = $g_cDebug_LargeElementLimit ExitLoop Else $t = GUICtrlRead($inp) If StringRegExp($t,'^([0-9]{1,})$',0) Then $limit = Number($t) $ret = True ExitLoop Else MsgBox($MB_ICONWARNING+$MB_TASKMODAL,'cDebug warning','Enter a positive integer') GUICtrlSetData($inp,$g_cDebug_elementLimitDefault) EndIf EndIf Case $radLimit GUICtrlSetState($inp,BitOR($GUI_ENABLE,$GUI_FOCUS)) $bAll = False Case $radAll GUICtrlSetState($inp,$GUI_DISABLE) $bAll = True EndSwitch WEnd GUIDelete($frmChangeLimit) If $g_cDebug_elementLimit=0 Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,'$g_cDebug_elementLimit=0') ElseIf $g_cDebug_elementLimit='' Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber,"$g_cDebug_elementLimit=''") EndIf Return $ret EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name...........: __ArrayQuickSort1D ; Description ...: Helper function for sorting 1D arrays ; Syntax.........: __ArrayQuickSort1D ( ByRef $aArray, ByRef $iStart, ByRef $iEnd ) ; Parameters ....: $aArray - Array to sort ; $iStart - Index of array to start sorting at ; $iEnd - Index of array to stop sorting at ; $fCaseSense - type of comparison of elements ; |$STR_NOCASESENSE (0) = not case sensitive, using the user's locale (default) ; |$STR_CASESENSE (1) = case sensitive ; |$STR_NOCASESENSEBASIC (2) = not case sensitive, using a basic/faster ; Return values .: None ; Author ........: Jos van der Zande, LazyCoder, Tylo, Ultima ; Modified.......: c.haslam ; Remarks .......: For Internal Use Only ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _cDebug_ArrayQuickSort1D(ByRef $aArray, Const ByRef $iStart, Const ByRef $iEnd,$nCaseSense) If $iEnd <= $iStart Then Return Local $vTmp Local $bNbr = IsNumber($aArray[$iStart]) For $i = $iStart+1 To $iEnd If IsNumber($aArray[$i])<>$bNbr Then _cDebug_ReportCodingErrorAndExit(@ScriptLineNumber, _ 'Attempting to sort 1D arrray with mixed-type elements') EndIf Next ; The code below is the same as in Array.au3. except for adding $nCaseSens. ; Its bugs will have no effect due to checking code above. ; InsertionSort (faster for smaller segments) If ($iEnd - $iStart) < 15 Then Local $vCur For $i = $iStart + 1 To $iEnd $vTmp = $aArray[$i] If IsNumber($vTmp) Then For $j = $i - 1 To $iStart Step -1 $vCur = $aArray[$j] If ($vTmp >= $vCur And IsNumber($vCur)) Or _ (Not IsNumber($vCur) And StringCompare($vTmp, $vCur,$nCaseSense) >= 0) Then ExitLoop $aArray[$j + 1] = $vCur Next Else For $j = $i - 1 To $iStart Step -1 If (StringCompare($vTmp, $aArray[$j],$nCaseSense) >= 0) Then ExitLoop $aArray[$j + 1] = $aArray[$j] Next EndIf $aArray[$j + 1] = $vTmp Next Return EndIf ; QuickSort Local $L = $iStart, $R = $iEnd, $vPivot = $aArray[Int(($iStart + $iEnd) / 2)], $bNum = IsNumber($vPivot) Do If $bNum Then While ($aArray[$L] < $vPivot And IsNumber($aArray[$L])) Or _ (Not IsNumber($aArray[$L]) And StringCompare($aArray[$L], $vPivot,$nCaseSense) < 0) $L += 1 WEnd While ($aArray[$R] > $vPivot And IsNumber($aArray[$R])) Or _ (Not IsNumber($aArray[$R]) And StringCompare($aArray[$R], $vPivot,$nCaseSense) > 0) $R -= 1 WEnd Else While (StringCompare($aArray[$L], $vPivot,$nCaseSense) < 0) $L += 1 WEnd While (StringCompare($aArray[$R], $vPivot,$nCaseSense) > 0) $R -= 1 WEnd EndIf ; Swap If $L <= $R Then $vTmp = $aArray[$L] $aArray[$L] = $aArray[$R] $aArray[$R] = $vTmp $L += 1 $R -= 1 EndIf Until $L > $R _cDebug_ArrayQuickSort1D($aArray, $iStart, $R,$nCaseSense) _cDebug_ArrayQuickSort1D($aArray, $L, $iEnd,$nCaseSense) EndFunc ;==>__ArrayQuickSort1D ; #FUNCTION# ========================================================================================================= ; Name...........: _cDebug_StringSize ; Description ...: Returns size of rectangle required to display string - maximum permitted width can be chosen ; Syntax ........: _cDebug_StringSize($sText[, $iSize[, $iWeight[, $iAttrib[, $sName[, $iWidth[, $hWnd]]]]]]) ; Parameters ....: $sText - String to display ; $iSize - [optional] Font size in points - (default = 8.5) ; $iWeight - [optional] Font weight - (default = 400 = normal) ; $iAttrib - [optional] Font attribute (0-Normal (default), 2-Italic, 4-Underline, 8 Strike) ; + 1 if tabs are to be expanded before sizing ; $sName - [optional] Font name - (default = Tahoma) ; $iWidth - [optional] Max width for rectangle - (default = 0 => width of original string) ; $hWnd - [optional] GUI in which string will be displayed - (default 0 => normally not required) ; Requirement(s) : v3.2.12.1 or higher ; Return values .: Success - Returns 4-element array: ($iWidth set // $iWidth not set) ; |$array[0] = String reformatted with additonal @CRLF // Original string ; |$array[1] = Height of single line in selected font // idem ; |$array[2] = Width of rectangle required for reformatted // original string ; |$array[3] = Height of rectangle required for reformatted // original string ; Failure - Returns 0 and sets @error: ; |1 - Incorrect parameter type (@extended = parameter index) ; |2 - DLL call error - extended set as follows: ; |1 - GetDC failure ; |2 - SendMessage failure ; |3 - GetDeviceCaps failure ; |4 - CreateFont failure ; |5 - SelectObject failure ; |6 - GetTextExtentPoint32 failure ; |3 - Font too large for chosen max width - a word will not fit ; Author ........: Melba23 - thanks to trancexx for the default DC code ; Modified ......: ; Remarks .......: The use of the $hWnd parameter is not normally necessary - it is only required if the UDF does not ; return correct dimensions without it. ; Related .......: ; Link ..........: ; Example .......: Yes ;===================================================================================================================== Func _cDebug_StringSize($sText, $iSize = 8.5, $iWeight = 400, $iAttrib = 0, $sName = "", $iMaxWidth = 0, $hWnd = 0) ; Set parameters passed as Default If $iSize = Default Then $iSize = 8.5 If $iWeight = Default Then $iWeight = 400 If $iAttrib = Default Then $iAttrib = 0 If $sName = "" Or $sName = Default Then $sName = _cDebug_StringSize_DefaultFontName() ; Check parameters are correct type If Not IsString($sText) Then Return SetError(1, 1, 0) If Not IsNumber($iSize) Then Return SetError(1, 2, 0) If Not IsInt($iWeight) Then Return SetError(1, 3, 0) If Not IsInt($iAttrib) Then Return SetError(1, 4, 0) If Not IsString($sName) Then Return SetError(1, 5, 0) If Not IsNumber($iMaxWidth) Then Return SetError(1, 6, 0) If Not IsHwnd($hWnd) And $hWnd <> 0 Then Return SetError(1, 7, 0) Local $aRet, $hDC, $hFont, $hLabel = 0, $hLabel_Handle ; Check for tab expansion flag Local $iExpTab = BitAnd($iAttrib, 1) ; Remove possible tab expansion flag from font attribute value $iAttrib = BitAnd($iAttrib, BitNot(1)) ; If GUI handle was passed If IsHWnd($hWnd) Then ; Create label outside GUI borders $hLabel = GUICtrlCreateLabel("", -10, -10, 10, 10) $hLabel_Handle = GUICtrlGetHandle(-1) GUICtrlSetFont(-1, $iSize, $iWeight, $iAttrib, $sName) ; Create DC $aRet = DllCall("user32.dll", "handle", "GetDC", "hwnd", $hLabel_Handle) If @error Or $aRet[0] = 0 Then GUICtrlDelete($hLabel) Return SetError(2, 1, 0) EndIf $hDC = $aRet[0] $aRet = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hLabel_Handle, "int", 0x0031, "wparam", 0, "lparam", 0) ; $WM_GetFont If @error Or $aRet[0] = 0 Then GUICtrlDelete($hLabel) Return SetError(2, _cDebug_StringSize_Error_Close(2, $hDC), 0) EndIf $hFont = $aRet[0] Else ; Get default DC $aRet = DllCall("user32.dll", "handle", "GetDC", "hwnd", $hWnd) If @error Or $aRet[0] = 0 Then Return SetError(2, 1, 0) $hDC = $aRet[0] ; Create required font $aRet = DllCall("gdi32.dll", "int", "GetDeviceCaps", "handle", $hDC, "int", 90) ; $LOGPIXELSY If @error Or $aRet[0] = 0 Then Return SetError(2, _cDebug_StringSize_Error_Close(3, $hDC), 0) Local $iInfo = $aRet[0] $aRet = DllCall("gdi32.dll", "handle", "CreateFontW", "int", -$iInfo * $iSize / 72, "int", 0, "int", 0, "int", 0, _ "int", $iWeight, "dword", BitAND($iAttrib, 2), "dword", BitAND($iAttrib, 4), "dword", BitAND($iAttrib, 8), "dword", 0, "dword", 0, _ "dword", 0, "dword", 5, "dword", 0, "wstr", $sName) If @error Or $aRet[0] = 0 Then Return SetError(2, _cDebug_StringSize_Error_Close(4, $hDC), 0) $hFont = $aRet[0] EndIf ; Select font and store previous font $aRet = DllCall("gdi32.dll", "handle", "SelectObject", "handle", $hDC, "handle", $hFont) If @error Or $aRet[0] = 0 Then Return SetError(2, _cDebug_StringSize_Error_Close(5, $hDC, $hFont, $hLabel), 0) Local $hPrevFont = $aRet[0] ; Declare variables Local $avSize_Info[4], $iLine_Length, $iLine_Height = 0, $iLine_Count = 0, $iLine_Width = 0, $iWrap_Count, $iLast_Word, $sTest_Line ; Declare and fill Size structure Local $tSize = DllStructCreate("int X;int Y") DllStructSetData($tSize, "X", 0) DllStructSetData($tSize, "Y", 0) ; Ensure EoL is @CRLF and break text into lines $sText = StringRegExpReplace($sText, "((?<!\x0d)\x0a|\x0d(?!\x0a))", @CRLF) Local $asLines = StringSplit($sText, @CRLF, 1) ; For each line For $i = 1 To $asLines[0] ; Expand tabs if required If $iExpTab Then $asLines[$i] = StringReplace($asLines[$i], @TAB, " XXXXXXXX") EndIf ; Size line $iLine_Length = StringLen($asLines[$i]) DllCall("gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $asLines[$i], "int", $iLine_Length, "ptr", DllStructGetPtr($tSize)) If @error Then Return SetError(2, _cDebug_StringSize_Error_Close(6, $hDC, $hFont, $hLabel), 0) If DllStructGetData($tSize, "X") > $iLine_Width Then $iLine_Width = DllStructGetData($tSize, "X") If DllStructGetData($tSize, "Y") > $iLine_Height Then $iLine_Height = DllStructGetData($tSize, "Y") Next ; Check if $iMaxWidth has been both set and exceeded If $iMaxWidth <> 0 And $iLine_Width > $iMaxWidth Then ; Wrapping required ; For each Line For $j = 1 To $asLines[0] ; Size line unwrapped $iLine_Length = StringLen($asLines[$j]) DllCall("gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $asLines[$j], "int", $iLine_Length, "ptr", DllStructGetPtr($tSize)) If @error Then Return SetError(2, _cDebug_StringSize_Error_Close(6, $hDC, $hFont, $hLabel), 0) ; Check wrap status If DllStructGetData($tSize, "X") < $iMaxWidth - 4 Then ; No wrap needed so count line and store $iLine_Count += 1 $avSize_Info[0] &= $asLines[$j] & @CRLF Else ; Wrap needed so zero counter for wrapped lines $iWrap_Count = 0 ; Build line to max width While 1 ; Zero line width $iLine_Width = 0 ; Initialise pointer for end of word $iLast_Word = 0 ; Add characters until EOL or maximum width reached For $i = 1 To StringLen($asLines[$j]) ; Is this just past a word ending? If StringMid($asLines[$j], $i, 1) = " " Then $iLast_Word = $i - 1 ; Increase line by one character $sTest_Line = StringMid($asLines[$j], 1, $i) ; Get line length $iLine_Length = StringLen($sTest_Line) DllCall("gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sTest_Line, "int", $iLine_Length, "ptr", DllStructGetPtr($tSize)) If @error Then Return SetError(2, _cDebug_StringSize_Error_Close(6, $hDC, $hFont, $hLabel), 0) $iLine_Width = DllStructGetData($tSize, "X") ; If too long exit the loop If $iLine_Width >= $iMaxWidth - 4 Then ExitLoop Next ; End of the line of text? If $i > StringLen($asLines[$j]) Then ; Yes, so add final line to count $iWrap_Count += 1 ; Store line $avSize_Info[0] &= $sTest_Line & @CRLF ExitLoop Else ; No, but add line just completed to count $iWrap_Count += 1 ; Check at least 1 word completed or return error If $iLast_Word = 0 Then Return SetError(3, _cDebug_StringSize_Error_Close(0, $hDC, $hFont, $hLabel), 0) ; Store line up to end of last word $avSize_Info[0] &= StringLeft($sTest_Line, $iLast_Word) & @CRLF ; Strip string to point reached $asLines[$j] = StringTrimLeft($asLines[$j], $iLast_Word) ; Trim leading whitespace $asLines[$j] = StringStripWS($asLines[$j], 1) ; Repeat with remaining characters in line EndIf WEnd ; Add the number of wrapped lines to the count $iLine_Count += $iWrap_Count EndIf Next ; Reset any tab expansions If $iExpTab Then $avSize_Info[0] = StringRegExpReplace($avSize_Info[0], "\x20?XXXXXXXX", @TAB) EndIf ; Complete return array $avSize_Info[1] = $iLine_Height $avSize_Info[2] = $iMaxWidth ; Convert lines to pixels and add drop margin $avSize_Info[3] = ($iLine_Count * $iLine_Height) + 4 Else ; No wrapping required ; Create return array (add drop margin to height) Local $avSize_Info[4] = [$sText, $iLine_Height, $iLine_Width, ($asLines[0] * $iLine_Height) + 4] EndIf ; Clear up DllCall("gdi32.dll", "handle", "SelectObject", "handle", $hDC, "handle", $hPrevFont) DllCall("gdi32.dll", "bool", "DeleteObject", "handle", $hFont) DllCall("user32.dll", "int", "ReleaseDC", "hwnd", 0, "handle", $hDC) If $hLabel Then GUICtrlDelete($hLabel) Return $avSize_Info EndFunc ;==>_cDebug_StringSize ; #INTERNAL_USE_ONLY#============================================================================================================ ; Name...........: _cDebug_StringSize_Error_Close ; Description ...: Releases DC and deleted font object if required after error ; Syntax ........: _cDebug_StringSize_Error_Close ($iExtCode, $hDC, $hGUI) ; Parameters ....: $iExtCode - code to return ; $hDC, $hGUI - handles as set in _cDebug_StringSize function ; Return value ..: $iExtCode as passed ; Author ........: Melba23 ; Modified.......: ; Remarks .......: This function is used internally by _cDebug_StringSize ; =============================================================================================================================== Func _cDebug_StringSize_Error_Close($iExtCode, $hDC = 0, $hFont = 0, $hLabel = 0) If $hFont <> 0 Then DllCall("gdi32.dll", "bool", "DeleteObject", "handle", $hFont) If $hDC <> 0 Then DllCall("user32.dll", "int", "ReleaseDC", "hwnd", 0, "handle", $hDC) If $hLabel Then GUICtrlDelete($hLabel) Return $iExtCode EndFunc ;=>_cDebug_StringSize_Error_Close ; #INTERNAL_USE_ONLY#============================================================================================================ ; Name...........: _cDebug_StringSize_DefaultFontName ; Description ...: Determines Windows default font ; Syntax ........: _cDebug_StringSize_DefaultFontName() ; Parameters ....: None ; Return values .: Success - Returns name of system default font ; Failure - Returns "Tahoma" ; Author ........: Melba23, based on some original code by Larrydalooza ; Modified.......: ; Remarks .......: This function is used internally by _cDebug_StringSize ; =============================================================================================================================== Func _cDebug_StringSize_DefaultFontName() ; Get default system font data Local $tNONCLIENTMETRICS = DllStructCreate("uint;int;int;int;int;int;byte[60];int;int;byte[60];int;int;byte[60];byte[60];byte[60]") DLLStructSetData($tNONCLIENTMETRICS, 1, DllStructGetSize($tNONCLIENTMETRICS)) DLLCall("user32.dll", "int", "SystemParametersInfo", "int", 41, "int", DllStructGetSize($tNONCLIENTMETRICS), "ptr", DllStructGetPtr($tNONCLIENTMETRICS), "int", 0) Local $tLOGFONT = DllStructCreate("long;long;long;long;long;byte;byte;byte;byte;byte;byte;byte;byte;char[32]", DLLStructGetPtr($tNONCLIENTMETRICS, 13)) If IsString(DllStructGetData($tLOGFONT, 14)) Then Return DllStructGetData($tLOGFONT, 14) Else Return "Tahoma" EndIf EndFunc ;=>_cDebug_StringSize_DefaultFontName #cs maps Func _cDebug_MapKeys($map,$lineNbr) Local $mapKeys = MapKeys($map) If @error Then If IsMap($map) Then Local $mapKeys[0] Else _cDebug_ReportCodingErrorAndExit('Argument to _cDebug_cMapKeys() is a '&VarGetType($map),$lineNbr) EndIf EndIf Return $mapKeys EndFunc #ce maps Func _cDebug_IsMap($var) #cs maps Return IsMap($var) #ce maps ;#cs nomaps Return False ;#ce nomaps EndFunc ; Thanks to jchd Func _cDebug_Example() Local $ans = MsgBox($MB_ICONINFORMATION+$MB_OKCANCEL,'cDebug Example', _ 'Using the same data, this example reports twice: ' _ &'with a struct tag specified in the call to _GuiDebug(), and again with the tag being detected') If $ans=$IDCANCEL Then Exit EndIf Local $tag = "char a[3];handle b[3];uint c[35];byte d[128];wchar e[190000]; double f[3];int64 g[3]; char h[3];"& _ "byte i;struct;float j;double k;endstruct;byte l;ubyte m;short n;ushort o;int p;uint q;char r;boolean s" Local $struct = DllStructCreate($tag) DllStructSetData($struct, 'a', 'sos') DllStructSetData($struct, 'b', Ptr(123456789)) DllStructSetData($struct, 'c', 8, 1) DllStructSetData($struct, 'c', 0x87654321, 2) DllStructSetData($struct, 'c', 256, 5) DllStructSetData($struct, 'd', Binary('sos')) DllStructSetData($struct, 'e', 'gno' & @CRLF & 'ji' & @TAB & 'o') DllStructSetData($struct, 'f', 3.1415926, 2) DllStructSetData($struct, 'g', 17, 1) DllStructSetData($struct, 'g', -1, 2) DllStructSetData($struct, 'h', 'end') DllStructSetData($struct, 'i', 0x43) DllStructSetData($struct, 'j', 2.7182818284590452353602874713527) DllStructSetData($struct, 'k', 4*ATan(1)) DllStructSetData($struct, 'l', 107) DllStructSetData($struct, 'm', -4) ; signed bye does not exist. A ubuye is a byte! DllStructSetData($struct, 'n', 109) DllStructSetData($struct, 'o', 110) DllStructSetData($struct, 'p', 111) DllStructSetData($struct, 'q', 112) DllStructSetData($struct, 'r', '^') DllStructSetData($struct, 's', True) Local $c[2][0] Local $e[2][2] = [[Null, Default], [_cDebug_DumpStr, MsgBox]] Local Enum $p = 33333333333333 Opt("WinTitleMatchMode", 2) Local $a[4][4] = [ _ [$c, $e, ObjCreate("shell.application"), WinGetHandle("Dump.au3")], _ ['zzz', 1/3, True, 0x123456], _ [$struct, 93, Null, $p], _ [] _ ] Local $ar = [['a1',11,-11.0,3.14],['a2',12,1.2e12,25],['b1',-22,22.22 ,99],['c1',23,0.23],['d1',-2,-3,-4]] Local $i = 1, $J = 3 Local $vec = [100,200,300,400,$ar] Local $welcome = 'cDebug works, so Enjoy!@@' #cs maps Local $cats[],$cat1[],$cat2[] $cat1.name = 'jack' $cat1.colour = 'black' $cat1.chases = 'squirrels' $cat1[50] = 5 $cat1[7] = 20 $cats.cat1 = $cat1 $cat2.name = 'suki' $cat2.colour = 'grey' $cat2.chases = 'birds' $cat2.age = 4 $cats.cat2 = $cat2 $cats.cat2.friendly = False $cats.cat1.friendly = True $cats.array = $vec Local $names1 = '$ar[1][..],$ar[1..][2..],$ar[..1][1..2],$ar[..1][..$i],$i,$ar[1][0,2..$j],'& _ '$vec[1,3],$vec[..0,2],a constant,$j,StringTrimRight($welcome,2),' Local $names2 = 'cat map,cat2[regexp:^c],'& _ '$vec[4]->$ar[$i][1..],$i,$cat2["c".."d"],$cats->["colour","name"]' _GuiDebug('Test example of moderate complexity (with structure tag specified)',$names1&'$a{'&$tag&'},'&$names2, _ $ar,$ar,$ar,$ar,$i,$ar,$vec,$vec,$g_cDebug_elementLimit,$j,StringTrimRight($welcome,2),$a,$cats,$cat2, _ $vec,$i,$cat2,$cats) _GuiDebug('Test example of moderate complexity (without tag specified)',$names1&'$a,'&$names2, _ $ar,$ar,$ar,$ar,$i,$ar,$vec,$vec,$g_cDebug_elementLimit,$j,StringTrimRight($welcome,2),$a,$cats,$cat2, _ $vec,$i,$cat2,$cats) #ce maps ;#cs nomaps Local $names1 = '$ar[1][..],$ar[1..][2..],$ar[..1][1..2],$ar[..1][..$i],$i,$ar[1][0,2..$j],'& _ '$vec[1,3],$vec[..0,2],a constant,$j,StringTrimRight($welcome,2),' Local $names2 = _ '$vec[4]->$ar[$i][1..],$i' _GuiDebug('Test example of moderate complexity (with structure tag specified)',$names1&'$a{'&$tag&'},'&$names2, _ $ar,$ar,$ar,$ar,$i,$ar,$vec,$vec,$g_cDebug_elementLimit,$j,StringTrimRight($welcome,2),$a, _ $vec,$i) _GuiDebug('Test example of moderate complexity (without tag specified)',$names1&'$a,'&$names2, _ $ar,$ar,$ar,$ar,$i,$ar,$vec,$vec,$g_cDebug_elementLimit,$j,StringTrimRight($welcome,2),$a, _ $vec,$i) ;#ce nomaps EndFunc ;~ _cDebug_Example()