Struct
Struct() is a build-in function that creates and returns a special
structure object.
This special object can be used to access the stucture its fields using object
syntax.
OutputVar := Struct(Definition ,AddressToStructure, InitObject)
Function Example: pt := Struct("int x;y",{x:10,y:20})
Parameters
- OutputVar
The name of the variable in which to store the Structure Object.
- Definition
This parameter must be a string containing the structure definition.
Definition is similar to C so most structures can be transformed very easily, also default data types can be used.
Either semicolon (;) or comma (,) can be used to separate fields, even mixed.
If no type for first field is given UInt will be used, otherwise previous type will be used, e.g. in "a,Int x,y,Char c,d", a will be UInt, y Int and d Char.
If only one type/key is given, e.g. "UInt", it is assumed to be a structure definition that resolves to default type or a variable that describes the structure.
Note! something like "len;" or "MyVar," are interpreted as "UInt length" and "UInt MyVar" unless len and MyVar are a variable defining the structure.
So for Struct("MyVar"), MyVar must define a structure, e.g. MyVar := "Int x, Int y", if there is no MyVar variable or it is empty Struct("MyVar") will be same as Struct("UInt MyVar")._POINT:="( Int x; // also comments in C style are supported // empty lines will be simply ignored. Int y; // last ; is optional and can be omitted. )"
New lines can be omitted too. This way the definition can be written much more compact._POINT:="Int x,Int y"
UInt is default type so it can be omitted too if negative values are not relevant (for negative values Int must be used).
_POINT:="x,y"
UNION AND STRUCT
Struct supports unions and structures in structures, note such structures do not have a name so you can't use same name for a field in main structure and sub-structure.
_MyUnion:=" ( union { UInt int; struct { UShort x; UShort y; }; struct { Byte a; Byte b; Byte c; Byte d; }; }; )" mys:=Struct(_MyUnion) mys.int:=0xFFFFFFFF MsgBox % mys.int "`n" mys.x " " mys.y "`n" mys.a " " mys.b " " mys.c " " mys.d
Create structure from a string containing the structure definition.
pt:=Struct("UInt x,UInt y")
The definition can be saved in a variable. Struct will also resolve the given string to the variable if necessary.
POINT:="UInt x,UInt y" pt:=Struct("POINT")
An existing structure object can be used too.
POINT:=Struct("x,y") pt:= Struct(POINT)
Global / Static / Local variables
Inside a function you can also use local and static variables for structure definition.
Even when this objects are returned the static variable refference in definition can be resolved dynamically.
It is also possible to create a structure from a static variable even if you are not inside the function. Therefore include the name of the function and enclose variable in brackets. This is also necessary if you create a static structure from a static variable like in MyFunc here.
MyFunc() ; using this method we can create static structures AnotherFunc() ; this method can be used anywhere to adccess the variable pt:=Struct("MyFunc(POINT)",{x:100,y:200}) ; even outside the function we can access the definition variable MsgBox % pt.x "-" pt.y MyFunc(){ static POINT:="UInt x,UInt y" , pt:=Struct("MyFunc(POINT)",{x:10,y:20}) MsgBox(pt.x "-" pt.y) } AnotherFunc(){ static pt:=Struct("MyFunc(POINT)",{x:10,y:20}) MsgBox(pt.x "-" pt.y) }
- AddressToStructure
Address of memory representing the structure. This variable is used to access an existing structure in memory.
When no AddressToStructure is given but InitObject is used, it must be passed in this parameter, see InitObject example. For example here we would use the memory of variable pointMem for the structure.
VarSetCapacity(pointMem,8) pt:=Struct("x,y",&pointMem) pt.x:=10 MsgBox % pt[] " = " (&pointMem) "`n" pt.x " = " NumGet(pointMem,"UInt")
- InitObject
Initialize your structure right away. To initialize the structure you will need to pass an object with keys and values.
The order of keys and values is not relevant because it will be enumerated in alphabetical order anyway.
When no AddressToStructure is given, InitObject must be used in AddressToStructure parameter.pt:=Struct("x,y",{x:100,y:200}) MsgBox % pt.x "`n" pt.y
Methods
Size
Returns the size in bytes of a structure or its field.
OutputVar := Struct.Size([field])
OutputVar | The name of the Variable in which to store the size of field or structure. |
field | Name of existing field within the structure, if omitted the size of structure is returned. |
pt:=Struct("x,y") Msgbox % pt.Size() ; returns 8
struct:=Struct("Int64 x,y") Msgbox % struct.Size("y") ; returns 8If structure is an array you will needle to pass a digit to retrieve the size of a field.
struct:=Struct("Int64[2]") Msgbox % struct.Size(1) ; returns 8
Offset
Returns offset for a field.
OutputVar := Struct.Offset(field)
OutputVar | The name of the Variable in which to store the offset. |
field | Name of existing field within the structure. |
pt:=Struct("x,y") MsgBox % pt.Offset("y") ; returns 4
CountOf
Returns size of array or 0 if structure or field is not an array.
OutputVar := Struct.CountOf([field])
OutputVar | The name of the Variable in which to store the length of array. |
field | Name of existing field within the structure.. |
uint:=Struct("UInt[10]") MsgBox % uint.CountOf() ; returns 10 pt:=Struct("UInt x[2],UInt y[2]") MsgBox % pt.CountOf("x") ; returns 2
Fill
Fills the structure with given value.
Struct.Fill([value])
value | A digit value or character that will fill the structure. Mainly used to empty/clear a structure. |
pt:=Struct("x,y",{x:10,y:20}) MsgBox % pt.x pt.Fill() ; same as pt.Fill(0) MsgBox % pt.x s:=Struct("Byte[10]") s.Fill("A") MsgBox % StrGet(s[],10,"CP0")
GetAddress
Returns address of field or structure.
OutputVar := Struct.GetAddress([field])
OutputVar | The name of the Variable in which to store the address. |
field | Name of existing field within the structure. When omitted, returns address of structure itself. To get the address for structure you can also use[] or [""] for structure objects and [""] for its fields. Note you cannot use [] for fields. |
pt:=Struct("x,y") MsgBox % pt.GetAddress() " = " pt[] MsgBox % pt.GetAddress("x") " = " pt.x[""]
Encoding
Returns encoding for field or structure.
OutputVar := Struct.Encoding([field])
OutputVar | The name of the Variable in which to store the encoding. |
field | Name of existing field within the structure. When omitted, Encoding of structure itself will be returned. |
Other encoding types have to use StrGet and StrSet to retrieve correct text.
str1:=Struct("LPTSTR name") str2:=Struct("LPTSTR") MsgBox % str1.Encoding("name") " = " str2.Encoding()
IsPointer
Returns true if the field or structure is a pointer.
OutputVar := Struct.IsPointer([field])
OutputVar | The name of the Variable in which to store true if field or structure is a pointer or 0 / false otherwise. |
field | Name of existing field within the structure. When omitted, returns true if structure itself is a pointer. |
s:=Struct("UInt *a,UInt b") MsgBox % s.IsPointer("a") "`n" s.IsPointer("b") s:=Struct("UInt*") MsgBox % s.IsPointer()
GetPointer
Returns pointer saved in structure or field.
OutputVar := Struct.GetPointer([field])
OutputVar | The name of the Variable in which to store the address. |
field | Name of existing field within the structure. When omitted, reads and returns pointer of first array item in our structure. |
str:=Struct("LPTSTR name",{name:"AutoHotkey"}) MsgBox % str.GetPointer("name") "`n" StrGet(str.GetPointer("name"))
You can also use "" to read the pointer. So [""] returns address and ["",""] returns the pointer, ["","",""] pointer to pointer and so on.
str:=Struct("LPTSTR name",{name:"AutoHotkey"}) MsgBox % str.name["",""] "`n" StrGet(str.name["",""]))
SetCapacity
Set new size for our structure or pointer, returns true if new memory was allocated.
OutputVar := Struct.SetCapacity([field,] newsize)
OutputVar | The name of the Variable in which to store the new size. |
field | Name of the field where capacity should be set, if omitted structure capacity will be set. This is mainly used for arrays to shrink or increase the size. When setting capacity for main structure, its old memory will be freed if necessary and new memory will be zero-filled. |
new size | Must be a digit or a variable containing a digit that represents new size of our field or structure. |
str:=Struct("LPTSTR name") str.SetCapacity("name",2000) previous_pointer := str.GetPointer("name") str.name:="AutoHotkey" MsgBox % previous_pointer " = " str.GetPointer("name") "`n" str.name ; as you can see pointer did not change.
You can allocate and use memory as you like, for example here we will store a String and the pointer in same memory block. Of course when you allocate new memory here you will loose contents.
str:=Struct("LPTSTR") str.SetCapacity(2000) str.1[""]:=str[]+A_PtrSize str.1:="AutoHotkey" MsgBox % str.1
GetCapacity
Returns Capacity previously set using .SetCapacity() or via assigning a string.
OutputVar := Struct.GetCapacity([field])
OutputVar | The name of the Variable in which to store the capacity in bytes. |
field | Name of existing field in our structure, if omitted returns structure capacity. |
str:=Struct("LPTSTR name") str.SetCapacity("name",2000) MsgBox % str.GetCapacity("name")
Clone
Returns new structure object of same type.
OutputVar := Struct.Clone([AddressOfStructure,InitObject])
OutputVar | The name of the Variable in which to store the new structure object. |
AddressOfStructure | Address to memory for this structure. When omitted, memory will be reserved and set internally. |
InitObject | An object used to initialize the structure. |
pt:=Struct("x,y") pt1:=pt.Clone({x:10,y:20}) MsgBox % pt1.x "-" pt1.yYou can do the same using the new operator
pt:=Struct("x,y") pt1:= new pt({x:10,y:20}) MsgBox pt1.x "-" pt1.y
- Features and Remarks
- Some remarks about structure objects and more features.
- A structure object cannot be altered, so you cannot add more fields to
it. The only exeption are arrays, here items are resolved dynamically.
You can receive the address of structure or key using empty key (e.g. struct.item[""]). For structure objects also [] can be used (e.g. struct[] or struct[""]). - When a key is not given a type, e.g. "LPTSTR key1,key2", previous type is used. If the first key lacks a type, Uint is used,
so "key1,key2" is equivalent to "UInt key1,key2" or "UInt key1,UInt key2".
Note: pointer needs to be specified for each element, so "*UInt key1,key2" is equivalent to "UInt *key1,UInt key2". If both elements are pointers "UInt *key1,*key2" must be used. - To access a pointer in pointer you can specify empty key several times,
e.g. object["",""] would get the pointer at address of object[].
Same is valid for keys, so here you'll receive the pointer.
s:=Struct("LPTSTR str") s.str:="Hello World!" MsgBox % StrGet(s.str["",""])
- TYPE ONLY DEFINITION
Struct supports type only definition for all default types like
Int,Byte,Char... .
To access fields of such structures you will allways need to use digits like in arrays.
u:=Struct("UInt") ; this is similar to UInt[1] u.1:=10
MsgBox % u.1 - ARRAYS
Same way arrays are supported.
u:=Struct("UInt[10]") u.10:=100 MsgBox % u.10
- ARRAYS OF UNKNOWN SIZE
Any structure can be used as array.
However be careful, accessing memory that does not belong to the structure may crash your application.
pt:=Struct("x,y") pt.SetCapacity(16) ; increase capacity to hold 2 structures pt.x := 1 ; we can access the first field right away, similar to pt.1.x := 1 pt.2.x := 2 ; here we access the second structure MsgBox % pt.2.x " != " pt.x
- ENUMERATING A STRUCTURE
Using a for loop we can enumerate the structure to retrieve field names
and their values.
Enumeration will be executed in same order as the structure was defined, not alphabetically like for simple objects.
s:=Struct("Byte x,Int u,LPTSTR str") s.x:=10 s.u:=1000 s.str:="AutoHotkey" for k,v in s MsgBox % k ": " v
Also dedicated Arrays can be enumerated same way.
x:=Struct("UInt[10]",[0,9,8,7,6,5,4,3,2,1]) for k, v In x MsgBox % k ": " v
- DYNAMIC AND STATIC FIELDS AND
STRUCTURES
Struct supports calling dynamic structures and fields, such that are
defined but do not exist as an object/field.
These objects/fields are created dynamically whenever needed and invoked/called automatically internally.
A static field on the other hand is defined directly in structure object.
For Example, here x and y are static fields.
myStruct:=Struct("Int x, Int y")
Dynamic fields and structures are little different to static, they use refference to the definition to create the structure internally.
So here x and y fields will be created dynamically only when necessary.
POINT:="Int x, Int y" pt:=Struct("POINT p", { p: { x:10, y:20 } } ) ; same structure as above but POINT structure is resoved dynamically. MsgBox % pt.p.x " , " pt.p.y
Furthermore, you can allocate memory for static fields using .SetCapacity() method, see below. This memory will be managed internally and freed whenever the object is deleted (last
reference is released).
This feature allows assigning a string without initializing memory manually before.
s:=Struct("LPTSTR string") s.string:="Hello World!" MsgBox % s.string
The size of allocated memory is backed up internally and can be retrieved with .GetCapacity() method
MsgBox % s.GetCapacity("string")
Whenever a new string is assigned, memory will be only reallocated if a larger memory is needed.
To free the memory manually use .SetCapacity() method.
s.SetCapacity("string",0) MsgBox % s.GetCapacity("string")
You can manually allocate memory to fields using .SetCapacity() method.
s:=Struct("LPTSTR string") s.SetCapacity("string",260)
NOTE You cannot allocate memory for dynamic fields.
Calling .GetCapacity() method on dynamic field will return -1.
Also calling .SetCapacity() method will simply fail.
- BIT FIELDS
Also bit fields are supported, see Bit Fields for more information.
Bits:=Struct(" ( { Byte int; struct { Byte a:1,b:1,c:1,d:1,e:1,f:1,g:1,h:1; } } )") Loop % 0xFF{ bit:=(Bits.int:=A_Index) "`t" For k, v in Bits If A_Index>1 bit.= v " " ToolTip % "int bits: 1 2 3 4 5 6 7 8`n" bit Sleep 100 }
Related
sizeof, StructTypes , DllCall, NumGet, NumPut
Examples
; SIMPLE STRUCTURE pt:=Struct("x,y") ; SAME STRUCTURE CREATED FROM VARIABLE _POINT:="x,y" pt:=Struct(_POINT) ; ARRAY OF POINTS pt:=Struct("_POINT[10]") ; ARRAY OF POINTS OF UNKNOWN SIZE pt:=Struct("*_POINT") ; TO CREATE ARRAY FROM POINTER _POINT:="x,y", VarSetCapacity(pt1,8) pt:=Struct("*_POINT") ; similar to "*_POINT[1]" pt["",""]:=&;pt1 ; assign pointer to fist item pt.x:=1 ; same as pt.1.x MsgBox % pt.x ; Create a structure from structure pt1:= new pt pt1:= pt.Clone() ; More examples pt:=Struct("x,y") ;POINT structure pt.x:=100 MsgBox % pt.x rc:=Struct("left,top,right,bottom") ; RECT structure Gui,Show,w100 h100,Test Gui,+LastFound DllCall("GetWindowRect","PTR",WinExist(),"PTR",rc[]) MsgBox % "left: " rc.left "`ntop: " rc.top "`nright: " rc.right "`nbottom: " rc.bottom ; Array Examples ; Simple array structures. ; Array is always accessed using integer array:=Struct("Uint[10]") array.5:=10 MsgBox % array.5 MyArray:="a,b" array:=Struct("MyArray[10]") array.1.a:=1 array.2.b:=2 MsgBox % array.1.a "`n" array.2.b ; Pointer Examples ; SIMPLE POINTER* int:=Struct("*UInt"), VarSetCapacity(mem,100) int["",""]:=&mem int.1:=100 ; automatically resolves to pointer. MsgBox % int.1 ; again pointer is resolved automatically ; POINTER TO ARRAY OF POINTERS VarSetCapacity(Arr,10*A_PtrSize,0) Loop 10 ; create 10 arrays to hold 10 integers VarSetCapacity(Arr%A_Index%,10*sizeof("UInt"),0) ,NumPut(&Arr%A_Index%,&arr,(A_Index-1)*A_PtrSize,"PTR") s:=Struct("**UInt") s["",""]:=&Arr s.1.1:=10 s.2.10:=20 MsgBox % s.1.1 "-" s.2.10 ; ARRAY OF POINTERS VarSetCapacity(Arr,10*A_PtrSize,0) Loop 10 ; create 10 arrays to hold 10 integers VarSetCapacity(Arr%A_Index%,10*sizeof("UInt"),0) ,NumPut(&Arr%A_Index%,&arr,(A_Index-1)*A_PtrSize,"PTR") s:=Struct("*UInt[10]",&Arr) s.1.1:=30 s.2.10:=40 MsgBox % s.1.1 "-" s.2.10 ; ARRAY OF POINTERS TO POINTERS VarSetCapacity(Arr,10*A_PtrSize,0) Loop 10 ; create 10 arrays to hold 10 arrays of 10 integers { i:=A_Index VarSetCapacity(Arr%i%,10*A_PtrSize,0) ,NumPut(&Arr%i%,&arr,(i-1)*4,"PTR") Loop 10 VarSetCapacity(Arr%i%_%A_Index%,10*sizeof("UInt"),0) ,NumPut(&Arr%i%_%A_Index%,&arr%i%,(A_Index-1)*4,"PTR") } s:=Struct("**UInt[10]",&Arr) s.1.1.1:=50, s.2.3.10:=60 MsgBox % s.1.1.1 "-" s.2.3.10 ; String Examples ; SIMPLE USER DEFINED STRUCTURE user:="UInt Id, LPTSTR Name" users := Struct("user[2]") ; array of structs ; here no automatic String allocation can be done because users is evaluated dynamically so we use own memory Loop 2 VarSetCapacity(Str%A_Index%,256) users.1.name[""]:=&Str1 ,users.2.name[""]:=&Str2 ; above assignment can be assigned via object too ; users:=[{name:{"":&Str1}},{name:{"":&Str2}}] users.1.Id := 1 ,users.2.Id := 2 users.1.Name := "Admin" ,users.2.Name := "User" ; same here, we could use an object to assign values ; users:=[{id:1,name:"Admin"},{id:2,name:"User"}] MsgBox % users.1.Id "`t" users.1.Name "`n" users.2.Id "`t" users.2.Name ; Now to do the same with automatic String memory we would need to use non dynamic structure ; Therefore we define the structure completely and we can initialize it directly users := Struct("UInt id1, LPTSTR Name1,UInt id2,LPTSTR Name2",{id1:1,name1:"Admin",id2:2,name2:"User"}) MsgBox % users.id1 "`t" users.name1 "`n" users.id2 "`t" users.name2 ; CHAR ARRAY String:=Struct("TCHAR char[26]") Loop 26 string["char"][A_Index]:=Chr(A_Index+64) Loop 3 MsgBox % String["char"][A_Index*2] ;show some characters MsgBox % StrGet(string[],26) ;get complete string ; RECT EXAMPLE Gui,+LastFound hwnd:=WinExist() ;get window handle _RECT:="left,top,right,bottom" RC:=Struct(_RECT) ;create structure Gui,Add,Text,,Press Escape to continue Gui,Show,w200 h100 ;show window DllCall("GetWindowRect","PTR",hwnd,"PTR",rc[]) ;get window position rc.right := rc.right - rc.left ;Set rc.right to be the width rc.bottom := rc.bottom - rc.top ;Set rc.bottom to be the height While DllCall("GetCursorPos","PTR",rc[]) { DllCall("MoveWindow","PTR",hwnd,"int",rc.left,"int",rc.top,"int",rc.right,"int",rc.bottom,"Int",1) If GetKeyState("Escape","P") break } Gui,Destroy ; FINDFIRSTFILE EXAMPLE _FILETIME := "dwLowDateTime,dwHighDateTime" _SYSTEMTIME := "WORD wYear,WORD wMonth,WORD wDayOfWeek,WORD wDay,WORD wHour,WORD wMinute,WORD wSecond,WORD Milliseconds" _WIN32_FIND_DATA := "dwFileAttributes,_FILETIME ftCreationTime,_FILETIME ftLastAccessTime,_FILETIME ftLastWriteTime," . "nFileSizeHigh,nFileSizeLow,dwReserved0,dwReserved1,TCHAR cFileName[260],TCHAR cAlternateFileName[14]" file:=Struct("_WIN32_FIND_DATA[2]") time:=Struct("_SYSTEMTIME") DllCall("FindFirstFile","Str",A_ScriptFullPath,"Uint",file.1[""]) DllCall("FindFirstFile","Str",A_AhkPath,"UInt",file.2[""]) MsgBox % StrGet(file.1.cFileName[""]) 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[""]) handle:=DllCall("FindFirstFile","Str","C:\*","Uint",file.2[""]) Loop { If !DllCall("FindNextFile","Uint",handle,"Uint",file.2[""]) break DllCall("FileTimeToSystemTime","Uint",file.2.ftLastWriteTime[""],"Uint",time[""]) ToolTip % StrGet(file.2.cFileName[""]) "`n" StrGet(file.2.cAlternateFileName[""]) "`n" file.2.nFileSizeHigh " - " file.2.nFileSizeLow . "`n" time.wYear . "-" time.wMonth . "-" time.wDay . "`n" time.wDayOfWeek . "`n" time.wHour . ":" time.wMinute . ":" time.wSecond . ":" time.Milliseconds Sleep, 200 } ToolTip DllCall("CloseHandle","Uint",handle) ; PROCESS32FIRST EXAMPLE MAX_PATH:=260 _PROCESSENTRY32:=" ( DWORD dwSize; DWORD cntUsage; DWORD th32ProcessID; ULONG_PTR th32DefaultHeapID; DWORD th32ModuleID; DWORD cntThreads; DWORD th32ParentProcessID; LONG pcPriClassBase; DWORD dwFlags; TCHAR szExeFile[" MAX_PATH "]; )" VarSetCapacity(string,260) pEntry:= Struct(_PROCESSENTRY32) pEntry.dwSize := sizeof(_PROCESSENTRY32) hSnapshot:=DllCall("CreateToolhelp32Snapshot","UInt",TH32CS_SNAPALL:=0x0000001F,"PTR",0) DllCall("Process32First" (A_IsUnicode?"W":""),"PTR",hSnapshot,"PTR",pEntry[""]) While % (A_Index=1 || DllCall("Process32Next" (A_IsUnicode?"W":""),"PTR",hSnapshot,"PTR",pEntry[""])) { ToolTip % pEntry.cntUsage "`n" pEntry.th32ProcessID . "`n" pEntry.th32DefaultHeapID "`n" pEntry.th32ModuleID . "`n" pEntry.cntThreads "`n" pEntry.th32ParentProcessID . "`n" pEntry.pcPriClassBase "`n" pEntry.dwFlags "`n" StrGet(pEntry.szExeFile[""]) Sleep, 200 } ; LISTPROCESSMODULES EXAMPLE MAX_PATH:=260 MAX_MODULE_NAME32:=255 _MODULEENTRY32:=" ( DWORD dwSize; DWORD th32ModuleID; DWORD th32ProcessID; DWORD GlblcntUsage; DWORD ProccntUsage; BYTE *modBaseAddr; DWORD modBaseSize; HMODULE hModule; TCHAR szModule[" MAX_MODULE_NAME32 + 1 "]; TCHAR szExePath[" MAX_PATH "]; )" ListProcessModules(DllCall("GetCurrentProcessId")) ListProcessModules(dwPID){ global _Struct static TH32CS_SNAPMODULE:=0x00000008,INVALID_HANDLE_VALUE:=-1 hModuleSnap := Struct("HANDLE") me32 := Struct("_MODULEENTRY32") ; Take a snapshot of all modules in the specified process. hModuleSnap := DllCall("CreateToolhelp32Snapshot","UInt", TH32CS_SNAPMODULE,"PTR", dwPID ) if( hModuleSnap = INVALID_HANDLE_VALUE ) { MsgBox % "CreateToolhelp32Snapshot (of modules)" return FALSE } ; Set the size of the structure before using it. me32.dwSize := sizeof("_MODULEENTRY32") ; Retrieve information about the first module, ; and exit if unsuccessful if( !DllCall("Module32First" (A_IsUnicode?"W":""),"PTR", hModuleSnap,"PTR", me32[""] ) ) { MsgBox % "Module32First" ; Show cause of failure DllCall("CloseHandle","PTR", hModuleSnap ) ; // Must clean up the snapshot object! return FALSE } ; Now walk the module list of the process, ; and display information about each module while(A_Index=1 || DllCall("Module32Next" (A_IsUnicode?"W":""),"PTR",hModuleSnap,"PTR", me32[""] ) ) { ToolTip % "MODULE NAME`t=`t" StrGet(me32.szModule[""]) . "`nexecutable`t=`t" StrGet(me32.szExePath[""]) . "`nprocess ID`t=`t" me32.th32ProcessID . "`nref count (g)`t=`t" me32.GlblcntUsage . "`nref count (p)`t=`t" me32.ProccntUsage . "`nbase address`t=`t" me32.modBaseAddr[""] . "`nbase size`t=`t" me32.modBaseSize Sleep, 200 } ; Do not forget to clean up the snapshot object. DllCall("CloseHandle","PTR",hModuleSnap) return TRUE } ; Enumerate a structure. ; ENUMERATE SIMPLE STRUCTURE MyStruct:="a,b,c" s:=Struct(MyStruct,{a:1,b:2,c:3}) for k, v in s MsgBox % k ": " v ; ENUMERATE ARRAY OF STRUCTURES MyStruct:="a,b,c" s:=Struct("MyStruct[3]",[{a:1,b:2,c:3},{a:4,b:5,c:6},{a:7,b:8,c:9}]) for k, v in s for key,value in v MsgBox % key ": " value ; ENUMERATE DYNAMIC STRUCTURE MyStruct:="a,b,c" s:=Struct("Short size,LPTSTR name,MyStruct ms",{size:sizeof(MyStruct),name:"MyStruct",ms:{a:1,b:2,c:3}}) for k, v in s if !IsObject(v) MsgBox % k ": " v else for key,value in v MsgBox % key ": " value