Jump to content

DllStructPrint example


Luigi
 Share

Recommended Posts

A simple function to print a DllStruct on AutoIt.

 

#include <StringConstants.au3>
#include <Array.au3>

Func DllStructPrint($str, $tag)
    Local $ret = ""
    If IsDllStruct($str) Then
        $tag = StringLower($tag)
        Local $arr1, $arr2
        $arr1 = StringSplit($tag, ";", $STR_NOCOUNT)
        Local $aLabel[1]
        For $ii = 0 To UBound($arr1, 1) - 1
            If Not ($arr1[$ii] = "struct") And Not ($arr1[$ii] = "endstruct") Then
                $arr2 = StringSplit($arr1[$ii], " ", $STR_NOCOUNT)
                If IsArray($arr2) Then _ArrayAdd($aLabel, $arr2[1])
            EndIf
        Next
        For $ii = 1 To UBound($aLabel, 1) - 1
            $ret &= $aLabel[$ii] & "=" & DllStructGetData($str, $aLabel[$ii])
        Next
    ElseIf IsArray($str) Then
        $ret &= "[" & @LF
        Local $iSize = UBound($str, 1) - 1
        For $ii = 0 To $iSize
            $ret &= "  " & DllStructPrint($str[$ii], $tag) & ($ii = $iSize ? "" : ",") & @LF
        Next
        $ret &= "]" & @LF
    EndIf
    Return $ret
EndFunc   ;==>DllStructPrint

Local $tag = "Struct;byte key;EndStruct"

Local $str1 = DllStructCreate($tag)
$str1.key = Random(100, 999)
Local $str2 = DllStructCreate($tag)
$str2.key = Random(100, 999)
Local $str3 = DllStructCreate($tag)
$str3.key = Random(100, 999)

Local $arr[2]
$arr[0] = $str2
$arr[1] = $str3

Local $var1 = DllStructPrint($str1, $tag)
ConsoleWrite($var1 & @LF)

Local $var2 = DllStructPrint($arr, $tag)
ConsoleWrite($var2 & @LF)

 

OUTPUT:

key=189
[
  key=155,
  key=62
]

 

Edited by Luigi

Visit my repository

Link to comment
Share on other sites

  • 2 weeks later...

Hi Luigi,

This is a good idea. I recently had the same need here for a debugging function and ended up just modifying _WinAPI_DisplayStruct to get around all the leg work that's needed for a function like this. There are a lot of different situations to think about. I actually spent more time perfecting/making a decision on the table formatting. I still go back and forth on which one I like better. Anyway here's example from help file and what the output would look like. Cheers

Local $sStruct = 'dword Length;short State;uint Flags;handle hBitmap;hwnd hDC;long Rect[4];byte[14];int Reserved[10];wchar Text[80]'
Local $tStruct = DllStructCreate($sStruct)

DllStructSetData($tStruct, 1, 80)
DllStructSetData($tStruct, 2, 6)
DllStructSetData($tStruct, 3, 1)
DllStructSetData($tStruct, 4, 0x00010014)
DllStructSetData($tStruct, 5, 0x01010057)
DllStructSetData($tStruct, 6, 20, 1)
DllStructSetData($tStruct, 6, 20, 2)
DllStructSetData($tStruct, 6, 60, 3)
DllStructSetData($tStruct, 6, 80, 4)
DllStructSetData($tStruct, 7, Binary('0x656A6D633835206C6A6764206200'))
DllStructSetData($tStruct, 8, 0)
DllStructSetData($tStruct, 9, 'Simple Text')

Local $aStruct = _Winapi_PrintStruct($tStruct, $sStruct)

Output:

________________________________________________________________________________________________
| #   | Member      | Offset       | Type          | Size     | Value                            | 
|¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
| -   | -           | 0x011B9620   | <struct>      | 0        | -                                | 
| 1   | Length      | 0            | DWORD         | 4        | 80                               | 
| 2   | State       | 4            | short         | 2        | 6                                | 
| -   | -           | -            | <alignment>   | 2        | -                                | 
| 3   | Flags       | 8            | UINT          | 4        | 1                                | 
| 4   | hBitmap     | 12           | HANDLE        | 4        | 0x00010014                       | 
| 5   | hDC         | 16           | HWND          | 4        | 0x01010057                       | 
| 6   | Rect        | 20           | long[4]       | 16 (4)   | [1] 20                           | 
| -   | -           | 24           | -             | -        | [2] 20                           | 
| -   | -           | 28           | -             | -        | [3] 60                           | 
| -   | -           | 32           | -             | -        | [4] 80                           | 
| 7   | <unnamed>   | 36           | BYTE[14]      | 14       | 0x656A6D633835206C6A6764206200   | 
| -   | -           | -            | <alignment>   | 2        | -                                | 
| 8   | Reserved    | 52           | int[10]       | 40       | -                                | 
| 9   | Text        | 92           | WCHAR[80]     | 160      | Simple Text                      | 
| -   | -           | 0x011B971C   | <endstruct>   | 252      | -                                | 
 ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

 

 

_Winapi_PrintStruct.au3

Link to comment
Share on other sites

That only works when you have the struct definition text at hand.

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 here
RegExp tutorial: enough to get started
PCRE 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

Yup.. Yashied did put in a request a one point asking for function that would return the string used to define the structure if it was created with autoit but never happened. I recall Ward did some work somewhere too for discovering the types

Link to comment
Share on other sites

Search for a recent post of mine based on the word _vardump.  Found it:

 

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 here
RegExp tutorial: enough to get started
PCRE 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

Link to comment
Share on other sites

You'll have to remove the map-supporting part of the code if you don't want to rely on the beta.

I plan to support scripting dictionary objects as well some day.  Not that it's hard to do given the existing code base.

Also not very hard to derive code to output some struct definition in AutoIt test format.  Only very weird pointless alignment directives might get undetected but that's very unusual.

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 here
RegExp tutorial: enough to get started
PCRE 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

  • 2 weeks later...

This was fun. I really liked these set and check statements you have for getting the element types and also poking the indexes to confirm the element array count. With knowing type size and array count we can actually confirm the alignment as we walk through by using the ptr values of the the next element. The next ptr also tells us if we are finished or not.

This below should produce same basic output as _winapi_displaystruct (minus options) without needing the definition:

#include <array.au3>
#include <WinAPIDiag.au3>

Local $sStruct = 'dword Length;short State;uint Flags;handle hBitmap;hwnd hDC;long Rect[4];byte[9];int Reserved[10];wchar Text[80];double d;float f'
Local $tStruct = DllStructCreate($sStruct)

DllStructSetData($tStruct, 1, 80)
DllStructSetData($tStruct, 2, 6)
DllStructSetData($tStruct, 3, 1)
DllStructSetData($tStruct, 4, 0x00010014)
DllStructSetData($tStruct, 5, 0x01010057)
DllStructSetData($tStruct, 6, 10, 1)
DllStructSetData($tStruct, 6, 20, 2)
DllStructSetData($tStruct, 6, 30, 3)
DllStructSetData($tStruct, 7, Binary('0xABCDEF0123456789'))
DllStructSetData($tStruct, 8, 0)
DllStructSetData($tStruct, 9, 'Simple Text')
DllStructSetData($tStruct, 10, 12567823854.1256782385411)
DllStructSetData($tStruct, 11, 11256.12567823854111)

_dlldisplay($tStruct)
_WinAPI_DisplayStruct($tStruct, $sStruct)


Func _dlldisplay($tStruct)

    Local $pNextPtr, $pCurrentPtr = DllStructGetPtr($tStruct, 1)
    Local $iOffset = 0, $iDllSize = DllStructGetSize($tStruct)
    Local $vElVal, $sType, $iTypeSize, $iElSize, $iArrCount, $iAlign

    Local $aStruct[1][5] = [['-', $pCurrentPtr, '<struct>', 0, '-']] ; #|Offset|Type|Size|Value'

    ; loop through elements
    For $iE = 1 To 2 ^ 63

        ; backup first index value, establish type and typesize of element, restore first index value
        $vElVal = DllStructGetData($tStruct, $iE, 1)
        Switch VarGetType($vElVal)
            Case "Int32", "Int64"
                DllStructSetData($tStruct, $iE, 0x7777666655554433, 1)
                Switch DllStructGetData($tStruct, $iE, 1)
                    Case 0x7777666655554433
                        $sType = "int64"
                        $iTypeSize = 8
                    Case 0x55554433
                        DllStructSetData($tStruct, $iE, 0x88887777, 1)
                        $sType = (DllStructGetData($tStruct, $iE, 1) > 0 ? "uint" : "int")
                        $iTypeSize = 4
                    Case 0x4433
                        DllStructSetData($tStruct, $iE, 0x8888, 1)
                        $sType = (DllStructGetData($tStruct, $iE, 1) > 0 ? "ushort" : "short")
                        $iTypeSize = 2
                    Case 0x33
                        $sType = 'byte'
                        $iTypeSize = 1
                EndSwitch
            Case 'Ptr'
                $sType = 'ptr'
                $iTypeSize = @AutoItX64 ? 8 : 4
            Case 'String'
                DllStructSetData($tStruct, $iE, ChrW(0x2573), 1)
                $sType = (DllStructGetData($tStruct, $iE, 1) = ChrW(0x2573) ? "wchar" : "char")
                $iTypeSize = ($sType = 'wchar') ? 2 : 1
            Case 'Double'
                DllStructSetData($tStruct, $iE, 10 ^ - 15, 1)
                $sType = (DllStructGetData($tStruct, $iE, 1) = 10 ^ - 15 ? "double" : "float")
                $iTypeSize = ($sType = 'double') ? 8 : 4
        EndSwitch
        DllStructSetData($tStruct, $iE, $vElVal, 1)

        ;calculate element total size based on distance to next element
        $pNextPtr = DllStructGetPtr($tStruct, $iE + 1)
        $iElSize = $pNextPtr ? Int($pNextPtr - $pCurrentPtr) : $iDllSize

        ;calculate true array count. Walk index backwards till there is NOT an error
        $iArrCount = Int($iElSize / $iTypeSize)
        While $iArrCount > 1
            DllStructGetData($tStruct, $iE, $iArrCount)
            If Not @error Then ExitLoop
            $iArrCount -= 1
        WEnd

        ;alignment is whatever space is left
        $iAlign = $iElSize - ($iArrCount * $iTypeSize)
        $iElSize -= $iAlign

        ;Add/print values and alignment
        Switch $sType
            Case 'wchar', 'char', 'byte'
                _ArrayAdd($aStruct, $iE & '|' & $iOffset & '|' & $sType & '[' & $iArrCount & ']|' & $iElSize & '|' & DllStructGetData($tStruct, $iE))
            Case Else ; 'uint', 'int', 'ushort', 'short', 'double', 'float', 'ptr'
                If $iArrCount > 1 Then
                    _ArrayAdd($aStruct, $iE & '|' & $iOffset & '|' & $sType & '[' & $iArrCount & ']' & '|' & $iElSize & ' (' & $iTypeSize & ')|' & (DllStructGetData($tStruct, $iE) ? '[1] ' & $vElVal : '-'))
                    If DllStructGetData($tStruct, $iE) Then ; skip empty arrays
                        For $j = 2 To $iArrCount
                            _ArrayAdd($aStruct, '-|' & $iOffset + ($iTypeSize * ($j - 1)) & '|-|-|[' & $j & '] ' & DllStructGetData($tStruct, $iE, $j))
                        Next
                    EndIf
                Else
                    _ArrayAdd($aStruct, $iE & '|' & $iOffset & '|' & $sType & '|' & $iElSize & '|' & $vElVal)
                EndIf
        EndSwitch
        If $iAlign Then _ArrayAdd($aStruct, '-|-|<alignment>|' & ($iAlign) & '|-')

        ;if no next ptr then this was the last/only element
        If Not $pNextPtr Then ExitLoop

        ;update offset, size and next ptr
        $iOffset += $iElSize + $iAlign
        $iDllSize -= $iElSize + $iAlign
        $pCurrentPtr = $pNextPtr

    Next

    _ArrayAdd($aStruct, '-|' & DllStructGetPtr($tStruct) + DllStructGetSize($tStruct) & '|<endstruct>|' & DllStructGetSize($tStruct) & '|-')

    _ArrayDisplay($aStruct, '', '', 64, Default, '#|Offset|Type|Size|Value')

    Return $aStruct

EndFunc   ;==>_dlldisplay

 

Edited by Beege
Link to comment
Share on other sites

To be honest I never find it urgent to invest time and more complexity to detect non-standard align directives.  Indeed it's quite uncommon to encounter real-world structures needing something like "align 8;byte;byte[4];align 1; byte;word; align 4;byte;..." and I don't even know how one would use it except for interfacing with weird assembly code.

I know it's possible as you show but is that necessary in daily work?

Also I didn't bother with nested struct..endstruct directives, but I confess being lazy ... and not using AutoIt at all for my own needs.

If I ever add something, that will be a dump of scripting dictionary objects (something easy to do), since the Map datatype seems to be falling in obsolescence (unfortunately).

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 here
RegExp tutorial: enough to get started
PCRE 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

You cant imply this is a more complicated method. You just cant. I'm using simple arithmetic to establish the array count, not the alignment. The alignment/padding just happens to end up being a easy bonus since we know both space-allocated and actual space-used. Alignment is just the difference now. 

We dont need a crazy structure like that to demonstrate how standard alignment can by itself get tricky with the padding, especially when your a beginner just grasping what alignment is.  Each one of these will end up with multiple padding statements:

$tStruct = 'byte Enabled;dword Value'
_dlldisplay(DllStructCreate($tStruct))

$tStruct = 'byte Enabled;dword Value;word Idx'
_dlldisplay(DllStructCreate($tStruct))

; incorrect way of defining collection of structures
$tStruct &= ';' & $tStruct
_dlldisplay(DllStructCreate($tStruct))

; correct way - notice the alignment difference
$tStructForCollection = 'struct;byte Enabled;dword Value;word Idx;endstruct'
$tStructForCollection &= ';' & $tStructForCollection
_dlldisplay(DllStructCreate($tStructForCollection))

Outputs:

byte Enabled;dword Value
 _______________________________________________________
| #   | Offset       | Type          | Size   | Value   | 
|¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯|
| -   | 0x04840BD8   | <struct>      | 0      | -       | 
| 1   | 0            | byte[1]       | 1      | 0       | 
| -   | -            | <alignment>   | 3      | -       | <<<
| 2   | 4            | uint          | 4      | 0       | 
| -   | 0x04840BE0   | <endstruct>   | 8      | -       | 
 ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

byte Enabled;dword Value;word Idx
 _______________________________________________________
| #   | Offset       | Type          | Size   | Value   | 
|¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯|
| -   | 0x0484A8C0   | <struct>      | 0      | -       | 
| 1   | 0            | byte[1]       | 1      | 0       | 
| -   | -            | <alignment>   | 3      | -       | <<<
| 2   | 4            | uint          | 4      | 0       | 
| 3   | 8            | ushort        | 2      | 0       | 
| -   | -            | <alignment>   | 2      | -       | <<<
| -   | 0x0484A8CC   | <endstruct>   | 12     | -       | 
 ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

byte Enabled;dword Value;word Idx;byte Enabled;dword Value;word Idx
 _______________________________________________________
| #   | Offset       | Type          | Size   | Value   | 
|¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯|
| -   | 0x047FD050   | <struct>      | 0      | -       | 
| 1   | 0            | byte[1]       | 1      | 0       | 
| -   | -            | <alignment>   | 3      | -       | <<<
| 2   | 4            | uint          | 4      | 0       | 
| 3   | 8            | ushort        | 2      | 0       | 
| 4   | 10           | byte[1]       | 1      | 0       | 
| -   | -            | <alignment>   | 1      | -       | <<<
| 5   | 12           | uint          | 4      | 0       | 
| 6   | 16           | ushort        | 2      | 0       | 
| -   | -            | <alignment>   | 2      | -       | <<<
| -   | 0x047FD064   | <endstruct>   | 20     | -       | 
 ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

struct;byte Enabled;dword Value;word Idx;endstruct;struct;byte Enabled;dword Value;word Idx;endstruct
 _______________________________________________________
| #   | Offset       | Type          | Size   | Value   | 
|¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯|
| -   | 0x047FD1D0   | <struct>      | 0      | -       | 
| 1   | 0            | byte[1]       | 1      | 0       | 
| -   | -            | <alignment>   | 3      | -       | <<<
| 2   | 4            | uint          | 4      | 0       | 
| 3   | 8            | ushort        | 2      | 0       | 
| -   | -            | <alignment>   | 2      | -       | <<<
| 4   | 12           | byte[1]       | 1      | 0       | 
| -   | -            | <alignment>   | 3      | -       | <<<
| 5   | 16           | uint          | 4      | 0       | 
| 6   | 20           | ushort        | 2      | 0       | 
| -   | -            | <alignment>   | 2      | -       | <<<
| -   | 0x047FD1E8   | <endstruct>   | 24     | -       | 
 ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

 

Right here was my first introduction to what alignment/padding was and I totally thought @trancexx was fucking with me. Even after she explained it and @wraithdu gave me the fix, I still didnt completely understand what we were talking about. At the time struct/endstruct didn't exist so that didnt help things. The last two structs above showing incorrect/correct collections shows exactly the problem I was having back then and how the alignment ends up different. 

 

Edited by Beege
Link to comment
Share on other sites

You're correct: it's just my lazyness

 

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 here
RegExp tutorial: enough to get started
PCRE 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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...