c.haslam Posted January 28, 2018 Share Posted January 28, 2018 (edited) jchd posted VarTypeDump(). It has something like: $data = DllStructGetData($vVar, $nbElem) . . $type = VarGetType($data) Switch $type . . Case "Ptr" . . $elem = "ptr" ; alias: hwnd, handle I have found that a hwnd or handle can be detected by: $elem = IsHwnd($data) ? 'handle' : 'ptr' jchd did not differentiate between Hwnd and Ptr. Is that because differentiating may fail? Are Hwnd and Handle the same for both 32-bit and 64-bit AutoIt? The Help for DllStructCreate(0 lists both, with identical descriptions. In 32-bit AutoIt, the length of both is 4. Edited January 28, 2018 by c.haslam Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard Link to comment Share on other sites More sharing options...
jchd Posted January 28, 2018 Share Posted January 28, 2018 You're seing an old version. Probably my fault as it's quite possible that I never updated the various places where I posted the code. Again it was only for example, not really intended as a clean and stable UDF for public consumption. Here's what I currently have. expandcollapse popup#AutoIt3Wrapper_UseUpx=n #AutoIt3Wrapper_Compile_Both=n ;~ #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_Run_AU3Check=n #AutoIt3Wrapper_Version=B ; beta 3.3.15.0 or greater is mandatory #include-once #include <AutoItConstants.au3> #include <String.au3> #include <Math.au3> Global Const $_TAB = ' ' Global $_DumpStr, $_DumpBin ; user-callable function, so that noone messes with __VarDump indentation ; $vVar is the variable to be dumped ; $iLimit is the max number of entries of an array dimension, map or DllStruct array element to be displayed in full Func _VarDump(ByRef $vVar, $iLimit = 20, $bFullStr = 0, $bFullBin = 0) If $iLimit < 3 Then $iLimit = 0 $_DumpStr = ($bFullStr ? __DumpFullStr : __DumpStr) $_DumpBin = ($bFullBin ? __DumpFullBin : __DumpBin) Return (__VarDump($vVar, $iLimit)) EndFunc ;==>_VarDump Func __VarDump(ByRef $vVar, $iLimit, $sIndent = '', $sMore = '') Local $ret, $len, $ptr, $tmp Switch VarGetType($vVar) Case "String" $len = StringLen($vVar) Return 'String (' & $len & ") " & $_DumpStr($vVar) Case "Double" Return 'Double ' & $vVar & (IsInt($vVar) ? '.0' : '') Case "Int32", "Int64" Return VarGetType($vVar) & ' ' & $vVar Case "Array" Local $iDimensions = UBound($vVar, 0) Local $iCells = 1 $ret = 'Array' $iDimensions -= 1 For $i = 0 To $iDimensions $ret &= '[' & UBound($vVar, $i + 1) & ']' $iCells *= UBound($vVar, $i + 1) Next $sMore = _StringRepeat(' ', StringLen($ret) - 1) If $iCells = 0 Then Return $ret & $_TAB & ' (array is empty)' Else Return $ret & @CRLF & __VarDumpArray($vVar, $iLimit, $sIndent, $sMore) EndIf Case "Binary" $len = BinaryLen($vVar) $ret = 'Binary (' & BinaryLen($vVar) & ') ' Return ($ret & $_DumpBin($vVar)) Case "Bool" Return 'Boolean ' & $vVar Case "Keyword" Return ('Keyword ' & ($vVar = Null ? 'Null' : ($vVar = Default ? 'Default' : 'Other keyword'))) Case "Ptr" Return (IsHWnd($vVar) ? 'HWnd ' : 'Pointer ' & $vVar) Case "Object" $tmp = 'Object' & @LF & $sMore & $sIndent & ' Name: ' & ObjName($vVar, $OBJ_NAME) $ret = ObjName($vVar, $OBJ_STRING) If Not @error Then $tmp &= @LF & $sMore & $sIndent & ' Description: ' & $ret $ret = ObjName($vVar, $OBJ_PROGID) If Not @error Then $tmp &= @LF & $sMore & $sIndent & ' ProgID: ' & $ret $ret = ObjName($vVar, $OBJ_FILE) If Not @error Then $tmp &= @LF & $sMore & $sIndent & ' Associated file: ' & $ret $ret = ObjName($vVar, $OBJ_MODULE) If Not @error Then $tmp &= @LF & $sMore & $sIndent & ' Owner/marshaller: ' & $ret $ret = ObjName($vVar, $OBJ_CLSID) If Not @error Then $tmp &= @LF & $sMore & $sIndent & ' CLSID: ' & $ret $ret = ObjName($vVar, $OBJ_IID) If Not @error Then $tmp &= @LF & $sMore & $sIndent & ' InterfaceID: ' & $ret Return $tmp Case "Function", "UserFunction" Return StringFormat('%-13s', VarGetType($vVar)) & FuncName($vVar) Case "DllStruct" $len = DllStructGetSize($vVar) $ptr = DllStructGetPtr($vVar) $ret = 'Struct (' & $len & ') @:' & Hex($ptr) & ' (structure alignment is unknown)' & @CRLF Local $nbElem = 1, $idx, $incr, $data, $type, $indent = $sIndent & $_TAB, $oldvalue, $readvalue, $elem While 1 $data = DllStructGetData($vVar, $nbElem) If @error = 2 Then ExitLoop $type = VarGetType($data) $idx = 1 $incr = 0 ; determine max index of element While 1 DllStructGetData($vVar, $nbElem, 2 * $idx) If @error = 3 Then ExitLoop $incr = $idx $idx *= 2 WEnd ; index is in [$idx, (2 * $idx) - 1] $idx += $incr Do DllStructGetData($vVar, $nbElem, $idx) If @error = 3 Then ; 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 Switch $type Case "Int32", "Int64" $ret &= $indent $data = DllStructGetData($vVar, $nbElem, 1) DllStructSetData($vVar, $nbElem, 0x7777666655554433, 1) $readvalue = DllStructGetData($vVar, $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($vVar, $nbElem, 0x88887777, 1) $readvalue = DllStructGetData($vVar, $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($vVar, $nbElem, 0x8888, 1) $readvalue = DllStructGetData($vVar, $nbElem, 1) $elem = ($readvalue > 0 ? "ushort" : "short") ; ushort alias: word Case 0x33 $elem = "byte" ; alias: ubyte EndSwitch DllStructSetData($vVar, $nbElem, $data, 1) If $idx = 1 Then $ret &= StringFormat('%-' & 9 + StringLen($len) & 's ', $elem) & $data & @CRLF Else $ret &= $elem & "[" & $idx & "]" & @CRLF For $i = 1 To $idx If $iLimit And $idx > $iLimit And $i > $iLimit Then $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's ', '') & '... there are ' & $idx - $iLimit & ' more ' & $elem & ' in this array' & @CRLF ExitLoop Else $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's ', '') & DllStructGetData($vVar, $nbElem, $i) & @CRLF EndIf Next EndIf Case "String" $oldvalue = DllStructGetData($vVar, $nbElem, 1) DllStructSetData($vVar, $nbElem, ChrW(0x2573), 1) $readvalue = DllStructGetData($vVar, $nbElem, 1) DllStructSetData($vVar, $nbElem, $oldvalue, 1) $elem = ($readvalue = ChrW(0x2573) ? "wchar" : "char") If $idx > 1 Then $elem &= "[" & $idx & "]" $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's ', $elem) & $_DumpStr($data) & @CRLF Case "Binary" Local $blen = BinaryLen($data) $elem = "byte" If $idx > 1 Then $elem &= "[" & $idx & "]" $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's ', $elem) & $_DumpBin($data) & @CRLF Case "Ptr" $ret &= $indent $elem = "ptr" ; alias: hwnd, handle If $idx = 1 Then $ret &= StringFormat('%-' & 9 + StringLen($len) & 's ', $elem) & $data & @CRLF Else $ret &= $elem & "[" & $idx & "]" & @CRLF For $i = 1 To $idx $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's ', '') & DllStructGetData($vVar, $nbElem, $i) & @CRLF Next EndIf Case "Double" $ret &= $indent $oldvalue = DllStructGetData($vVar, $nbElem, 1) DllStructSetData($vVar, $nbElem, 10 ^ - 15, 1) $readvalue = DllStructGetData($vVar, $nbElem, 1) DllStructSetData($vVar, $nbElem, $oldvalue, 1) $elem = ($readvalue = 10 ^ - 15 ? "double" : "float") If $idx = 1 Then $ret &= StringFormat('%-' & 9 + StringLen($len) & 's ', $elem) & $data & (IsInt($data) ? '.0' : '') & @CRLF Else $ret &= $elem & "[" & $idx & "]" & @CRLF For $i = 1 To $idx If $iLimit And $idx > $iLimit And $i > $iLimit Then $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's ', '') & '... there are ' & $idx - $iLimit & ' more ' & $elem & ' in this array' & @CRLF ExitLoop Else $ret &= $indent & StringFormat('%-' & 9 + StringLen($len) & 's %s', '', DllStructGetData($vVar, $nbElem, $i)) & (IsInt(DllStructGetData($vVar, $nbElem, $i)) ? '.0' : '') & @CRLF EndIf Next EndIf EndSwitch $nbElem += 1 WEnd Return StringTrimRight($ret, 2) Case "Map" Local $iCells = UBound($vVar) $ret = 'Map[' & $iCells & ']' If $iCells = 0 Then Return $ret & $_TAB & ' (map is empty)' Else Return $ret & @CRLF & __VarDumpMap($vVar, $iLimit, $sIndent, ' ') EndIf Case Else Return StringFormat('%-13s', VarGetType($vVar)) & $vVar EndSwitch EndFunc ;==>__VarDump Func __VarDumpArray(ByRef $aArray, $iLimit, $sIndent = $_TAB, $sMore = '') Local $sDump, $sArrayFetch, $sArrayRead, $iDone = 0, $iElements = 1 Local $iDimensions = UBound($aArray, 0) Local $aUBounds[$iDimensions] Local $aIndices[$iDimensions] $iDimensions -= 1 For $i = 0 To $iDimensions $aUBounds[$i] = UBound($aArray, $i + 1) - 1 $iElements *= $aUBounds[$i] + 1 $aIndices[$i] = 0 Next $sIndent &= $_TAB While $iDone < ($iLimit ? _Min($iLimit, $iElements) : $iElements) $sArrayFetch = '' For $i = 0 To $iDimensions $sArrayFetch &= '[' & $aIndices[$i] & ']' Next $sArrayRead = Execute('$aArray' & $sArrayFetch) $sDump &= $sIndent & $sArrayFetch & ' => ' & __VarDump($sArrayRead, $iLimit, $sIndent, $sMore) & @CRLF $iDone += 1 If $iLimit And $iDone = $iLimit Then $sDump &= $sIndent & '... there are ' & $iElements - $iDone & ' more elements in this array' & @CRLF ExitLoop EndIf For $i = $iDimensions To 0 Step -1 $aIndices[$i] += 1 If $aIndices[$i] > $aUBounds[$i] Then $aIndices[$i] = 0 Else ExitLoop EndIf Next WEnd Return (StringTrimRight($sDump, 2)) EndFunc ;==>__VarDumpArray Func __VarDumpMap(ByRef $mMap, $iLimit, $sIndent = $_TAB, $sMore = '') Local $i = 0, $sDump $sIndent &= $_TAB For $key In MapKeys($mMap) $sDump &= $sIndent & StringFormat('%-16s => ', _ "[" & (IsString($key) ? __DumpStr($key) : $key) & "]") $sDump &= __VarDump($mMap[$key], $iLimit, $sIndent, $sMore) & @CRLF If $iLimit And $i = $iLimit - 1 Then $sDump &= $sIndent & '... there are ' & UBound($mMap) - $i - 1 & ' more elements in this map' & @CRLF ExitLoop EndIf $i += 1 Next Return (StringTrimRight($sDump, 2)) EndFunc ;==>__VarDumpMap Func __DumpStr($vVar) Local $len = StringLen($vVar) $vVar = Execute("'" & StringRegExpReplace(StringReplace($vVar, "'", "''"), "([\p{Cc}])", "<0x' & Hex(AscW('$1'), 2) & '>") & "'") Return "'" & (($len <= 64) ? $vVar : StringMid($vVar, 1, 32) & ' ... ' & StringTrimLeft(StringMid($vVar, $len - 31, 32), 2)) & "'" EndFunc ;==>__DumpStr Func __DumpBin(ByRef $vVar) Local $len = BinaryLen($vVar) Return (($len <= 32) ? $vVar : BinaryMid($vVar, 1, 16) & ' ... ' & StringTrimLeft(BinaryMid($vVar, $len - 15, 16), 2)) EndFunc ;==>__DumpBin Func __DumpFullStr(ByRef $vVar) $vVar = Execute("'" & StringRegExpReplace(StringReplace($vVar, "'", "''"), "([\p{Cc}])", "<0x' & Hex(AscW('$1'), 2) & '>") & "'") Return "'" & $vVar & "'" EndFunc ;==>__DumpFullStr Func __DumpFullBin(ByRef $vVar) Return $vVar EndFunc ;==>__DumpFullBin Func _VarCmp(ByRef $vVar1, ByRef $vVar2, $iMethod = 1) If $iMethod = Default Then $iMethod = 1 Local $dim = UBound($vVar1, $UBOUND_DIMENSIONS) If $dim <> UBound($vVar2, $UBOUND_DIMENSIONS) Then Return SetError(1, 0, '') Local $err = 0 If $dim = 0 Then If BitAND($iMethod, 1) And $vVar1 <> $vVar2 Then $err = 4 If BitAND($iMethod, 2) And Not ($vVar1 == $vVar2) Then $err += 8 If BitAND($iMethod, 4) And VarGetType($vVar1) <> VarGetType($vVar2) Then $err += 16 If BitAND($iMethod, 8) And _VarDump($vVar1) <> _VarDump($vVar2) Then $err += 32 If $err Then Return SetError($err, 0, '') EndIf Local $iElems = 1 For $i = 1 To $dim If UBound($vVar1, $i) <> UBound($vVar2, $i) Then Return SetError(2, 0, $i) $iElems *= UBound($vVar1, $i) Next Local $idx, $n, $v1, $v2 For $i = 0 To $iElems - 1 $idx = '' $n = $i For $j = 1 To $dim $n = Mod($n, UBound($vVar1, $j)) $idx = '[' & $n & ']' & $idx $n = Int($i / UBound($vVar1, $j)) Next $v1 = Execute('$vVar1' & $idx) $v2 = Execute('$vVar2' & $idx) If BitAND($iMethod, 1) And $v1 <> $v2 Then $err = 4 If BitAND($iMethod, 2) And Not ($v1 == $v2) Then $err += 8 If BitAND($iMethod, 4) And VarGetType($v1) <> VarGetType($v2) Then $err += 16 If BitAND($iMethod, 8) And _VarDump($v1) <> _VarDump($v2) Then $err += 32 If $err Then Return SetError($err, 0, $idx) Next Return SetError(0, 0, '') EndFunc ;==>_VarCmp ; Unicode-aware ConsoleWrite Func _ConsoleWrite($s) ConsoleWrite(BinaryToString(StringToBinary($s, 4), 1)) EndFunc ;==>_ConsoleWrite #cs ; Example use Local $tTest = DllStructCreate("byte;byte[3];char;char[3];wchar;wchar[3];short;short[3];ushort;ushort[3];int;int[3];uint;uint[3];int64;int64[3];uint64;uint64[3];float;float[3];double;double[3];handle;handle[3];boolean;bool;hwnd;handle;int_ptr;long_ptr;lresult;lparam;uint_ptr;ulong_ptr;dword_ptr;wparam") DllStructSetData($tTest, 2, '€') DllStructSetData($tTest, 6, '€') _ConsoleWrite('Test structure types' & @LF & _VarDump($tTest) & @LF & @LF) Local $struct = DllStructCreate("char[3];handle[3];uint[35];byte[128];wchar[190000]; double[3];int64[3];char[3];float;double;byte;byte;short;ushort;int;uint;char") DllStructSetData($struct, 1, 'sos') DllStructSetData($struct, 2, Ptr(123456789)) DllStructSetData($struct, 3, 8, 1) DllStructSetData($struct, 3, 0x87654321, 2) DllStructSetData($struct, 3, 256, 5) DllStructSetData($struct, 4, Binary('sos')) DllStructSetData($struct, 5, 'gno' & @CRLF & 'j''i' & @TAB & 'o') DllStructSetData($struct, 6, 3.1415926, 2) DllStructSetData($struct, 7, 17, 1) DllStructSetData($struct, 7, -1, 2) DllStructSetData($struct, 8, 'end') DllStructSetData($struct, 9, 2.7182818284590452353602874713527) DllStructSetData($struct, 10, 2.7182818284590452353602874713527) DllStructSetData($struct, 11, 107) DllStructSetData($struct, 12, -108) DllStructSetData($struct, 13, 109) DllStructSetData($struct, 14, 110) DllStructSetData($struct, 15, 111) DllStructSetData($struct, 16, 112) Local $f = _VarDump Local $c[2][0] Local $e = [[Null, Default], [__DumpStr, MsgBox]] Local Enum $p = 33333333333333 Opt("WinTitleMatchMode", 2) Local $a[3][4] = [ _ [$c, $e, ObjCreate("shell.application"), WinGetHandle("Dump.au3")], _ ['zzz', 1/3, True, 0x123456], _ [$struct, 93, Null, $p] _ ] _ConsoleWrite('Test example of moderate complexity' & @LF & $f($a) & @LF) ;~ ; _VarCmp() test Local $a = [['', 0x123456], [1, "A", -2.0]], $b = [[0, Ptr(0x123456)], ["1", "a", -2]] Local $ret = _VarCmp($a, $b) ConsoleWrite("Method 1 : " & @error & ', ' & @extended & ', ' & $ret & @LF) $ret = _VarCmp($a, $b, 2) ConsoleWrite("Method 2 : " & @error & ', ' & @extended & ', ' & $ret & @LF) $ret = _VarCmp($a, $b, 4) ConsoleWrite("Method 4 : " & @error & ', ' & @extended & ', ' & $ret & @LF) $ret = _VarCmp($a, $b, 8) ConsoleWrite("Method 8 : " & @error & ', ' & @extended & ', ' & $ret & @LF) $ret = _VarCmp($a, $b, 15) ConsoleWrite("Method 15 : " & @error & ', ' & @extended & ', ' & $ret & @LF) Local $m[], $n[] $m[25] = ObjCreate("shell.application") $n["grhjiop jpgr 25"] = ObjCreate("shell.application") $m["tghjnio"] = $n ConsoleWrite(_VarDump($m) & @LF) #ce This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe hereRegExp tutorial: enough to get startedPCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta. SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt) Link to comment Share on other sites More sharing options...
c.haslam Posted January 28, 2018 Author Share Posted January 28, 2018 jchd, Most interesting! Thank you It appears to me that you do not distinguish among types of pointer. I would think that a hwnd is a handle of a window while handle is a non-window handle. And then there are non-hwnd, non-handle pointers. AutoIt cannot distinguish between hwnd and handle. Am I correct? I also see that Map is back. I do not see it in the 3.3.15.0 History/Changelog. Anyway, welcome back, Map! Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard Link to comment Share on other sites More sharing options...
jchd Posted January 29, 2018 Share Posted January 29, 2018 11 hours ago, c.haslam said: AutoIt cannot distinguish between hwnd and handle. Am I correct? Yes IFAICT. All else is a 32- or 64-bit pointer, also AFAIK. The term handle is widely used, as in "file handle". In fact I regard them as either an opaque reference (loose term) to an object (loose term) or a simple index in a table of known existing "things". Similarly, the term "pointer" is also vague, as in "file pointer". It's OS business not mine. OTOH a memory pointer is a direct link to something in memory, hence much more fragile in the sense that basing a DllStruct on a random pointer then reading/writing there is most likely going to cause a program crash. Operating a window/control/file function on a random handle is harmless, just issues an non-fatal error. A variable dump is mainly meant to display its actual content, interpretation of this content being left to the developper. Decorating this content with some user-friendly display is a comfortable luxury, compared to getting a Mb of monolithic hex core dump (like those I was taking hours to dissect in the early mainframe era). Regard _VarDump as a halfway between viewing a full PDF in some hex editor and viewing it thru a PDF display program. This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe hereRegExp tutorial: enough to get startedPCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta. SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt) Link to comment Share on other sites More sharing options...
c.haslam Posted January 29, 2018 Author Share Posted January 29, 2018 6 hours ago, jchd said: Regard _VarDump as a halfway between viewing a full PDF in some hex editor and viewing it thru a PDF display program. Understood. My objective is somewhat different from yours. When this all started, I already had my cDebug dumping array and nested arrays working AOK, to the Console. I then had trouble with DLL calls in GDI Plus. So I started to add structures to cDebug, helped greatly by your VarDump(). I am now working on comparison of user-specified tag and detected tag. I remember dissecting hex core dumps a mainframe. I started programming for the IBM 650 mainframe, with 4K 36-bit words of drum memory. Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now