├── 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