├── AHKStructures.ahk ├── README ├── _Struct.Example.ahk ├── _Struct.ahk └── sizeof.ahk /AHKStructures.ahk: -------------------------------------------------------------------------------- 1 | ; AHK Structures 2 | _AHKDerefType := "LPTSTR marker,{_AHKVar *var,_AHKFunc *func},BYTE is_function,BYTE param_count,WORD length" 3 | _AHKExprTokenType := "{__int64 value_int64,double value_double,struct{{PTR *object,_AHKDerefType *deref,_AHKVar *var,LPTSTR marker},{LPTSTR buf,size_t marker_length}}},UINT symbol,{_AHKExprTokenType *circuit_token,LPTSTR mem_to_free}" 4 | _AHKArgStruct := "BYTE type,BYTE is_expression,WORD length,LPTSTR text,_AHKDerefType *deref,_AHKExprTokenType *postfix" 5 | _AHKLine := "BYTE ActionType,BYTE Argc,WORD FileIndex,UINT LineNumber,_AHKArgStruct *Arg,PTR *Attribute,*_AHKLine PrevLine,*_AHKLine NextLine,*_AHKLine RelatedLine,*_AHKLine ParentLine" 6 | _AHKLabel := "LPTSTR name,*_AHKLine JumpToLine,*_AHKLabel PrevLabel,*_AHKLabel NextLabel" 7 | _AHKFuncParam := "*_AHKVar var,UShort is_byref,UShort default_type,{default_str,Int64 default_int64,Double default_double}" 8 | If (A_PtrSize = 8) 9 | _AHKRCCallbackFunc := "UINT64 data1,UINT64 data2,PTR stub,UINT_PTR callfuncptr,BYTE actual_param_count,BYTE create_new_thread,event_info,*_AHKFunc func" 10 | else 11 | _AHKRCCallbackFunc := "ULONG data1,ULONG data2,ULONG data3,PTR stub,UINT_PTR callfuncptr,ULONG data4,ULONG data5,BYTE actual_param_count,BYTE create_new_thread,event_info,*_AHKFunc func" 12 | _AHKFunc := "PTR vTable,LPTSTR name,{PTR BIF,*_AHKLine JumpToLine},*_AHKFuncParam Param,Int ParamCount,Int MinParams,*_AHKVar var,*_AHKVar LazyVar,Int VarCount,Int VarCountMax,Int LazyVarCount,Int Instances,*_AHKFunc NextFunc,BYTE DefaultVarType,BYTE IsBuiltIn" 13 | _AHKVar := "{Int64 ContentsInt64,Double ContentsDouble,PTR object},{char *mByteContents,LPTSTR CharContents},{UINT_PTR Length,_AHKVar *AliasFor},{UINT_PTR Capacity,UINT_PTR BIV},BYTE HowAllocated,BYTE Attrib,BYTE IsLocal,BYTE Type,LPTSTR Name" -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | _Struct is a class that is used to get easy access to structures and its members. 2 | 3 | sizeof() is used to calculate structure size and is mandatory for _Struct to work. 4 | 5 | Read about usage of _Struct here: http://www.autohotkey.net/~HotKeyIt/AutoHotkey/_Struct.htm 6 | Read about usage of sizeof here: http://www.autohotkey.net/~HotKeyIt/AutoHotkey/sizeof.htm 7 | 8 | 9 | Download _Struct.ahk and sizeof.ahk to your library (Path of AutoHotkey.exe\Lib\_Struct.ahk...) 10 | 11 | Visit _Struct on AutoHotkey forum http://www.autohotkey.com/forum/viewtopic.php?p=364838#364838! 12 | 13 | Companion projects: 14 | [WinStructs](https://github.com/ahkscript/WinStructs) - A collection of definitions for Windows Structures. If you create structure definitions, please add them here so only one person ever need do a structure. 15 | 16 | [AHK-SizeOf-Checker](https://github.com/ahkscript/AHK-SizeOf-Checker) - Verifies sizes of structures that _Struct creates against the size of the structure reported in compiled C++ code. 17 | REQUIRES VISUAL STUDIO. 18 | -------------------------------------------------------------------------------- /_Struct.Example.ahk: -------------------------------------------------------------------------------- 1 | #Include <_Struct> 2 | id: 3 | { ; Struct() examples 4 | 5 | MsgBox Example1 6 | gosub Example1 7 | MsgBox Example2 8 | gosub Example2 9 | MsgBox Example3 10 | gosub Example3 11 | MsgBox Example4 12 | gosub Example4 13 | MsgBox Example5 14 | gosub Example5 15 | MsgBox Example6 16 | gosub Example6 17 | MsgBox Example7 18 | gosub Example7 19 | MsgBox Example8 20 | gosub Example8 21 | MsgBox Example9 22 | gosub Example9 23 | MsgBox Example10 24 | gosub Example10 25 | }ExitApp 26 | Example1: 27 | { 28 | ; Simple user defined structure (Use number for characters, so StrGet/StrSet will be used) 29 | ;typedef struct { 30 | ; TCHAR char[2]; 31 | ; int code[2]; 32 | ;} ASCIICharacter; 33 | MyChar := new _Struct("Char char[2],int code[2]") ;create structure, type for code could be omited 34 | MyChar.char.1:="A" 35 | MyChar.char.2:="B" 36 | MyChar.code.1 := 64 37 | MyChar.code.2 := 65 38 | MsgBox % MyChar.char.1 " = " MyChar.code.1 "`n" MyChar.char.2 " = " MyChar.code.2 39 | }return 40 | Example2: 41 | { 42 | ; Simple array of 26 characters 43 | ;~ MsgBox % sizeof(tchar) 44 | String:=new _Struct("TCHAR char[26]") 45 | Loop 26 46 | string["char"][A_Index]:=Chr(A_Index+64) 47 | Loop 3 48 | MsgBox % String["char"][A_Index*2] ;show some characters 49 | MsgBox % StrGet(string[],26) ;get complete string 50 | }return 51 | Example3: 52 | { 53 | ; Array of structures 54 | user:="LPTSTR Id, LPTSTR Name" 55 | users := new _Struct("user[2]") ; array of structs 56 | MsgBox % users.Size() 57 | VarSetCapacity(mem1,1000) 58 | users.1.id[""]:=&mem1 59 | users.1.name[""]:=(&mem1)+200 60 | users.2.id[""]:=(&mem1)+400 61 | users.2.name[""]:=(&mem1)+600 62 | users.1.Id := "Id1" , users.1.Name := "Name 1" 63 | users.2.Id := "Id2", users.2.Name := "Name 2" 64 | MsgBox % users.1.Id " " users.1.Name "`n" users.2.Id " " users.2.Name 65 | }return 66 | Example4: 67 | { 68 | ; Vector example 69 | Vector:="a,b,c,d" 70 | v:=new _Struct("Vector[2]") ;create an array of Vertors 71 | MsgBox % IsObject(v) 72 | MsgBox % sizeof("Vector[2]") "-" sizeof(v) 73 | v.1.a:=1 ;set some keys 74 | v.2.c:=10 ;set some keys 75 | MsgBox % v.1.a "`n" v.2.c ;show values 76 | 77 | VarSetCapacity(newmem,sizeof(v)) ;resevere some memory for new structure 78 | v[]:=&newmem ;set new memory address 79 | MsgBox % v.1.a "`n" v.2.c ;show new structure 80 | v.1.a:=1 81 | v.2.c:=10 82 | MsgBox % v.1.a "`n" v.2.c ;now values are filled 83 | }return 84 | Example5: 85 | { 86 | ; RECT example 87 | ;Example using RECT structure to move a window 88 | Gui,+LastFound 89 | hwnd:=WinExist() ;get window handle 90 | _RECT:="left,top,right,bottom" 91 | RC:=new _Struct(_RECT) ;create structure 92 | Gui,Add,Text,,Press Escape to continue 93 | Gui,Show,w200 h100 ;show window 94 | DllCall("GetWindowRect","Uint",hwnd,"Uint",rc[]) ;get window position 95 | rc.right := rc.right - rc.left ;Set rc.right to be the width 96 | rc.bottom := rc.bottom - rc.top ;Set rc.bottom to be the height 97 | While DllCall("GetCursorPos","Uint",rc[]) 98 | && DllCall("MoveWindow","Uint",hwnd 99 | ,"int",rc.left,"int",rc.top,"int",rc.right,"int",rc.bottom,"Int",1) 100 | If GetKeyState("Escape","P") 101 | break 102 | Gui,Destroy 103 | rc:="" 104 | }return 105 | Example6: 106 | { 107 | ; FindFirstFile && FindNextFile && FileTimeToSystemTime 108 | _FILETIME := "dwLowDateTime,dwHighDateTime" 109 | _SYSTEMTIME := "WORD wYear,WORD wMonth,WORD wDayOfWeek,WORD wDay,WORD wHour,WORD wMinute,WORD wSecond,WORD Milliseconds" 110 | _WIN32_FIND_DATA := "dwFileAttributes,_FILETIME ftCreationTime,_FILETIME ftLastAccessTime,_FILETIME ftLastWriteTime,UInt nFileSizeHigh,nFileSizeLow,dwReserved0,dwReserved1,TCHAR cFileName[260],TCHAR cAlternateFileName[14]" 111 | 112 | file:=new _Struct("_WIN32_FIND_DATA[2]") 113 | time:=new _Struct("_SYSTEMTIME") 114 | ;~ MsgBox % IsObject(time) 115 | ;~ MsgBox % IsObject(file) "-" IsObject(time) "-" file[] "-" file.1[] 116 | DllCall("FindFirstFile","Str",A_ScriptFullPath,"Uint",file.1[""]) 117 | DllCall("FindFirstFile","Str",A_AhkPath,"UInt",file.2[""]) 118 | MsgBox % StrGet(file.1.cFileName[""]) 119 | MsgBox % "A_ScriptFullPath:`t" StrGet(file.1.cFileName[""]) "`t" StrGet(file.1.cAlternateFileName[""]) "`nA_AhkPath:`t" StrGet(file.2.cFileName[""]) "`t" StrGet(file.2.cAlternateFileName[""]) 120 | 121 | handle:=DllCall("FindFirstFile","Str","C:\*","Uint",file.2[""]) 122 | Loop { 123 | If !DllCall("FindNextFile","Uint",handle,"Uint",file.2[""]) 124 | break 125 | DllCall("FileTimeToSystemTime","Uint",file.2.ftLastWriteTime[""],"Uint",time[""]) 126 | ToolTip % StrGet(file.2.cFileName[""]) "`n" StrGet(file.2.cAlternateFileName[""]) "`n" file.2.nFileSizeHigh " - " file.2.nFileSizeLow 127 | . "`n" time.wYear . "-" time.wMonth . "-" time.wDay 128 | . "`n" time.wDayOfWeek 129 | . "`n" time.wHour . ":" time.wMinute . ":" time.wSecond . ":" time.Milliseconds 130 | Sleep, 200 131 | } 132 | ToolTip 133 | DllCall("FindClose","Uint",handle) 134 | }return 135 | Example7: 136 | { 137 | ; Predefinition of structures 138 | MyStruct:=new _Struct("a,b,c,d") 139 | MyStruct.a:=1 140 | MsgBox % MyStruct.a 141 | 142 | ; C/C++ like syntax 143 | NewStruct:=" 144 | ( 145 | TCHAR char[11]; // Array of 11 characters 146 | TCHAR char2[11]; // Another array of 11 characters 147 | LPTSTR string; // String 148 | Int integer; // Integer 149 | PTR pointer; // Pointer 150 | )" 151 | 152 | MyStruct:=new _Struct(NewStruct) 153 | VarSetCapacity(string,100) 154 | MyStruct.string[""] := &string 155 | MyStruct.char.1:="A" ;set first char 156 | MyStruct.char2.1:="ABC" ;here only first characters will be writter to the array char2 157 | MyStruct.string := "New String" 158 | MyStruct.integer := 100 159 | MyStruct.pointer := &MyStruct 160 | 161 | MsgBox % MyStruct.char.1 "`n" 162 | . StrGet(MyStruct.char2[""]) "`n" 163 | . MyStruct.String "`n" 164 | . MyStruct.integer "`n" 165 | . MyStruct.pointer "`n" 166 | }return 167 | Example8: 168 | { 169 | ;Pointer example 170 | ;Create a variable containing a string 171 | var:="AutoHotKey" 172 | MsgBox % sizeof("*UInt p") 173 | ;Create a pointer that will point to the variable/string 174 | VarSetCapacity(v,A_PtrSize),NumPut(&var,v,"PTR") 175 | s:=new _Struct("*Uint p",&v) 176 | MsgBox % s.p[""] "-" s[] 177 | MsgBox % StrGet(s.p["",""]) 178 | 179 | ;assign another pointer 180 | anothervar:="AutoHotkey_L" 181 | s.p[""]:=&anothervar 182 | MsgBox % StrGet(s.p["",""]) 183 | 184 | ;Using LPTSTR you can assign a string directly 185 | VarSetCapacity(string,100) 186 | s:=new _Struct("LPTSTR p") 187 | s.p[""]:=&string 188 | s.p:="String" 189 | MsgBox % s.p 190 | s.p[""]:=&var 191 | MsgBox % s.p 192 | }return 193 | Example9: 194 | { 195 | ; PROCESSENTRY32 196 | MAX_PATH:=260 197 | _PROCESSENTRY32:=" 198 | (Q 199 | DWORD dwSize; 200 | DWORD cntUsage; 201 | DWORD th32ProcessID; 202 | ULONG_PTR th32DefaultHeapID; 203 | DWORD th32ModuleID; 204 | DWORD cntThreads; 205 | DWORD th32ParentProcessID; 206 | LONG pcPriClassBase; 207 | DWORD dwFlags; 208 | TCHAR szExeFile[" MAX_PATH "]; 209 | )" 210 | VarSetCapacity(string,260) 211 | pEntry:= new _Struct(_PROCESSENTRY32) 212 | pEntry.dwSize := sizeof(_PROCESSENTRY32) 213 | hSnapshot:=DllCall("CreateToolhelp32Snapshot","UInt",TH32CS_SNAPALL:=0x0000001F,"PTR",0) 214 | DllCall("Process32First" (A_IsUnicode?"W":""),"PTR",hSnapshot,"PTR",pEntry[""]) 215 | While % (A_Index=1 || DllCall("Process32Next" (A_IsUnicode?"W":""),"PTR",hSnapshot,"PTR",pEntry[""])) { 216 | ToolTip % pEntry.cntUsage "`n" pEntry.th32ProcessID 217 | . "`n" pEntry.th32DefaultHeapID "`n" pEntry.th32ModuleID 218 | . "`n" pEntry.cntThreads "`n" pEntry.th32ParentProcessID 219 | . "`n" pEntry.pcPriClassBase "`n" pEntry.dwFlags "`n" StrGet(pEntry.szExeFile[""]) 220 | Sleep, 200 221 | } 222 | ToolTip 223 | }return 224 | Example10: 225 | { 226 | ; MODULEENTRY32 227 | MAX_PATH:=260 228 | MAX_MODULE_NAME32:=255 229 | _MODULEENTRY32:=" 230 | (Q 231 | DWORD dwSize; 232 | DWORD th32ModuleID; 233 | DWORD th32ProcessID; 234 | DWORD GlblcntUsage; 235 | DWORD ProccntUsage; 236 | BYTE *modBaseAddr; 237 | DWORD modBaseSize; 238 | HMODULE hModule; 239 | TCHAR szModule[" MAX_MODULE_NAME32 + 1 "]; 240 | TCHAR szExePath[" MAX_PATH "]; 241 | )" 242 | 243 | ListProcessModules(DllCall("GetCurrentProcessId")) 244 | Return 245 | 246 | ListProcessModules(dwPID) 247 | { 248 | global _Struct 249 | static TH32CS_SNAPMODULE:=0x00000008,INVALID_HANDLE_VALUE:=-1 250 | hModuleSnap := new _Struct("HANDLE") 251 | me32 := new _Struct("_MODULEENTRY32") 252 | 253 | ; Take a snapshot of all modules in the specified process. 254 | hModuleSnap := DllCall("CreateToolhelp32Snapshot","UInt", TH32CS_SNAPMODULE,"PTR", dwPID ) 255 | if( hModuleSnap = INVALID_HANDLE_VALUE ) 256 | { 257 | MsgBox % "CreateToolhelp32Snapshot (of modules)" 258 | return FALSE 259 | } 260 | 261 | ; Set the size of the structure before using it. 262 | me32.dwSize := sizeof("_MODULEENTRY32") 263 | 264 | ; Retrieve information about the first module, 265 | ; and exit if unsuccessful 266 | 267 | if( !DllCall("Module32First" (A_IsUnicode?"W":""),"PTR", hModuleSnap,"PTR", me32[""] ) ) 268 | { 269 | MsgBox % "Module32First" ; // Show cause of failure 270 | DllCall("CloseHandle","PTR", hModuleSnap ) ; // Must clean up the snapshot object! 271 | return FALSE 272 | } 273 | 274 | ;// Now walk the module list of the process, 275 | ;// and display information about each module 276 | while(A_Index=1 || DllCall("Module32Next" (A_IsUnicode?"W":""),"PTR",hModuleSnap,"PTR", me32[""] ) ) 277 | { 278 | ToolTip % "`tMODULE NAME`t=`t" StrGet(me32.szModule[""]) 279 | . "`n`texecutable`t=`t" StrGet(me32.szExePath[""]) 280 | . "`n`tprocess ID`t=`t" me32.th32ProcessID 281 | . "`n`tref count (g)`t=`t" me32.GlblcntUsage 282 | . "`n`tref count (p)`t=`t" me32.ProccntUsage 283 | . "`n`tbase address`t=`t" me32.modBaseAddr[""] 284 | . "`n`tbase size`t=`t" me32.modBaseSize 285 | Sleep, 1000 286 | } 287 | 288 | ;// Do not forget to clean up the snapshot object. 289 | DllCall("CloseHandle","PTR",hModuleSnap) 290 | return TRUE 291 | } 292 | 293 | } 294 | 295 | 296 | 297 | 298 | 299 | -------------------------------------------------------------------------------- /_Struct.ahk: -------------------------------------------------------------------------------- 1 | ;: Title: _Struct by HotKeyIt 2 | ; 3 | 4 | ; Function: _Struct 5 | ; Description: 6 | ; _Struct is based on AHK_L objects and supports both, ANSI and UNICODE version. To use it you will require Lexikos AutoHotkey_L.exe or other versions based on it.

new _Struct is used to create new structure. A structure must be defined as a global variable or an item of global class (e.g. "MyClass.Struct").
_Struct can handle structure in structure as well as Arrays of structures and Vectors.
Visit _Struct on AutoHotkey forum, any feedback is welcome. 7 | ; Syntax: MyStruct:= new _Struct(Structure_Definition,Address,initialization) 8 | ; Parameters: 9 | ; General Design - Class _Struct will create Object(s) that will manage fields of structure(s), for example
left,top,right,bottom
RC := new _Struct("RECT")
will create a RECT structure with fields left,top,right,bottom of type UInt. To pass the structure its pointer to a function, DllCall or SendMessage use RC[""].

To access fields you can use usual Object syntax: RC.left, RC.right ...
To set a field of the structure use RC.top := 100. 10 | ; Field types - Following AutoHotkey and Windows Data Types are supported:

AutoHotkey Data Types:
Int, Uint, Int64, UInt64, Char, UChar, Short, UShort, Fload and Double.

Windows Data Types:
ATOM,BOOL,BOOLEAN,BYTE,CHAR,COLORREF,DWORD,DWORDLONG,DWORD_PTR,
DWORD32,DWORD64,FLOAT,HACCEL,HALF_PTR,HANDLE,HBITMAP,HBRUSH,HCOLORSPACE,HCONV,HCONVLIST,HCURSOR,HDC,
HDDEDATA,HDESK,HDROP,HDWP,HENHMETAFILE,HFILE,HFONT,HGDIOBJ,HGLOBAL,HHOOK,HICON,HINSTANCE,HKEY,HKL,
HLOCAL,HMENU,HMETAFILE,HMODULE,HMONITOR,HPALETTE,HPEN,HRESULT,HRGN,HRSRC,HSZ,HWINSTA,HWND,INT,
INT_PTR,INT32,INT64,LANGID,LCID,LCTYPE,LGRPID,LONG,LONGLONG,LONG_PTR,LONG32,LONG64,LPARAM,LPBOOL,
LPBYTE,LPCOLORREF,LPCSTR,LPCTSTR,LPCVOID,LPCWSTR,LPDWORD,LPHANDLE,LPINT,LPLONG,LPSTR,LPTSTR,LPVOID,
LPWORD,LPWSTR,LRESULT,PBOOL,PBOOLEAN,PBYTE,PCHAR,PCSTR,PCTSTR,PCWSTR,PDWORD,PDWORDLONG,PDWORD_PTR,
PDWORD32,PDWORD64,PFLOAT,PHALF_PTR,PHANDLE,PHKEY,PINT,PINT_PTR,PINT32,PINT64,PLCID,PLONG,PLONGLONG,
PLONG_PTR,PLONG32,PLONG64,POINTER_32,POINTER_64,POINTER_SIGNED,POINTER_UNSIGNED,PSHORT,PSIZE_T,
PSSIZE_T,PSTR,PTBYTE,PTCHAR,PTSTR,PUCHAR,PUHALF_PTR,PUINT,PUINT_PTR,PUINT32,PUINT64,PULONG,PULONGLONG,
PULONG_PTR,PULONG32,PULONG64,PUSHORT,PVOID,PWCHAR,PWORD,PWSTR,SC_HANDLE,SC_LOCK,SERVICE_STATUS_HANDLE,
SHORT,SIZE_T,SSIZE_T,TBYTE,TCHAR,UCHAR,UHALF_PTR,UINT,UINT_PTR,UINT32,UINT64,ULONG,ULONGLONG,
ULONG_PTR,ULONG32,ULONG64,USHORT,USN,WCHAR,WORD,WPARAM 11 | ; Structure Definition - Description 12 | ; User defined - To create a user defined structure you will need to pass a string of predefined types and field names.
Default type is UInt, so for example for a RECT structure type can be omited: "left,top,right,left", which is the same as "Uint left,Uint top,Uint right,Uint bottom"

You can also use structures very similar to C#/C++ syntax, see example. 13 | ; Global - Global variables can be used to save structures, easily pass name of that variable as first parameter, e.g. new _Struct("MyStruct") where MyStruct must be a global variable with structure definition. Also new _Struct(MyStruct) can be used if variable is accessible. 14 | ; Array - To create an array of structures include a digit in the end of your string enclosed in squared brackets.
For example "RECT[2]" would create an array of 2 structures.
This feature can also be used for user defined arrays, for example "Int age,TCHAR name[10]". 15 | ; Union - Using {} you can create union, for example:
_AHKVar:="{Int64 ContentsInt64,Double ContentsDouble,object},... 16 | ; Struct - Using struct{} you can create structures in union or in structures. 17 | ; Pointer - To create a pointer you can use *, for example: CHR:="char *str" will hold a pointer to a character. Same way you can have a structure in structure so you can call it recursive, for example Label.NextLabel.NextLabel.NextLabel.JumpToLine 18 | ; Parameters - Description 19 | ; MyStruct - This is a variable that will hold the object representing the strucuture which is returned by new _Struct(...). 20 | ; Structure_Definition - C/C++ syntax or one-line definition e.g. "Int x,Int y". 21 | ; pointer - Pass a pointer as second parameter to occupy existing strucure. 22 | ; Initialization - Pass an object to initialize structure, e.g. {left:100,top:20}. If pointer is not used initialization can be specified in second parameter. 23 | ; Methods - Description 24 | ; Strct.Type(itm) - Returns type of item or structure 25 | ; Strct.AhkType(itm) - Returns AHK type of item or structure to be used with NumGet and NumPut as well as DllCall 26 | ; Strct.Size() - Returns size of structure, same as sizeof(MyStruct) 27 | ; Strct.SizeT(itm) - Returns size of an item 28 | ; Strct.Offset(itm) - Returns offset for items 29 | ; Strct.Encoding(itm) - Returns encoding for items, to be used with StrGet and StrPut 30 | ; Strct.Alloc(itm,size[,ptrsize]) - Allocates memory in bytes, ptrsize is used to create pointers 31 | ; Strct.Capacity(itm) - Returns memory capacity for items. 32 | ; Strct.IsPointer(itm) - Returns whether the item is a pointer (defined using *). 33 | ; Return Value: 34 | ; A class object representing your structure 35 | ; Remarks: 36 | ; NOTE!!! accessing a field that does not exist will cause recrusive calls and will crash your script, these errors are not catched for performance reasons.
TCHAR, UCHAR and CHAR return actual character rather than the value, use Asc() function to find out the value/code. 37 | ; Related: 38 | ; Example: 39 | ; file:Struct_Example.ahk 40 | ; 41 | #Include 42 | Class _Struct { 43 | ; Data Sizes 44 | static PTR:=A_PtrSize,UPTR:=A_PtrSize,SHORT:=2,USHORT:=2,INT:=4,UINT:=4,__int64:=8,INT64:=8,UINT64:=8,DOUBLE:=8,FLOAT:=4,CHAR:=1,UCHAR:=1,VOID:=A_PtrSize 45 | ,TBYTE:=A_IsUnicode?2:1,TCHAR:=A_IsUnicode?2:1,HALF_PTR:=A_PtrSize=8?4:2,UHALF_PTR:=A_PtrSize=8?4:2,INT32:=4,LONG:=4,LONG32:=4,LONGLONG:=8 46 | ,LONG64:=8,USN:=8,HFILE:=4,HRESULT:=4,INT_PTR:=A_PtrSize,LONG_PTR:=A_PtrSize,POINTER_64:=A_PtrSize,POINTER_SIGNED:=A_PtrSize 47 | ,BOOL:=4,SSIZE_T:=A_PtrSize,WPARAM:=A_PtrSize,BOOLEAN:=1,BYTE:=1,COLORREF:=4,DWORD:=4,DWORD32:=4,LCID:=4,LCTYPE:=4,LGRPID:=4,LRESULT:=4,PBOOL:=4 48 | ,PBOOLEAN:=A_PtrSize,PBYTE:=A_PtrSize,PCHAR:=A_PtrSize,PCSTR:=A_PtrSize,PCTSTR:=A_PtrSize,PCWSTR:=A_PtrSize,PDWORD:=A_PtrSize,PDWORDLONG:=A_PtrSize 49 | ,PDWORD_PTR:=A_PtrSize,PDWORD32:=A_PtrSize,PDWORD64:=A_PtrSize,PFLOAT:=A_PtrSize,PHALF_PTR:=A_PtrSize 50 | ,UINT32:=4,ULONG:=4,ULONG32:=4,DWORDLONG:=8,DWORD64:=8,ULONGLONG:=8,ULONG64:=8,DWORD_PTR:=A_PtrSize,HACCEL:=A_PtrSize,HANDLE:=A_PtrSize 51 | ,HBITMAP:=A_PtrSize,HBRUSH:=A_PtrSize,HCOLORSPACE:=A_PtrSize,HCONV:=A_PtrSize,HCONVLIST:=A_PtrSize,HCURSOR:=A_PtrSize,HDC:=A_PtrSize 52 | ,HDDEDATA:=A_PtrSize,HDESK:=A_PtrSize,HDROP:=A_PtrSize,HDWP:=A_PtrSize,HENHMETAFILE:=A_PtrSize,HFONT:=A_PtrSize 53 | static HGDIOBJ:=A_PtrSize,HGLOBAL:=A_PtrSize,HHOOK:=A_PtrSize,HICON:=A_PtrSize,HINSTANCE:=A_PtrSize,HKEY:=A_PtrSize,HKL:=A_PtrSize 54 | ,HLOCAL:=A_PtrSize,HMENU:=A_PtrSize,HMETAFILE:=A_PtrSize,HMODULE:=A_PtrSize,HMONITOR:=A_PtrSize,HPALETTE:=A_PtrSize,HPEN:=A_PtrSize 55 | ,HRGN:=A_PtrSize,HRSRC:=A_PtrSize,HSZ:=A_PtrSize,HWINSTA:=A_PtrSize,HWND:=A_PtrSize,LPARAM:=A_PtrSize,LPBOOL:=A_PtrSize,LPBYTE:=A_PtrSize 56 | ,LPCOLORREF:=A_PtrSize,LPCSTR:=A_PtrSize,LPCTSTR:=A_PtrSize,LPCVOID:=A_PtrSize,LPCWSTR:=A_PtrSize,LPDWORD:=A_PtrSize,LPHANDLE:=A_PtrSize 57 | ,LPINT:=A_PtrSize,LPLONG:=A_PtrSize,LPSTR:=A_PtrSize,LPTSTR:=A_PtrSize,LPVOID:=A_PtrSize,LPWORD:=A_PtrSize,LPWSTR:=A_PtrSize,PHANDLE:=A_PtrSize 58 | ,PHKEY:=A_PtrSize,PINT:=A_PtrSize,PINT_PTR:=A_PtrSize,PINT32:=A_PtrSize,PINT64:=A_PtrSize,PLCID:=A_PtrSize,PLONG:=A_PtrSize,PLONGLONG:=A_PtrSize 59 | ,PLONG_PTR:=A_PtrSize,PLONG32:=A_PtrSize,PLONG64:=A_PtrSize,POINTER_32:=A_PtrSize,POINTER_UNSIGNED:=A_PtrSize,PSHORT:=A_PtrSize,PSIZE_T:=A_PtrSize 60 | ,PSSIZE_T:=A_PtrSize,PSTR:=A_PtrSize,PTBYTE:=A_PtrSize,PTCHAR:=A_PtrSize,PTSTR:=A_PtrSize,PUCHAR:=A_PtrSize,PUHALF_PTR:=A_PtrSize,PUINT:=A_PtrSize 61 | ,PUINT_PTR:=A_PtrSize,PUINT32:=A_PtrSize,PUINT64:=A_PtrSize,PULONG:=A_PtrSize,PULONGLONG:=A_PtrSize,PULONG_PTR:=A_PtrSize,PULONG32:=A_PtrSize 62 | ,PULONG64:=A_PtrSize,PUSHORT:=A_PtrSize,PVOID:=A_PtrSize,PWCHAR:=A_PtrSize,PWORD:=A_PtrSize,PWSTR:=A_PtrSize,SC_HANDLE:=A_PtrSize 63 | ,SC_LOCK:=A_PtrSize,SERVICE_STATUS_HANDLE:=A_PtrSize,SIZE_T:=A_PtrSize,UINT_PTR:=A_PtrSize,ULONG_PTR:=A_PtrSize,ATOM:=2,LANGID:=2,WCHAR:=2,WORD:=2,USAGE:=2 64 | ; Data Types 65 | static _PTR:="PTR",_UPTR:="UPTR",_SHORT:="Short",_USHORT:="UShort",_INT:="Int",_UINT:="UInt" 66 | ,_INT64:="Int64",_UINT64:="UInt64",_DOUBLE:="Double",_FLOAT:="Float",_CHAR:="Char",_UCHAR:="UChar" 67 | ,_VOID:="PTR",_TBYTE:=A_IsUnicode?"USHORT":"UCHAR",_TCHAR:=A_IsUnicode?"USHORT":"UCHAR",_HALF_PTR:=A_PtrSize=8?"INT":"SHORT" 68 | ,_UHALF_PTR:=A_PtrSize=8?"UINT":"USHORT",_BOOL:="Int",_INT32:="Int",_LONG:="Int",_LONG32:="Int",_LONGLONG:="Int64",_LONG64:="Int64" 69 | ,_USN:="Int64",_HFILE:="UInt",_HRESULT:="UInt",_INT_PTR:="PTR",_LONG_PTR:="PTR",_POINTER_64:="PTR",_POINTER_SIGNED:="PTR",_SSIZE_T:="PTR" 70 | ,_WPARAM:="PTR",_BOOLEAN:="UCHAR",_BYTE:="UCHAR",_COLORREF:="UInt",_DWORD:="UInt",_DWORD32:="UInt",_LCID:="UInt",_LCTYPE:="UInt" 71 | ,_LGRPID:="UInt",_LRESULT:="UInt",_PBOOL:="UPTR",_PBOOLEAN:="UPTR",_PBYTE:="UPTR",_PCHAR:="UPTR",_PCSTR:="UPTR",_PCTSTR:="UPTR" 72 | ,_PCWSTR:="UPTR",_PDWORD:="UPTR",_PDWORDLONG:="UPTR",_PDWORD_PTR:="UPTR",_PDWORD32:="UPTR",_PDWORD64:="UPTR",_PFLOAT:="UPTR",___int64:="Int64" 73 | ,_PHALF_PTR:="UPTR",_UINT32:="UInt",_ULONG:="UInt",_ULONG32:="UInt",_DWORDLONG:="UInt64",_DWORD64:="UInt64",_ULONGLONG:="UInt64" 74 | ,_ULONG64:="UInt64",_DWORD_PTR:="UPTR",_HACCEL:="UPTR",_HANDLE:="UPTR",_HBITMAP:="UPTR",_HBRUSH:="UPTR",_HCOLORSPACE:="UPTR" 75 | ,_HCONV:="UPTR",_HCONVLIST:="UPTR",_HCURSOR:="UPTR",_HDC:="UPTR",_HDDEDATA:="UPTR",_HDESK:="UPTR",_HDROP:="UPTR",_HDWP:="UPTR" 76 | static _HENHMETAFILE:="UPTR",_HFONT:="UPTR",_HGDIOBJ:="UPTR",_HGLOBAL:="UPTR",_HHOOK:="UPTR",_HICON:="UPTR",_HINSTANCE:="UPTR",_HKEY:="UPTR" 77 | ,_HKL:="UPTR",_HLOCAL:="UPTR",_HMENU:="UPTR",_HMETAFILE:="UPTR",_HMODULE:="UPTR",_HMONITOR:="UPTR",_HPALETTE:="UPTR",_HPEN:="UPTR" 78 | ,_HRGN:="UPTR",_HRSRC:="UPTR",_HSZ:="UPTR",_HWINSTA:="UPTR",_HWND:="UPTR",_LPARAM:="UPTR",_LPBOOL:="UPTR",_LPBYTE:="UPTR",_LPCOLORREF:="UPTR" 79 | ,_LPCSTR:="UPTR",_LPCTSTR:="UPTR",_LPCVOID:="UPTR",_LPCWSTR:="UPTR",_LPDWORD:="UPTR",_LPHANDLE:="UPTR",_LPINT:="UPTR",_LPLONG:="UPTR" 80 | ,_LPSTR:="UPTR",_LPTSTR:="UPTR",_LPVOID:="UPTR",_LPWORD:="UPTR",_LPWSTR:="UPTR",_PHANDLE:="UPTR",_PHKEY:="UPTR",_PINT:="UPTR" 81 | ,_PINT_PTR:="UPTR",_PINT32:="UPTR",_PINT64:="UPTR",_PLCID:="UPTR",_PLONG:="UPTR",_PLONGLONG:="UPTR",_PLONG_PTR:="UPTR",_PLONG32:="UPTR" 82 | ,_PLONG64:="UPTR",_POINTER_32:="UPTR",_POINTER_UNSIGNED:="UPTR",_PSHORT:="UPTR",_PSIZE_T:="UPTR",_PSSIZE_T:="UPTR",_PSTR:="UPTR" 83 | ,_PTBYTE:="UPTR",_PTCHAR:="UPTR",_PTSTR:="UPTR",_PUCHAR:="UPTR",_PUHALF_PTR:="UPTR",_PUINT:="UPTR",_PUINT_PTR:="UPTR",_PUINT32:="UPTR" 84 | ,_PUINT64:="UPTR",_PULONG:="UPTR",_PULONGLONG:="UPTR",_PULONG_PTR:="UPTR",_PULONG32:="UPTR",_PULONG64:="UPTR",_PUSHORT:="UPTR" 85 | ,_PVOID:="UPTR",_PWCHAR:="UPTR",_PWORD:="UPTR",_PWSTR:="UPTR",_SC_HANDLE:="UPTR",_SC_LOCK:="UPTR",_SERVICE_STATUS_HANDLE:="UPTR" 86 | static _SIZE_T:="UPTR",_UINT_PTR:="UPTR",_ULONG_PTR:="UPTR",_ATOM:="Ushort",_LANGID:="Ushort",_WCHAR:="Ushort",_WORD:="UShort",_USAGE:="UShort" 87 | 88 | ; Following is used internally only to simplify setting field helpers 89 | ; the corresponding key can be set to invalid type (for string integer and vice versa) to set default if necessary, e.g. ___InitField(N,"") 90 | ___InitField(_this,N,offset=" ",encoding=0,AHKType=0,isptr=" ",type=0,arrsize=0,memory=0){ ; N = Name of field 91 | static _prefixes_:={offset:"`b",isptr:"`r",AHKType:"`n",type:"`t",encoding:"`f",memory:"`v",arrsize:" "} 92 | ,_testtype_:={offset:"integer",isptr:"integer",AHKType:"string",type:"string",encoding:"string",arrsize:"integer"} 93 | ,_default_:={offset:0,isptr:0,AHKType:"UInt",type:"UINT",encoding:"CP0",memory:"",arrsize:1} 94 | for _key_,_value_ in _prefixes_ 95 | { 96 | _typevalid_:=0 97 | If (_testtype_[_key_]="Integer"){ 98 | If %_key_% is integer 99 | useDefault:=1,_typevalid_:=1 100 | else if !_this.HasKey(_value_ N) 101 | useDefault:=1 102 | } else { 103 | If %_key_% is not integer 104 | useDefault:=1,_typevalid_:=1 105 | else if !_this.HasKey(_value_ N) 106 | useDefault:=1 107 | } 108 | If (useDefault) ; item does not exist or user supplied a valid type 109 | If (_key_="encoding") 110 | _this[_value_ N]:=_typevalid_?(InStr(",LPTSTR,LPCTSTR,TCHAR,","," %_key_% ",")?(A_IsUnicode?"UTF-16":"CP0") 111 | :InStr(",LPWSTR,LPCWSTR,WCHAR,","," %_key_% ",")?"UTF-16":"CP0") 112 | :_default_[_key_] 113 | else { 114 | _this[_value_ N]:=_typevalid_?%_key_%:_default_[_key_] 115 | } 116 | } 117 | } 118 | 119 | ; Struct Contstructor 120 | ; Memory, offset and definitions are saved in following character + given key/name 121 | ; `a = Allocated Memory 122 | ; `b = Byte Offset (related to struct address) 123 | ; `f = Format (encoding for string data types) 124 | ; `n = New data type (AHK data type) 125 | ; `r = Is Pointer (requred for __GET and __SET) 126 | ; `t = Type (data type, also when it is name of a Structure it is used to resolve structure pointers dynamically 127 | ; `v = Memory used to save string and pointer memory 128 | __NEW(_TYPE_,_pointer_=0,_init_=0){ 129 | static _base_:={__GET:_Struct.___GET,__SET:_Struct.___SET,__SETPTR:_Struct.___SETPTR,__Clone:_Struct.___Clone,__NEW:_Struct.___NEW 130 | ,IsPointer:_Struct.IsPointer,Offset:_Struct.Offset,Type:_Struct.Type,AHKType:_Struct.AHKType,Encoding:_Struct.Encoding 131 | ,Capacity:_Struct.Capacity,Alloc:_Struct.Alloc,Size:_Struct.Size,SizeT:_Struct.SizeT,Print:_Struct.Print,ToObj:_Struct.ToObj} 132 | local _:="",_ArrType_:="",_ArrName_:="",_ArrSize_:=0,_align_total_:=0,_defobj_:="",_IsPtr_:=0,_key_:="",_LF_:="",_LF_BKP_:="",_match_:="",_offset_:="" 133 | ,_struct_:="",_StructSize_:=0,_total_union_size_:=0,_union_:=0,_union_size_:=0,_value_:="",_mod_:=0,_max_size_:=0,_in_struct_:=0,_struct_align_:=0 134 | 135 | If (RegExMatch(_TYPE_,"^[\w\d\._]+$") && !_Struct.HasKey(_TYPE_)){ ; structures name was supplied, resolve to global var and run again 136 | If InStr(_TYPE_,"."){ ;check for object that holds structure definition 137 | Loop,Parse,_TYPE_,. 138 | If A_Index=1 139 | _defobj_:=%A_LoopField% 140 | else _defobj_:=_defobj_[A_LoopField] 141 | _TYPE_:=_defobj_ 142 | } else _TYPE_:=%_TYPE_%,_defobj_:="" 143 | } else _defobj_:="" 144 | ; If a pointer is supplied, save it in key [""] else reserve and zero-fill memory + set pointer in key [""] 145 | If (_pointer_ && !IsObject(_pointer_)) 146 | this[""] := _pointer_,this["`a"]:=0,this["`a`a"]:=sizeof(_TYPE_) 147 | else 148 | this._SetCapacity("`a",_StructSize_:=sizeof(_TYPE_)) ; Set Capacity in key ["`a"] 149 | ,this[""]:=this._GetAddress("`a") ; Save pointer in key [""] 150 | ,DllCall("RtlZeroMemory","UPTR",this[""],"UInt",this["`a`a"]:=_StructSize_) ; zero-fill memory 151 | ; C/C++ style structure definition, convert it 152 | If InStr(_TYPE_,"`n") { 153 | _struct_:=[] ; keep track of structures (union is just removed because {} = union, struct{} = struct 154 | _union_:=0 ; init to 0, used to keep track of union depth 155 | Loop,Parse,_TYPE_,`n,`r`t%A_Space%%A_Tab% ; Parse each line 156 | { 157 | _LF_:="" 158 | Loop,Parse,A_LoopField,`,`;,`t%A_Space%%A_Tab% ; Parse each item 159 | { 160 | If RegExMatch(A_LoopField,"^\s*//") ;break on comments and continue main loop 161 | break 162 | If (A_LoopField){ ; skip empty lines 163 | If (!_LF_ && _ArrType_:=RegExMatch(A_LoopField,"[\w\d_#@]\s+[\w\d_#@]")) ; new line, find out data type and save key in _LF_ Data type will be added later 164 | _LF_:=RegExReplace(A_LoopField,"[\w\d_#@]\K\s+.*$") 165 | If Instr(A_LoopField,"{"){ ; Union, also check if it is a structure 166 | _union_++,_struct_.Insert(_union_,RegExMatch(A_LoopField,"i)^\s*struct\s*\{")) 167 | } else If InStr(A_LoopField,"}") ; end of union/struct 168 | _offset_.="}" 169 | else { ; not starting or ending struct or union so add definitions and apply Data Type. 170 | If _union_ ; add { or struct{ 171 | Loop % _union_ 172 | _ArrName_.=(_struct_[A_Index]?"struct":"") "{" 173 | _offset_.=(_offset_ ? "," : "") _ArrName_ ((_ArrType_ && A_Index!=1)?(_LF_ " "):"") RegExReplace(A_LoopField,"\s+"," ") 174 | ,_ArrName_:="",_union_:=0 175 | } 176 | } 177 | } 178 | } 179 | _TYPE_:=_offset_ 180 | } 181 | 182 | _offset_:=0 183 | ,_union_:=[] ; keep track of union level, required to reset offset after union is parsed 184 | ,_struct_:=[] ; for each union level keep track if it is a structure (because here offset needs to increase 185 | ,_union_size_:=[] ; keep track of highest member within the union or structure, used to calculate new offset after union 186 | ,_struct_align_:=[] ; keep track of alignment before structure 187 | ,_total_union_size_:=0 ; used in combination with above, each loop the total offset is updated if current data size is higher 188 | ,_align_total_:=0 ; used to calculate alignment for total size of structure 189 | ,_in_struct_:=1 190 | 191 | ,this["`t"]:=0,this["`r"]:=0 ; will identify a Structure Pointer without members 192 | 193 | ; Parse given structure definition and create struct members 194 | ; User structures will be resolved by recrusive calls (!!! a structure must be a global variable) 195 | Loop,Parse,_TYPE_,`,`; ;,%A_Space%%A_Tab%`n`r 196 | { 197 | _in_struct_+=StrLen(A_LoopField)+1 198 | If ("" = _LF_ := trim(A_LoopField,A_Space A_Tab "`n`r")) 199 | continue 200 | _LF_BKP_:=_LF_ ;to check for ending brackets = union,struct 201 | _IsPtr_:=0 202 | ; Check for STARTING union and set union helpers 203 | While (_match_:=RegExMatch(_LF_,"i)^(struct|union)?\s*\{\K")) 204 | ; correct offset for union/structure, sizeof_maxsize returns max size of union or structure 205 | _max_size_:=sizeof_maxsize(SubStr(_TYPE_,_in_struct_-StrLen(A_LoopField)-1+(StrLen(_LF_BKP_)-StrLen(_LF_)))) 206 | ,_union_.Insert(_offset_+=(_mod_:=Mod(_offset_,_max_size_))?Mod(_max_size_-_mod_,_max_size_):0) 207 | ,_union_size_.Insert(0) 208 | ,_struct_align_.Insert(_align_total_>_max_size_?_align_total_:_max_size_) 209 | ,_struct_.Insert(RegExMatch(_LF_,"i)^struct\s*\{")?(1,_align_total_:=0):0) 210 | ,_LF_:=SubStr(_LF_,_match_) 211 | 212 | StringReplace,_LF_,_LF_,},,A ;remove all closing brackets (these will be checked later) 213 | 214 | ; Check if item is a pointer and remove * for further processing, separate key will store that information 215 | While % (InStr(_LF_,"*")){ 216 | StringReplace,_LF_,_LF_,* 217 | _IsPtr_:=A_Index 218 | } 219 | ; Split off data type, name and size (only data type is mandatory) 220 | RegExMatch(_LF_,"^(?[\w\d\._]+)?\s*(?[\w\d_]+)?\s*\[?(?\d+)?\]?\s*\}*\s*$",_) 221 | If (!_ArrName_ && !_ArrSize_){ 222 | If RegExMatch(_TYPE_,"^\**" _ArrType_ "\**$"){ 223 | _Struct.___InitField(this,"",0,_ArrType_,_IsPtr_?"PTR":_Struct.HasKey("_" _ArrType_)?_Struct["_" _ArrType_]:"PTR",_IsPtr_,_ArrType_) 224 | this.base:=_base_ 225 | If (IsObject(_init_)||IsObject(_pointer_)){ ; Initialization of structures members, e.g. _Struct(_RECT,{left:10,right:20}) 226 | for _key_,_value_ in IsObject(_init_)?_init_:_pointer_ 227 | { 228 | If !this["`r"]{ ; It is not a pointer, assign value 229 | If InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR,","," this["`t" _key_] ",") 230 | this.Alloc(_key_,StrLen(_value_)*(InStr(".LPWSTR,LPCWSTR,","," this["`t"] ",")||(InStr(",LPTSTR,LPCTSTR,","," this["`t" _key_] ",")&&A_IsUnicode)?2:1)) 231 | if InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR,CHAR,TCHAR,WCHAR,","," this["`t" _key_] ",") 232 | this[_key_]:=_value_ 233 | else 234 | this[_key_] := _value_ 235 | }else if (_value_<>"") ; It is not empty 236 | If _value_ is integer ; It is a new pointer 237 | this[_key_][""]:=_value_ 238 | } 239 | } 240 | Return this ;:= new _Struct(%_ArrType_%,_pointer_) ;only Data type was supplied, object/structure has got no members/keys 241 | } else 242 | _ArrName_:=_ArrType_,_ArrType_:="UInt" 243 | } 244 | If InStr(_ArrType_,"."){ ;check for object that holds structure definition 245 | Loop,Parse,_ArrType_,. 246 | If A_Index=1 247 | _defobj_:=%A_LoopField% 248 | else _defobj_:=_defobj_[A_LoopField] 249 | } 250 | if (!_IsPtr_ && !_Struct.HasKey(_ArrType_)){ ; _ArrType_ not found resolve to global variable (must contain struct definition) 251 | if (sizeof(_defobj_?_defobj_:%_ArrType_%,0,_align_total_) && mod:=Mod(_offset_,_align_total_)) 252 | _offset_+=Mod(_align_total_-_mod_,_align_total_) 253 | _Struct.___InitField(this,_ArrName_,_offset_,_ArrType_,0,0,_ArrType_,_ArrSize_) 254 | ; update current union size 255 | If (_uix_:=_union_.MaxIndex()) && (_max_size_:=_offset_ + sizeof(_defobj_?_defobj_:%_ArrType_%) - _union_[_uix_])>_union_size_[_uix_] 256 | _union_size_[_uix_]:=_max_size_ 257 | _max_size:=0 258 | ; if not a union or a union + structure then offset must be moved (when structure offset will be reset below 259 | If (!_uix_||_struct_[_struct_.MaxIndex()]) 260 | _offset_+=this[" " _ArrName_]*sizeof(_defobj_?_defobj_:%_ArrType_%) ; move offset 261 | ;Continue 262 | } else { 263 | If ((_IsPtr_ || _Struct.HasKey(_ArrType_))) 264 | _offset_+=(_mod_:=Mod(_offset_,_max_size_:=_IsPtr_?A_PtrSize:_Struct[_ArrType_]))=0?0:(_IsPtr_?A_PtrSize:_Struct[_ArrType_])-_mod_ 265 | ,_align_total_:=_max_size_>_align_total_?_max_size_:_align_total_ 266 | ,_Struct.___InitField(this,_ArrName_,_offset_,_ArrType_,_IsPtr_?"PTR":_Struct.HasKey(_ArrType_)?_Struct["_" _ArrType_]:_ArrType_,_IsPtr_,_ArrType_,_ArrSize_) 267 | ; update current union size 268 | If (_uix_:=_union_.MaxIndex()) && (_max_size_:=_offset_ + _Struct[this["`n" _ArrName_]] - _union_[_uix_])>_union_size_[_uix_] 269 | _union_size_[_uix_]:=_max_size_ 270 | _max_size_:=0 271 | ; if not a union or a union + structure then offset must be moved (when structure offset will be reset below 272 | If (!_uix_||_struct_[_uix_]) 273 | _offset_+=_IsPtr_?A_PtrSize:(_Struct.HasKey(_ArrType_)?_Struct[_ArrType_]:%_ArrType_%)*this[" " _ArrName_] 274 | } 275 | ; Check for ENDING union and reset offset and union helpers 276 | While (SubStr(_LF_BKP_,0)="}"){ 277 | If (!_uix_:=_union_.MaxIndex()){ 278 | MsgBox,0, Incorrect structure, missing opening braket {`nProgram will exit now `n%_TYPE_% 279 | ExitApp 280 | } ; Increase total size of union/structure if necessary 281 | ; reset offset and align because we left a union or structure 282 | if (_uix_>1 && _struct_[_uix_-1]){ 283 | if (_mod_:=Mod(_offset_,_struct_align_[_uix_])) 284 | _offset_+=Mod(_struct_align_[_uix_]-_mod_,_struct_align_[_uix_]) 285 | } else _offset_:=_union_[_uix_] 286 | if (_struct_[_uix_]&&_struct_align_[_uix_]>_align_total_) 287 | _align_total_ := _struct_align_[_uix_] 288 | ; Increase total size of union/structure if necessary 289 | _total_union_size_ := _union_size_[_uix_]>_total_union_size_?_union_size_[_uix_]:_total_union_size_ 290 | ,_union_._Remove(),_struct_._Remove(),_union_size_._Remove(),_struct_align_.Remove(),_LF_BKP_:=SubStr(_LF_BKP_,1,StrLen(_LF_BKP_)-1) ; remove latest items 291 | If (_uix_=1){ ; leaving top union, add offset 292 | if (_mod_:=Mod(_total_union_size_,_align_total_)) 293 | _total_union_size_ += Mod(_align_total_-_mod_,_align_total_) 294 | _offset_+=_total_union_size_,_total_union_size_:=0 295 | } 296 | } 297 | } 298 | this.base:=_base_ ; apply new base which uses below functions and uses ___GET for __GET and ___SET for __SET 299 | If (IsObject(_init_)||IsObject(_pointer_)){ ; Initialization of structures members, e.g. _Struct(_RECT,{left:10,right:20}) 300 | for _key_,_value_ in IsObject(_init_)?_init_:_pointer_ 301 | { 302 | If !this["`r" _key_]{ ; It is not a pointer, assign value 303 | If InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR,","," this["`t" _key_] ",") 304 | this.Alloc(_key_,StrLen(_value_)*(InStr(".LPWSTR,LPCWSTR,","," this["`t"] ",")||(InStr(",LPTSTR,LPCTSTR,","," this["`t" _key_] ",")&&A_IsUnicode)?2:1)) 305 | if InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR,CHAR,TCHAR,WCHAR,","," this["`t" _key_] ",") 306 | this[_key_]:=_value_ 307 | else 308 | this[_key_] := _value_ 309 | }else if (_value_<>"") ; It is not empty 310 | if _value_ is integer ; It is a new pointer 311 | this[_key_][""]:=_value_ 312 | } 313 | } 314 | Return this 315 | } 316 | ToObj(struct:=""){ 317 | obj:=[] 318 | for k,v in struct?struct:struct:=this 319 | if (Asc(k)=10) 320 | If IsObject(_VALUE_:=struct[_TYPE_:=SubStr(k,2)]) 321 | obj[_TYPE_]:=this.ToObj(_VALUE_) 322 | else obj[_TYPE_]:=_VALUE_ 323 | return obj 324 | } 325 | SizeT(_key_=""){ 326 | return sizeof(this["`t" _key_]) 327 | } 328 | Size(){ 329 | return sizeof(this) 330 | } 331 | IsPointer(_key_=""){ 332 | return this["`r" _key_] 333 | } 334 | Type(_key_=""){ 335 | return this["`t" _key_] 336 | } 337 | AHKType(_key_=""){ 338 | return this["`n" _key_] 339 | } 340 | Offset(_key_=""){ 341 | return this["`b" _key_] 342 | } 343 | Encoding(_key_=""){ 344 | return this["`b" _key_] 345 | } 346 | Capacity(_key_=""){ 347 | return this._GetCapacity("`v" _key_) 348 | } 349 | Alloc(_key_="",size="",ptrsize=0){ 350 | If _key_ is integer 351 | ptrsize:=size,size:=_key_,_key_:="" 352 | If size is integer 353 | SizeIsInt:=1 354 | If ptrsize { 355 | If (this._SetCapacity("`v" _key_,!SizeIsInt?A_PtrSize+ptrsize:size + (size//A_PtrSize)*ptrsize)="") 356 | MsgBox % "Memory for pointer ." _key_ ". of size " (SizeIsInt?size:A_PtrSize) " could not be set!" 357 | else { 358 | DllCall("RtlZeroMemory","UPTR",this._GetAddress("`v" _key_),"UInt",this._GetCapacity("`v" _key_)) 359 | If (this[" " _key_]>1){ 360 | ptr:=this[""] + this["`b" _key_] 361 | If (this["`r" _key_] || InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR,","," this["`t" _key_] ",")) 362 | NumPut(ptrs:=this._GetAddress("`v" _key_),ptr+0,"PTR") 363 | else if _key_ 364 | this[_key_,""]:=ptrs:=this._GetAddress("`v" _key_) 365 | else this[""]:=ptr:=this._GetAddress("`v" _key_),ptrs:=this._GetAddress("`v" _key_)+(SizeIsInt?size:A_PtrSize) 366 | } else { 367 | If (this["`r" _key_] || InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR,","," this["`t" _key_] ",")) 368 | NumPut(ptr:=this._GetAddress("`v" _key_),this[""] + this["`b" _key_],"PTR") 369 | else this[""]:=ptr:=this._GetAddress("`v" _key_) 370 | ptrs:=ptr+(size?size:A_PtrSize) 371 | } 372 | Loop % SizeIsInt?(size//A_PtrSize):1 373 | NumPut(ptrs+(A_Index-1)*ptrsize,ptr+(A_Index-1)*A_PtrSize,"PTR") 374 | } 375 | } else { 376 | If (this._SetCapacity("`v" _key_,SizeIsInt?size:A_PtrSize)=""){ 377 | MsgBox % "Memory for pointer ." _key_ ". of size " (SizeIsInt?size:A_PtrSize) " could not be set!" 378 | } else 379 | NumPut(ptr:=this._GetAddress("`v" _key_),this[""] + this["`b" _key_],"PTR"),DllCall("RtlZeroMemory","UPTR",ptr,"UInt",SizeIsInt?size:A_PtrSize) 380 | } 381 | return ptr 382 | } 383 | ___NEW(init*){ 384 | this:=this.base 385 | newobj := this.__Clone(1) ;clone structure and keep pointer (1), it will be changed below 386 | If (init.MaxIndex() && !IsObject(init.1)) 387 | newobj[""] := init.1 388 | else If (init.MaxIndex()>1 && !IsObject(init.2)) 389 | newobj[""] := init.2 390 | else 391 | newobj._SetCapacity("`a",_StructSize_:=sizeof(this)) ; Set Capacity in key ["`a"] 392 | ,newobj[""]:=newobj._GetAddress("`a") ; Save pointer in key [""] 393 | ,DllCall("RtlZeroMemory","UPTR",newobj[""],"UInt",_StructSize_) ; zero-fill memory 394 | If (IsObject(init.1)||IsObject(init.2)) 395 | for _key_,_value_ in IsObject(init.1)?init.1:init.2 396 | newobj[_key_] := _value_ 397 | return newobj 398 | } 399 | 400 | ; Clone structure and move pointer for new structure 401 | ___Clone(offset){ 402 | static _base_:={__GET:_Struct.___GET,__SET:_Struct.___SET,__SETPTR:_Struct.___SETPTR,__Clone:_Struct.___Clone,__NEW:_Struct.___NEW 403 | ,IsPointer:_Struct.IsPointer,Offset:_Struct.Offset,Type:_Struct.Type,AHKType:_Struct.AHKType,Encoding:_Struct.Encoding 404 | ,Capacity:_Struct.Capacity,Alloc:_Struct.Alloc,Size:_Struct.Size,SizeT:_Struct.SizeT,Print:_Struct.Print,ToObj:_Struct.ToObj} 405 | If offset=1 406 | return this 407 | newobj:={} ; new structure object 408 | for _key_,_value_ in this ; copy all values/objects 409 | If (_key_!="`a") 410 | newobj[_key_]:=_value_ ; add key to new object and assign value 411 | newobj._SetCapacity("`a",_StructSize_:=sizeof(this)) ; Set Capacity in key ["`a"] 412 | ,newobj[""]:=newobj._GetAddress("`a") ; Save pointer in key [""] 413 | ,DllCall("RtlZeroMemory","UPTR",newobj[""],"UInt",_StructSize_) ; zero-fill memory 414 | If this["`r"]{ ; its a pointer so we need too move internal memory 415 | NumPut(NumGet(this[""],"PTR")+A_PtrSize*(offset-1),newobj[""],"Ptr") 416 | newobj.base:=_base_ ;assign base of _Struct 417 | } else ; do not use internal memory, simply assign new pointer to new structure 418 | newobj.base:=_base_,newobj[]:=this[""]+sizeof(this)*(offset-1) 419 | return newobj ; return new object 420 | } 421 | ___GET(_key_="",p*){ 422 | If (_key_="") ; Key was not given so structure[] has been called, return pointer to structure 423 | Return this[""] 424 | else if !(idx:=p.MaxIndex()) 425 | _field_:=_key_,opt:="~" 426 | else { 427 | ObjInsert(p,1,_key_) 428 | opt:=ObjRemove(p),_field_:=_key_:=ObjRemove(p) 429 | for key_,value_ in p 430 | this:=this[value_] 431 | } 432 | If this["`t"] ; structure without keys/members 433 | _key_:="" ; set _key_ empty so items below will resolve to our structure 434 | If (opt!="~"){ 435 | If (opt=""){ 436 | If _field_ is integer 437 | return (this["`r"]?NumGet(this[""],"PTR"):this[""])+sizeof(this["`t"])*(_field_-1) 438 | else return this["`r" _key_]?NumGet(this[""]+this["`b" _key_],"PTR"):this[""]+this["`b" _key_] ;+sizeof(this["`t" _key_])*(_field_-1) 439 | } else If opt is integer 440 | { ;offset to a item e.g. struct.a[100] ("Uint a[100]") 441 | ; MsgBox % "ja " 442 | If (_Struct.HasKey("_" this["`t" _key_]) && this[" " _key_]>1) { 443 | If (InStr( ",CHAR,UCHAR,TCHAR,WCHAR," , "," this["`t" _key_] "," )){ ; StrGet 1 character only 444 | Return StrGet(this[""]+this["`b" _key_]+(opt-1)*sizeof(this["`t" _key_]),1,this["`f" _key_]) 445 | } else if InStr( ",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR," , "," this["`t" _key_] "," ){ ; StrGet string 446 | Return StrGet(NumGet(this[""]+this["`b" _key_]+(opt-1)*A_PtrSize,"PTR"),this["`f" _key_]) 447 | } else { 448 | Return NumGet(this[""]+this["`b" _key_]+(opt-1)*sizeof(this["`t" _key_]),this["`n" _key_]) 449 | } 450 | } else Return new _Struct(this["`t" _key_],this[""]+this["`b" _key_]+(opt-1)*sizeof(this["`t" _key_])) 451 | } else 452 | return this[_key_][opt] 453 | } else If _field_ is integer 454 | { ; array access (must be listed first because otherwise this["`r" _key_] cannot be resolved 455 | If (_key_){ ; Offset for item 456 | return this.__Clone(_field_) 457 | } else if this["`r"] { 458 | Pointer:="" 459 | Loop % (this["`r"]-1) ; dip into one step and return a new structure 460 | pointer.="*" 461 | If pointer 462 | Return new _Struct(pointer this["`t"],NumGet(this[""],"PTR")+A_PtrSize*(_field_-1)) 463 | else Return new _Struct(pointer this["`t"],NumGet(this[""],"PTR")+sizeof(this["`t"])*(_field_-1)).1 464 | } else if _Struct.HasKey("_" this["`t"]) { 465 | ; If this[" "] 466 | ; Return new _Struct(this["`t"],this[""]) 467 | ; else 468 | If (InStr( ",CHAR,UCHAR,TCHAR,WCHAR," , "," this["`t"] "," )){ ; StrGet 1 character only 469 | Return StrGet(this[""]+sizeof(this["`t"])*(_field_-1),1,this["`f"]) 470 | } else if InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR," , "," this["`t"] "," ){ ; StrGet string 471 | Return StrGet(NumGet(this[""]+A_PtrSize*(_field_-1),"PTR"),this["`f"]) 472 | } else { ; resolve pointer 473 | Return NumGet(this[""]+sizeof(this["`t"])*(_field_-1),this["`n"]) 474 | } 475 | } else { 476 | 477 | ; return this.__Clone(_field_) 478 | ; listVars 479 | ; MsgBox % this[""] "+" sizeof(this["`t"])*(_field_-1) "-" this["`t"] 480 | Return new _Struct(this["`t"],this[""]+sizeof(this["`t"])*(_field_-1)) 481 | } 482 | } else If this["`r" _key_] { ;pointer 483 | Pointer:="" 484 | Loop % (this["`r" _key_]-1) ; dip into one step and return a new structure 485 | pointer.="*" 486 | If (_key_=""){ 487 | return this[1][_field_] 488 | } else { 489 | Return new _Struct(pointer this["`t" _key_],NumGet(this[""]+this["`b" _key_],"PTR")) 490 | } 491 | } else if _Struct.HasKey("_" this["`t" _key_]) { ; default data type, not pointer 492 | If (this[" " _key_]>1) 493 | Return new _Struct(this["`t" _key_],this[""] + this["`b" _key_]) 494 | else If (InStr( ",CHAR,UCHAR,TCHAR,WCHAR," , "," this["`t" _key_] "," )){ ; StrGet 1 character only 495 | Return StrGet(this[""]+this["`b" _key_],1,this["`f" _key_]) 496 | } else if InStr( ",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR," , "," this["`t" _key_] "," ){ ; StrGet string 497 | Return StrGet(NumGet(this[""]+this["`b" _key_],"PTR"),this["`f" _key_]) 498 | } else { 499 | Return NumGet(this[""]+this["`b" _key_],this["`n" _key_]) 500 | } 501 | } else { ; the field is a non pointer structure 502 | Return new _Struct(this["`t" _key_],this[""]+this["`b" _key_]) 503 | } 504 | } 505 | ___SET(_key_,p*){ ;="",_value_=-0x8000000000000000 ,opt="~"){ 506 | If !(idx:=p.MaxIndex()) ; Set new Pointer, here a value was assigned e.g. struct[]:=&var 507 | return this[""] :=_key_,this._SetCapacity("`a",0) ; free internal memory, it will not be used anymore 508 | else if (idx=1) 509 | _value_:=p.1,opt:="~" 510 | else if (idx>1){ 511 | ObjInsert(p,1,_key_) 512 | If (p[idx]="") 513 | opt:=ObjRemove(p),_value_:=ObjRemove(p),_key_:=ObjRemove(p) 514 | else _value_:=ObjRemove(p),_key_:=ObjRemove(p),opt:="~" 515 | for key_,value_ in p 516 | this:=this[value_] 517 | } 518 | If this["`t"] ; structure without members 519 | _field_:=_key_,_key_:="" ; set _key_ empty so it will resolve to our structure 520 | else _field_:=_key_ 521 | If this["`r" _key_] { ; Pointer 522 | If opt is integer 523 | return NumPut(opt,this[""] + this["`b" _key_],"PTR") 524 | else if this.HasKey("`t" _key_) { 525 | Pointer:="" 526 | Loop % (this["`r" _key_]-1) ; dip into one step and return a new structure 527 | pointer.="*" 528 | If _key_ 529 | Return (new _Struct(pointer this["`t" _key_],NumGet(this[""] + this["`b" _key_],"PTR"))).1:=_value_ 530 | else Return (new _Struct(pointer this["`t"],NumGet(this[""],"PTR")))[_field_]:=_value_ 531 | } else If _field_ is Integer 532 | if (_key_="") ; replace this for the operation 533 | _this:=this,this:=this.__Clone(_Field_) 534 | If InStr( ",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR," , "," this["`t" _key_] "," ) 535 | StrPut(_value_,NumGet(NumGet(this[""]+this["`b" _key_],"PTR"),"PTR"),this["`f" _key_]) ; StrPut char to addr+A_PtrSize 536 | else if InStr( ",TCHAR,CHAR,UCHAR,WCHAR," , "," this["`t" _key_] "," ){ ; same as above but for 1 Character only 537 | StrPut(_value_,NumGet(this[""]+this["`b" _key_],"PTR"),this["`f" _key_]) ; StrPut char to addr 538 | } else 539 | NumPut(_value_,NumGet(this[""]+this["`b" _key_],"PTR"),this["`n" _key_]) 540 | If _field_ is integer ; restore this after operation 541 | this:=_this 542 | } else if (RegExMatch(_field_,"^\d+$") && _key_="") { 543 | if InStr( ",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR," , "," this["`t"] "," ){ 544 | StrPut(_value_,NumGet(this[""]+A_PtrSize*(_field_-1),"PTR"),this["`f"]) ; StrPut string to addr 545 | } else if InStr( ",TCHAR,CHAR,UCHAR,WCHAR," , "," this["`t" _key_] "," ){ 546 | StrPut(_value_,this[""] + sizeof(this["`t"])*(_field_-1),this["`f"]) 547 | } else 548 | NumPut(_value_,this[""] + sizeof(this["`t"])*(_field_-1),this["`n"]) ; NumPut new value to key 549 | } else if opt is integer 550 | { 551 | return NumPut(opt,this[""] + this["`b" _key_],"PTR") 552 | } else if InStr( ",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR," , "," this["`t" _key_] "," ){ 553 | StrPut(_value_,NumGet(this[""] + this["`b" _key_],"PTR"),this["`f" _key_]) ; StrPut string to addr 554 | } else if InStr( ",TCHAR,CHAR,UCHAR,WCHAR," , "," this["`t" _key_] "," ){ 555 | StrPut(_value_,this[""] + this["`b" _key_],this["`f" _key_]) ; StrPut character key 556 | } else 557 | NumPut(_value_,this[""]+this["`b" _key_],this["`n" _key_]) ; NumPut new value to key 558 | Return _value_ 559 | } 560 | } -------------------------------------------------------------------------------- /sizeof.ahk: -------------------------------------------------------------------------------- 1 | ;: Title: sizeof function by HotKeyIt 2 | ; 3 | 4 | ; Function: sizeof 5 | ; Description: 6 | ; sizeof() is based on AHK_L Objects and supports both, ANSI and UNICODE version, so to use it you will require Lexikos AutoHotkey_L.exe or other versions based on it that supports objects.

nsizeof is used to calculate the size of structures or data types.
Visit sizeof at AutoHotkey forum, any feedback is welcome. 7 | ; Syntax: size:= sizeof(Structure_Definition or Structure_Object) 8 | ; Parameters: 9 | ; Field types - All AutoHotkey and Windows Data Types are supported
AutoHotkey Data Types
Int, Uint, Int64, UInt64, Char, UChar, Short, UShort, Fload and Double.
Windows Data Types
- note, TCHAR UCHAR and CHAR return actual character rather than the value, use Asc() function to find out the value/code
Windows Data types: Asc(char)
ATOM,BOOL,BOOLEAN,BYTE,CHAR,COLORREF,DWORD,DWORDLONG,DWORD_PTR,
DWORD32,DWORD64,FLOAT,HACCEL,HALF_PTR,HANDLE,HBITMAP,HBRUSH,HCOLORSPACE,HCONV,HCONVLIST,HCURSOR,HDC,
HDDEDATA,HDESK,HDROP,HDWP,HENHMETAFILE,HFILE,HFONT,HGDIOBJ,HGLOBAL,HHOOK,HICON,HINSTANCE,HKEY,HKL,
HLOCAL,HMENU,HMETAFILE,HMODULE,HMONITOR,HPALETTE,HPEN,HRESULT,HRGN,HRSRC,HSZ,HWINSTA,HWND,INT,
INT_PTR,INT32,INT64,LANGID,LCID,LCTYPE,LGRPID,LONG,LONGLONG,LONG_PTR,LONG32,LONG64,LPARAM,LPBOOL,
LPBYTE,LPCOLORREF,LPCSTR,LPCTSTR,LPCVOID,LPCWSTR,LPDWORD,LPHANDLE,LPINT,LPLONG,LPSTR,LPTSTR,LPVOID,
LPWORD,LPWSTR,LRESULT,PBOOL,PBOOLEAN,PBYTE,PCHAR,PCSTR,PCTSTR,PCWSTR,PDWORD,PDWORDLONG,PDWORD_PTR,
PDWORD32,PDWORD64,PFLOAT,PHALF_PTR,PHANDLE,PHKEY,PINT,PINT_PTR,PINT32,PINT64,PLCID,PLONG,PLONGLONG,
PLONG_PTR,PLONG32,PLONG64,POINTER_32,POINTER_64,POINTER_SIGNED,POINTER_UNSIGNED,PSHORT,PSIZE_T,
PSSIZE_T,PSTR,PTBYTE,PTCHAR,PTSTR,PUCHAR,PUHALF_PTR,PUINT,PUINT_PTR,PUINT32,PUINT64,PULONG,PULONGLONG,
PULONG_PTR,PULONG32,PULONG64,PUSHORT,PVOID,PWCHAR,PWORD,PWSTR,SC_HANDLE,SC_LOCK,SERVICE_STATUS_HANDLE,
SHORT,SIZE_T,SSIZE_T,TBYTE,TCHAR,UCHAR,UHALF_PTR,UINT,UINT_PTR,UINT32,UINT64,ULONG,ULONGLONG,
ULONG_PTR,ULONG32,ULONG64,USHORT,USN,WCHAR,WORD,WPARAM 10 | ; Parameters - Description 11 | ; size - The size of structure or data type 12 | ; Structure_Definition - C/C++ syntax or usual definition (must not be multiline) e.g. "Int x,Int y", C/C++ definitions must be multiline. 13 | ; Return Value: 14 | ; sizeof returns size of structures or data types 15 | ; Remarks: 16 | ; None. 17 | ; Related: 18 | ; Example: 19 | ; file: 20 | 21 | sizeof(_TYPE_,parent_offset=0,ByRef _align_total_=0){ 22 | ;Windows and AHK Data Types, used to find out the corresponding size 23 | static _types__:=" 24 | (LTrim Join 25 | ,ATOM:2,LANGID:2,WCHAR:2,WORD:2,PTR:" A_PtrSize ",UPTR:" A_PtrSize ",SHORT:2,USHORT:2,INT:4,UINT:4,INT64:8,UINT64:8,DOUBLE:8,FLOAT:4,CHAR:1,UCHAR:1,__int64:8 26 | ,TBYTE:" (A_IsUnicode?2:1) ",TCHAR:" (A_IsUnicode?2:1) ",HALF_PTR:" (A_PtrSize=8?4:2) ",UHALF_PTR:" (A_PtrSize=8?4:2) ",INT32:4,LONG:4,LONG32:4,LONGLONG:8 27 | ,LONG64:8,USN:8,HFILE:4,HRESULT:4,INT_PTR:" A_PtrSize ",LONG_PTR:" A_PtrSize ",POINTER_64:" A_PtrSize ",POINTER_SIGNED:" A_PtrSize " 28 | ,BOOL:4,SSIZE_T:" A_PtrSize ",WPARAM:" A_PtrSize ",BOOLEAN:1,BYTE:1,COLORREF:4,DWORD:4,DWORD32:4,LCID:4,LCTYPE:4,LGRPID:4,LRESULT:4,PBOOL:" A_PtrSize " 29 | ,PBOOLEAN:" A_PtrSize ",PBYTE:" A_PtrSize ",PCHAR:" A_PtrSize ",PCSTR:" A_PtrSize ",PCTSTR:" A_PtrSize ",PCWSTR:" A_PtrSize ",PDWORD:" A_PtrSize " 30 | ,PDWORDLONG:" A_PtrSize ",PDWORD_PTR:" A_PtrSize ",PDWORD32:" A_PtrSize ",PDWORD64:" A_PtrSize ",PFLOAT:" A_PtrSize ",PHALF_PTR:" A_PtrSize " 31 | ,UINT32:4,ULONG:4,ULONG32:4,DWORDLONG:8,DWORD64:8,ULONGLONG:8,ULONG64:8,DWORD_PTR:" A_PtrSize ",HACCEL:" A_PtrSize ",HANDLE:" A_PtrSize " 32 | ,HBITMAP:" A_PtrSize ",HBRUSH:" A_PtrSize ",HCOLORSPACE:" A_PtrSize ",HCONV:" A_PtrSize ",HCONVLIST:" A_PtrSize ",HCURSOR:" A_PtrSize ",HDC:" A_PtrSize " 33 | ,HDDEDATA:" A_PtrSize ",HDESK:" A_PtrSize ",HDROP:" A_PtrSize ",HDWP:" A_PtrSize ",HENHMETAFILE:" A_PtrSize ",HFONT:" A_PtrSize ",USAGE:" 2 " 34 | )" 35 | static _types_:=_types__ " 36 | (LTrim Join 37 | ,HGDIOBJ:" A_PtrSize ",HGLOBAL:" A_PtrSize ",HHOOK:" A_PtrSize ",HICON:" A_PtrSize ",HINSTANCE:" A_PtrSize ",HKEY:" A_PtrSize ",HKL:" A_PtrSize " 38 | ,HLOCAL:" A_PtrSize ",HMENU:" A_PtrSize ",HMETAFILE:" A_PtrSize ",HMODULE:" A_PtrSize ",HMONITOR:" A_PtrSize ",HPALETTE:" A_PtrSize ",HPEN:" A_PtrSize " 39 | ,HRGN:" A_PtrSize ",HRSRC:" A_PtrSize ",HSZ:" A_PtrSize ",HWINSTA:" A_PtrSize ",HWND:" A_PtrSize ",LPARAM:" A_PtrSize ",LPBOOL:" A_PtrSize ",LPBYTE:" A_PtrSize " 40 | ,LPCOLORREF:" A_PtrSize ",LPCSTR:" A_PtrSize ",LPCTSTR:" A_PtrSize ",LPCVOID:" A_PtrSize ",LPCWSTR:" A_PtrSize ",LPDWORD:" A_PtrSize ",LPHANDLE:" A_PtrSize " 41 | ,LPINT:" A_PtrSize ",LPLONG:" A_PtrSize ",LPSTR:" A_PtrSize ",LPTSTR:" A_PtrSize ",LPVOID:" A_PtrSize ",LPWORD:" A_PtrSize ",LPWSTR:" A_PtrSize " 42 | ,PHANDLE:" A_PtrSize ",PHKEY:" A_PtrSize ",PINT:" A_PtrSize ",PINT_PTR:" A_PtrSize ",PINT32:" A_PtrSize ",PINT64:" A_PtrSize ",PLCID:" A_PtrSize " 43 | ,PLONG:" A_PtrSize ",PLONGLONG:" A_PtrSize ",PLONG_PTR:" A_PtrSize ",PLONG32:" A_PtrSize ",PLONG64:" A_PtrSize ",POINTER_32:" A_PtrSize " 44 | ,POINTER_UNSIGNED:" A_PtrSize ",PSHORT:" A_PtrSize ",PSIZE_T:" A_PtrSize ",PSSIZE_T:" A_PtrSize ",PSTR:" A_PtrSize ",PTBYTE:" A_PtrSize " 45 | ,PTCHAR:" A_PtrSize ",PTSTR:" A_PtrSize ",PUCHAR:" A_PtrSize ",PUHALF_PTR:" A_PtrSize ",PUINT:" A_PtrSize ",PUINT_PTR:" A_PtrSize " 46 | ,PUINT32:" A_PtrSize ",PUINT64:" A_PtrSize ",PULONG:" A_PtrSize ",PULONGLONG:" A_PtrSize ",PULONG_PTR:" A_PtrSize ",PULONG32:" A_PtrSize " 47 | ,PULONG64:" A_PtrSize ",PUSHORT:" A_PtrSize ",PVOID:" A_PtrSize ",PWCHAR:" A_PtrSize ",PWORD:" A_PtrSize ",PWSTR:" A_PtrSize ",SC_HANDLE:" A_PtrSize " 48 | ,SC_LOCK:" A_PtrSize ",SERVICE_STATUS_HANDLE:" A_PtrSize ",SIZE_T:" A_PtrSize ",UINT_PTR:" A_PtrSize ",ULONG_PTR:" A_PtrSize ",VOID:" A_PtrSize " 49 | )" 50 | local _:="",_ArrName_:="",_ArrType_:="",_ArrSize_:=0,_defobj_:="",_idx_:=0,_LF_:="",_LF_BKP_:="",_match_:="",_offset_:=0,_padding_:=0,_struct_:="" 51 | ,_total_union_size_:=0,_uix_:=0,_union_:=0,_union_size_:=0,_in_struct_:=0,_mod_:=0,_max_size_:=0,_struct_align_:=0 52 | _offset_:=parent_offset ; Init size/offset to 0 or parent_offset 53 | 54 | If IsObject(_TYPE_){ ; If structure object - check for offset in structure and return pointer + last offset + its data size 55 | return _TYPE_["`a`a"] 56 | } 57 | 58 | If RegExMatch(_TYPE_,"^[\w\d\._]+$"){ ; structures name was supplied, resolve to global var and run again 59 | If InStr(_types_,"," _TYPE_ ":") 60 | Return SubStr(_types_,InStr(_types_,"," _TYPE_ ":") + 2 + StrLen(_TYPE_),1) 61 | else If InStr(_TYPE_,"."){ ;check for object that holds structure definition 62 | Loop,Parse,_TYPE_,. 63 | If A_Index=1 64 | _defobj_:=%A_LoopField% 65 | else _defobj_:=_defobj_[A_LoopField] 66 | Return sizeof(_defobj_,parent_offset) 67 | } else Return sizeof(%_TYPE_%,parent_offset) 68 | } else _defobj_:="" 69 | If InStr(_TYPE_,"`n") { ; C/C++ style definition, convert 70 | _offset_:="" ; This will hold new structure 71 | ,_struct_:=[] ; This will keep track if union is structure 72 | ,_union_:=0 ; This will keep track of union depth 73 | Loop,Parse,_TYPE_,`n,`r`t%A_Space%%A_Tab% 74 | { 75 | _LF_:="" 76 | Loop,Parse,A_LoopField,`,`;,`t%A_Space%%A_Tab% 77 | { 78 | If RegExMatch(A_LoopField,"^\s*//") ;break on comments and continue main loop 79 | break 80 | If (A_LoopField){ ; skip empty lines 81 | If (!_LF_ && _ArrType_:=RegExMatch(A_LoopField,"[\w\d_#@]\s+[\w\d_#@]")) ; new line, find out data type and save key in _LF_ Data type will be added later 82 | _LF_:=RegExReplace(A_LoopField,"[\w\d_#@]\K\s+.*$") 83 | If Instr(A_LoopField,"{"){ ; Union, also check if it is a structure 84 | _union_++,_struct_.Insert(_union_,RegExMatch(A_LoopField,"i)^\s*struct\s*\{")) 85 | } else If InStr(A_LoopField,"}") ; end of union/struct 86 | _offset_.="}" 87 | else { ; not starting or ending struct or union so add definitions and apply Data Type. 88 | If _union_ ; add { or struct{ 89 | Loop % _union_ 90 | _ArrName_.=(_struct_[A_Index]?"struct":"") "{" 91 | _offset_.=(_offset_ ? "," : "") _ArrName_ ((_ArrType_ && A_Index!=1)?(_LF_ " "):"") RegExReplace(A_LoopField,"\s+"," ") 92 | ,_ArrName_:="",_union_:=0 93 | } 94 | } 95 | } 96 | } 97 | _TYPE_:=_offset_ 98 | ,_offset_:=parent_offset ; Init size/offset to 0 or parent_offset 99 | } 100 | 101 | ; Following keep track of union size/offset 102 | _union_:=[] ; keep track of union level, required to reset offset after union is parsed 103 | ,_struct_:=[] ; for each union level keep track if it is a structure (because here offset needs to increase 104 | ,_union_size_:=[] ; keep track of highest member within the union or structure, used to calculate new offset after union 105 | ,_struct_align_:=[] ; keep track of alignment before structure 106 | ,_total_union_size_:=0 ; used in combination with above, each loop the total offset is updated if current data size is higher 107 | ;,_align_total_:=0 ; used to calculate alignment for total size of structure 108 | ,_in_struct_:=1 109 | ; Parse given structure definition and calculate size 110 | ; Structures will be resolved by recrusive calls (a structure must be global) 111 | Loop,Parse,_TYPE_,`,`; ;,%A_Space%%A_Tab%`n`r 112 | { 113 | _in_struct_+=StrLen(A_LoopField)+1 114 | If ("" = _LF_ := trim(A_LoopField,A_Space A_Tab "`n`r")) 115 | continue 116 | _LF_BKP_:=_LF_ ;to check for ending brackets = union,struct 117 | ; Check for STARTING union and set union helpers 118 | While (_match_:=RegExMatch(_LF_,"i)^(struct|union)?\s*\{\K")) 119 | ; correct offset for union/structure, sizeof_maxsize returns max size of union or structure 120 | _max_size_:=sizeof_maxsize(SubStr(_TYPE_,_in_struct_-StrLen(A_LoopField)-1+(StrLen(_LF_BKP_)-StrLen(_LF_)))) 121 | ,_union_.Insert(_offset_+=(_mod_:=Mod(_offset_,_max_size_))?Mod(_max_size_-_mod_,_max_size_):0) 122 | ,_union_size_.Insert(0) 123 | ,_struct_align_.Insert(_align_total_>_max_size_?_align_total_:_max_size_) 124 | ,_struct_.Insert(RegExMatch(_LF_,"i)^struct\s*\{")?(1,_align_total_:=0):0) 125 | ,_LF_:=SubStr(_LF_,_match_) 126 | StringReplace,_LF_,_LF_,},,A 127 | 128 | If InStr(_LF_,"*"){ ; It's a pointer, size will be always A_PtrSize 129 | _offset_ += (_mod_:=Mod(_offset_ + A_PtrSize,A_PtrSize)?A_PtrSize-_mod_:0) + A_PtrSize 130 | ,_align_total_:=_align_total_[\w\d\._#@]+)?\s*(?[\w\d\._#@]+)?\s*\[?(?\d+)?\]?\s*$",_) 134 | If (!_ArrName_ && !_ArrSize_ && !InStr( _types_ ,"," _ArrType_ ":")) 135 | _ArrName_:=_ArrType_,_ArrType_:="UInt" 136 | If InStr(_ArrType_,"."){ ;check for object that holds structure definition 137 | Loop,Parse,_ArrType_,. 138 | If A_Index=1 139 | _defobj_:=%A_LoopField% 140 | else _defobj_:=_defobj_[A_LoopField] 141 | ; _ArrType_:=_defobj_ ; ?????????????????????????????????????? 142 | } 143 | If (_idx_:=InStr( _types_ ,"," _ArrType_ ":")) ; AHK or Windows data type 144 | _padding_:=SubStr( _types_ , _idx_+StrLen(_ArrType_)+2 , 1 ),_align_total_:=_align_total_<_padding_?_padding_:_align_total_ 145 | else _padding_:= sizeof(_defobj_?_defobj_:%_ArrType_%,0,_align_total_),_max_size_:=sizeof_maxsize(_defobj_?_defobj_:%_ArrType_%) 146 | if (_max_size_){ 147 | if (_mod_:=Mod(_offset_,_max_size_)) 148 | _offset_ += Mod(_max_size_-_mod_,_max_size_) 149 | } else if _mod_:=Mod(_offset_,_padding_) 150 | _offset_ += Mod(_padding_-_mod_,_padding_) 151 | _offset_ += (_padding_ * (_ArrSize_?_ArrSize_:1)) 152 | _max_size_:=0 153 | } 154 | ; It's a union or struct, check if new member is higher then previous members 155 | If (_uix_:=_union_.MaxIndex()) && (_max_size_:=_offset_ - _union_[_uix_])>_union_size_[_uix_] 156 | _union_size_[_uix_]:=_max_size_ 157 | _max_size_:=0 158 | ; It's a union and not struct 159 | If (_uix_ && !_struct_[_uix_]) 160 | _offset_:=_union_[_uix_] 161 | 162 | ; Check for ENDING union and reset offset and union helpers 163 | While (SubStr(_LF_BKP_,0)="}"){ 164 | If !(_uix_:=_union_.MaxIndex()){ 165 | MsgBox,0, Incorrect structure, missing opening braket {`nProgram will exit now `n%_TYPE_% 166 | ExitApp 167 | } 168 | ; reset offset and align because we left a union or structure 169 | if (_uix_>1 && _struct_[_uix_-1]){ 170 | If (_mod_:=Mod(_offset_,_struct_align_[_uix_])) 171 | _offset_+=Mod(_struct_align_[_uix_]-_mod_,_struct_align_[_uix_]) 172 | } else _offset_:=_union_[_uix_] 173 | ; a member of union/struct is smaller than previous align, restore 174 | if (_struct_[_uix_] &&_struct_align_[_uix_]>_align_total_) 175 | _align_total_ := _struct_align_[_uix_] 176 | ; Increase total size of union/structure if necessary 177 | _total_union_size_ := _union_size_[_uix_]>_total_union_size_?_union_size_[_uix_]:_total_union_size_ 178 | ,_union_.Remove() ,_struct_.Remove() ,_union_size_.Remove(),_struct_align_.Remove() ; remove latest items 179 | ,_LF_BKP_:=SubStr(_LF_BKP_,1,StrLen(_LF_BKP_)-1) 180 | If (_uix_=1){ ; leaving top union, add offset 181 | if (_mod_:=Mod(_total_union_size_,_align_total_)) 182 | _total_union_size_ += Mod(_align_total_-_mod_,_align_total_) 183 | _offset_+=_total_union_size_,_total_union_size_:=0 184 | } 185 | } 186 | } 187 | _offset_+= Mod(_align_total_ - Mod(_offset_,_align_total_),_align_total_) 188 | Return _offset_ 189 | } 190 | sizeof_maxsize(s){ 191 | static _types__:=" 192 | (LTrim Join 193 | ,ATOM:2,LANGID:2,WCHAR:2,WORD:2,PTR:" A_PtrSize ",UPTR:" A_PtrSize ",SHORT:2,USHORT:2,INT:4,UINT:4,INT64:8,UINT64:8,DOUBLE:8,FLOAT:4,CHAR:1,UCHAR:1,__int64:8 194 | ,TBYTE:" (A_IsUnicode?2:1) ",TCHAR:" (A_IsUnicode?2:1) ",HALF_PTR:" (A_PtrSize=8?4:2) ",UHALF_PTR:" (A_PtrSize=8?4:2) ",INT32:4,LONG:4,LONG32:4,LONGLONG:8 195 | ,LONG64:8,USN:8,HFILE:4,HRESULT:4,INT_PTR:" A_PtrSize ",LONG_PTR:" A_PtrSize ",POINTER_64:" A_PtrSize ",POINTER_SIGNED:" A_PtrSize " 196 | ,BOOL:4,SSIZE_T:" A_PtrSize ",WPARAM:" A_PtrSize ",BOOLEAN:1,BYTE:1,COLORREF:4,DWORD:4,DWORD32:4,LCID:4,LCTYPE:4,LGRPID:4,LRESULT:4,PBOOL:" A_PtrSize " 197 | ,PBOOLEAN:" A_PtrSize ",PBYTE:" A_PtrSize ",PCHAR:" A_PtrSize ",PCSTR:" A_PtrSize ",PCTSTR:" A_PtrSize ",PCWSTR:" A_PtrSize ",PDWORD:" A_PtrSize " 198 | ,PDWORDLONG:" A_PtrSize ",PDWORD_PTR:" A_PtrSize ",PDWORD32:" A_PtrSize ",PDWORD64:" A_PtrSize ",PFLOAT:" A_PtrSize ",PHALF_PTR:" A_PtrSize " 199 | ,UINT32:4,ULONG:4,ULONG32:4,DWORDLONG:8,DWORD64:8,ULONGLONG:8,ULONG64:8,DWORD_PTR:" A_PtrSize ",HACCEL:" A_PtrSize ",HANDLE:" A_PtrSize " 200 | ,HBITMAP:" A_PtrSize ",HBRUSH:" A_PtrSize ",HCOLORSPACE:" A_PtrSize ",HCONV:" A_PtrSize ",HCONVLIST:" A_PtrSize ",HCURSOR:" A_PtrSize ",HDC:" A_PtrSize " 201 | ,HDDEDATA:" A_PtrSize ",HDESK:" A_PtrSize ",HDROP:" A_PtrSize ",HDWP:" A_PtrSize ",HENHMETAFILE:" A_PtrSize ",HFONT:" A_PtrSize ",USAGE:" 2 " 202 | )" 203 | static _types_:=_types__ " 204 | (LTrim Join 205 | ,HGDIOBJ:" A_PtrSize ",HGLOBAL:" A_PtrSize ",HHOOK:" A_PtrSize ",HICON:" A_PtrSize ",HINSTANCE:" A_PtrSize ",HKEY:" A_PtrSize ",HKL:" A_PtrSize " 206 | ,HLOCAL:" A_PtrSize ",HMENU:" A_PtrSize ",HMETAFILE:" A_PtrSize ",HMODULE:" A_PtrSize ",HMONITOR:" A_PtrSize ",HPALETTE:" A_PtrSize ",HPEN:" A_PtrSize " 207 | ,HRGN:" A_PtrSize ",HRSRC:" A_PtrSize ",HSZ:" A_PtrSize ",HWINSTA:" A_PtrSize ",HWND:" A_PtrSize ",LPARAM:" A_PtrSize ",LPBOOL:" A_PtrSize ",LPBYTE:" A_PtrSize " 208 | ,LPCOLORREF:" A_PtrSize ",LPCSTR:" A_PtrSize ",LPCTSTR:" A_PtrSize ",LPCVOID:" A_PtrSize ",LPCWSTR:" A_PtrSize ",LPDWORD:" A_PtrSize ",LPHANDLE:" A_PtrSize " 209 | ,LPINT:" A_PtrSize ",LPLONG:" A_PtrSize ",LPSTR:" A_PtrSize ",LPTSTR:" A_PtrSize ",LPVOID:" A_PtrSize ",LPWORD:" A_PtrSize ",LPWSTR:" A_PtrSize " 210 | ,PHANDLE:" A_PtrSize ",PHKEY:" A_PtrSize ",PINT:" A_PtrSize ",PINT_PTR:" A_PtrSize ",PINT32:" A_PtrSize ",PINT64:" A_PtrSize ",PLCID:" A_PtrSize " 211 | ,PLONG:" A_PtrSize ",PLONGLONG:" A_PtrSize ",PLONG_PTR:" A_PtrSize ",PLONG32:" A_PtrSize ",PLONG64:" A_PtrSize ",POINTER_32:" A_PtrSize " 212 | ,POINTER_UNSIGNED:" A_PtrSize ",PSHORT:" A_PtrSize ",PSIZE_T:" A_PtrSize ",PSSIZE_T:" A_PtrSize ",PSTR:" A_PtrSize ",PTBYTE:" A_PtrSize " 213 | ,PTCHAR:" A_PtrSize ",PTSTR:" A_PtrSize ",PUCHAR:" A_PtrSize ",PUHALF_PTR:" A_PtrSize ",PUINT:" A_PtrSize ",PUINT_PTR:" A_PtrSize " 214 | ,PUINT32:" A_PtrSize ",PUINT64:" A_PtrSize ",PULONG:" A_PtrSize ",PULONGLONG:" A_PtrSize ",PULONG_PTR:" A_PtrSize ",PULONG32:" A_PtrSize " 215 | ,PULONG64:" A_PtrSize ",PUSHORT:" A_PtrSize ",PVOID:" A_PtrSize ",PWCHAR:" A_PtrSize ",PWORD:" A_PtrSize ",PWSTR:" A_PtrSize ",SC_HANDLE:" A_PtrSize " 216 | ,SC_LOCK:" A_PtrSize ",SERVICE_STATUS_HANDLE:" A_PtrSize ",SIZE_T:" A_PtrSize ",UINT_PTR:" A_PtrSize ",ULONG_PTR:" A_PtrSize ",VOID:" A_PtrSize " 217 | )" 218 | max:=0,i:=0 219 | s:=trim(s,"`n`r`t ") 220 | If InStr(s,"}"){ 221 | Loop,Parse,s 222 | if (A_LoopField="{") 223 | i++ 224 | else if (A_LoopField="}"){ 225 | if --i<1{ 226 | end:=A_Index 227 | break 228 | } 229 | } 230 | if end 231 | s:=SubStr(s,1,end) 232 | } 233 | Loop,Parse,s,`n,`r 234 | { 235 | _struct_:=(i:=InStr(A_LoopField," //"))?SubStr(A_LoopField,1,i):A_LoopField 236 | Loop,Parse,_struct_,`;`,{},%A_Space%%A_Tab% 237 | if A_LoopField&&!InStr(".union.struct.","." A_LoopField ".") 238 | if (!InStr(A_LoopField,A_Tab)&&!InStr(A_LoopField," ")) 239 | max:=max<4?4:max 240 | else if (sizeof(A_LoopField,0,size:=0) && max