Struct 是一个创建并返回结构对象的内置函数。
该对象可用于使用对象语法访问定义的结构。
SetCapacity 方法可用于为结构体和指针分配内存。
Methods:
Struct 需要一个定义并可选地接受结构内存和初始化对象的地址。
OutputVar := Struct(Definition ,StructMemory, InitObject)函数示例: pt := Struct("int x;y",,{x:10,y:20})
用于存储 Structure 对象的变量的名称。
该参数必须是包含结构定义的字符串或变量。
定义与C类似,因此大多数结构可以直接使用或很容易转换。
Following 默认数据类型 可以在Structures中使用,其他类型必须在脚本中定义。
可以使用分号(;)或逗号(,)来分隔字段,甚至可以混合使用。
如果没有给定第一个字段的类型,将使用 UInt,否则将使用先前的类型。
例如在 “a,Int x,y,字符 c,d”,a 将为 UInt,x 和 y 为 Int,c 和 d 为 Char。
如果只给出一种类型,例如 "UInt" 或 "POINT",假设它是一个由 1 组成的数组,与 "UInt[1]" 或 "POINT[1]"
注意! 如果定义包含逗号或分号,例如 "len;" 或 "MyVar," 它被解释为 "UInt
length" 和 "UInt MyVar",
去哪里 Struct("MyVar"), MyVar 必须定义一个结构,例如
MyVar := "Int x, Int y",如果没有 MyVar 变量或者它为空 Struct() 会抛出错误。
评论和一些例子:
从包含结构定义的字符串创建结构。
pt:=Struct("Int x,Int y")
定义可以保存在变量中。 Struct 如有必要,还将把给定的字符串解析为变量,但是该结构将被创建为 1 的数组,因此 Struct("POINT") 等于 Struct("POINT[1]").
这将改变如何访问字段的语法,例如 pt:=Struct(点) 或 pt:=Struct("UInt x,y") 您可以直接访问这些值,例如pt.x 在哪里 pt:=Struct("点") 和 pt:=Struct("POINT[1]") 您将需要使用 pt.1.x 或 pt[1].x 或 pt["1"].x。
求值顺序始终为 Structure -> 数组 -> 指针 -> 等 -> 字段。
所以在下面的结构中 s:=Struct("*UInt") 这与以下相同 s:=Struct("*UInt[1]"),
第一个数组被访问 s.1,然后是指针 s.1.1。
POINT:="
(
Int x; // also comments in C syntax are supported
// empty lines will be simply ignored.
Int y; // last ; is optional and can be omitted.
)"
POINT:="Int x,y"
pt:=Struct("POINT") ; 与 pt:=Struct("POINT[1]") 相同
如果没有注释,新行也可以省略。这样定义就可以写得更加紧凑。
POINT:="Int x,y"
UInt 是默认类型,因此如果负值不相关(对于负值必须使用 Int),也可以省略它。
POINT:="x,y"
Struct 支持结构中的联合和结构。请注意,子结构不能有名称,因此主结构和子结构中的字段不能使用相同的名称。
您可以简单地在结构名称前面加上前缀,例如虚拟_a、虚拟_b....
UnionStruct:="
(
union {
UInt int;
struct {
UShort x;
UShort y;
};
struct {
Byte a;
Byte b;
Byte c;
Byte d;
};
};
)"
mys:=Struct(UnionStruct)
mys.int:=0xFFFFFFFF
MsgBox % mys.int "`n" mys.x " " mys.y "`n" mys.a " " mys.b " " mys.c " " mys.d
Global / Static / Local
variables
我们可以从函数外部甚至另一个函数中的静态函数变量创建结构。因此,请包含函数名称并将变量括在括号中。如果您从静态变量创建静态结构(如此处的 MyFunc 中所示),这也是必要的。
MyFunc() ; 使用这种方法我们可以创建静态结构
AnotherFunc() ; 该方法可以在任何地方使用来访问变量
pt:=Struct("MyFunc(POINT)",,{x:100,y:200}) ; 即使在函数之外我们也可以访问定义变量
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)
}
表示结构的内存地址。该变量用于访问内存中现有的结构。例如这里我们将使用变量的内存 pointMem 对于结构。
VarSetCapacity(pointMem,8)
pt:=Struct("x,y",&pointMem)
pt.x:=10
MsgBox % pt[] " = " (&pointMem) "`n" pt.x " = " NumGet(pointMem,"UInt")
使用对象、映射、数组或其他结构立即初始化您的结构。
键和值的顺序不相关。
pt:=Struct("x,y",,{x:100,y:200})
MsgBox % pt.x "`n" pt.y
返回相同类型的新结构对象。
OutputVar := Struct.Clone()
| OutputVar | 用于存储新结构对象的变量的名称。 |
pt:=Struct("x,y")
pt1:=pt.Clone()
pt1[]:={x:10,y:20}
MsgBox % pt1.x "-" pt1.y
返回数组定义的大小,如果结构或字段不是数组,则返回 0。
注意! 可以使用 SetCapacity 增加数组大小,但 CountOf 将始终返回定义的值。
OutputVar := Struct.CountOf([field])
| OutputVar | 用于存储数组长度的变量的名称。 |
| field | 结构内现有字段的名称.. |
uint:=Struct("UInt[10]")
MsgBox % uint.CountOf() ; returns 10
pt:=Struct("UInt x[2],UInt y[2]")
MsgBox % pt.CountOf("x") ; returns 2
pt:=Struct("Uint a[2]")
MsgBox % pt.a.CountOf() ; returns 2
pt.SetCapacity(16)
MsgBox % pt.a.CountOf() ; 仍会返回 2
返回字段的编码。
OutputVar := Struct.Encoding([field])
| OutputVar | 用于存储编码的变量的名称。 |
| field | 结构内现有字段的名称。 |
str1:=Struct("LPSTR name")
str2:=Struct("LPTSTR name")
MsgBox % str1.Encoding("name") " != " str2.Encoding("name")
返回字段或结构的地址。
OutputVar := Struct.GetAddress([field])
| OutputVar | 用于存储地址的变量的名称。 |
| field | 结构内现有字段的名称。省略时,返回结构本身的地址。要获取结构的地址,您还可以使用 [] 或 [""] 作为结构对象,使用 [""] 作为其字段。 注意 字段不能使用 []。 |
pt:=Struct("x,y")
MsgBox % pt.GetAddress() " = " pt[]
MsgBox % pt.GetAddress("y") " = " pt.y[""]
返回先前使用 .SetCapacity() 或通过分配字符串分配的容量。
OutputVar := Struct.GetCapacity([field])
| OutputVar | 用于存储容量(以字节为单位)的变量的名称。 |
| field | 我们结构中现有字段的名称。 |
str:=Struct("LPTSTR name")
str.SetCapacity("name",2000)
MsgBox % str.GetCapacity("name")
返回保存在结构或字段中的已分配内存的指针。
OutputVar := Struct.GetPointer([field])
| OutputVar | 用于存储地址的变量的名称。 |
| field | 结构内现有字段的名称。省略时,返回结构中第一项的指针。 |
str:=Struct("LPTSTR name",,{name:"AutoHotkey"})
MsgBox % str.GetPointer("name") "`n" StrGet(str.GetPointer("name"))
也可以使用“”来读取指针。因此,[""] 返回地址,["",""] 返回指针,["","",""] 指向指针的指针,依此类推。
str:=Struct("LPTSTR name",,{name:"AutoHotkey"})
MsgBox % str.name["",""] "`n" StrGet(str.name["",""])
如果字段或结构是指针,则返回 true。
OutputVar := Struct.IsPointer([field])
| OutputVar | 如果字段或结构是指针,则在其中存储 true 的变量名称,否则存储 0 / false。 |
| field | 结构内现有字段的名称。省略时,如果结构本身是指针,则返回 true。 |
s:=Struct("UInt *a,UInt b")
MsgBox % s.IsPointer("a") " != " s.IsPointer("b")
s:=Struct("UInt*")
MsgBox % s.IsPointer()
返回字段的偏移量。
OutputVar := Struct.Offset(field)
| OutputVar | 用于存储偏移量的变量的名称。 |
| field | 结构内现有字段的名称。 |
pt:=Struct("x,y")
MsgBox % pt.Offset("y") ; returns 4
; 注意!因为结构动态解析指针和数组,所以它们的偏移量将相对于父项
MyStruct:="Int a,b"
pt:=Struct("MyStruct a[2]")
MsgBox % pt.a.Offset(2) ; returns 8
. " / " pt.a.2.Offset("b") ; returns 4
为字段分配内存,如果分配了新内存,则返回分配的大小。
OutputVar := Struct.SetCapacity([field,] newsize)
| OutputVar | 用于存储新大小的变量的名称。 |
| field | 应分配内存的字段名称。 |
| 新尺寸 | 必须是数字或包含数字的变量,表示要分配的新内存大小。 |
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 ; 正如你所看到的,指针没有改变,因为内存只是减少了。
MsgBox % str.name.GetCapacity() ; 但是,分配的大小发生了变化。
当内存被重新分配时,内容将被复制到新内存。将字符串分配给字段时,将重新分配内存,除非大小恰好是字符串+终止符所需的大小。
str:=Struct("LPTSTR name")
str.SetCapacity("name",100)
MsgBox % str.GetCapacity("name")
str.name:="AutoHotkey"
MsgBox % str.GetCapacity("name")
返回结构或字段的大小(以字节为单位)。
OutputVar := Struct.Size([field])
| OutputVar | 用于存储字段或结构大小的变量的名称。 |
| field | 结构中现有字段的名称,如果省略,则返回结构的大小。 |
pt:=Struct("x,y")
MsgBox % pt.Size() ; returns 8
struct:=Struct("Int64 x,y")
MsgBox % struct.Size("y") ; returns 8
如果结构是一个数组,您将需要传递一个数字来检索字段的大小。struct:=Struct("Int64[2]")
MsgBox % struct.Size(1) ; returns 8
s:=Struct("LPTSTR str")
s.str:="Hello World!"
MsgBox % StrGet(s.str["",""])Struct 支持所有默认类型(如 Int、Byte、Char...)的仅类型结构。
这些将被创建为数组,因此“char”相当于“char[1]”。要访问此类结构的字段,您始终需要使用 struct.1 或 struct[1] 或 struct["1"]。<>
u:=Struct("UInt") ; 相当于 UInt[1]
u.1:=10
MsgBox % u.1支持数组的方式相同。
u:=Struct("UInt[10]")
u.10:=100
MsgBox % u.10Struct也支持指针。
mystruct:=Struct("*int") ; 与“*int[1]”相同
mystruct.SetCapacity(1,8)
mystruct.1.1:=100
MsgBox % mystruct.1.1
Struct 支持自定义结构和字段。
POINT:="Int x, Int y"
pt:=Struct("POINT p",,{ p: { x:10, y:20 } } )
MsgBox % pt.p.x " , " pt.p.y
还支持指针,但是在访问该字段之前,我们必须为其分配内存。POINT:="Int x, Int y"
pt:=Struct("POINT *p")
pt.SetCapacity("p",sizeof(pt.p))
pt.p.x:=100, pt.p.y:=200
MsgBox % pt.p.x " , " pt.p.y
内存将在内部管理并在对象被删除时释放。
对于字符串,内存会在之前自动初始化。
s:=Struct("LPTSTR string")
s.string:="Hello World!"
MsgBox % s.string
可以使用 .GetCapacity() 方法检索分配的内存大小
MsgBox % s.GetCapacity("string")
每当分配新字符串时,如果新字符串长度不同,则将重新分配内存。
要手动释放内存,我们可以使用.SetCapacity()。
s.SetCapacity("string",0)
MsgBox % s.GetCapacity("string")
您可以使用 .SetCapacity() 方法手动为字段分配内存。
但是,要保留分配的内存,您必须使用 StrPut("new string",s.string[""]) 写入字符串,否则如果新字符串长度不同,内存将被重新分配。
s:=Struct("LPTSTR string")
s.SetCapacity("string",260)
还支持位字段,请参阅 Bit Fields 了解更多信息。
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 200
}
使用 for 循环,我们可以枚举结构来检索字段名称及其值。
枚举将以与定义结构相同的顺序执行。
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
数组也可以用同样的方式枚举。
x:=Struct("UInt[10]",[9,8,7,6,5,4,3,2,1,0])
for k, v In x
MsgBox % k ": " v
注意! 像“Uint *a”这样未知大小的字段只能枚举到第一个值,而不能枚举到更深的值!
要完整地枚举结构,需要完整地定义它!
MyStruct:="UInt[3]"
pt:=Struct("MyStruct *a")
pt.a.SetCapacity(1,100)
pt.a.1:=[100,200,300]
for k,v in pt.a.1
MsgBox % k "=" v
; 创建指针数组
_POINT:="x,y"
pt:=Struct("*_POINT") ; 类似于“*_POINT[1],但我们必须分配内存”
pt.SetCapacity(1,A_PtrSize),pt.SetCapacity(2,A_PtrSize)
pt.1.SetCapacity(1,8),pt.2.SetCapacity(1,8) ; 分配内存
pt.1.1.x:=100, pt.2.1.x:=200
MsgBox % pt.1.1.x " / " pt.2.1.x
; 更多示例
pt:=Struct("x,y") ; 点结构
pt.x:=100
MsgBox % pt.x
rc:=Struct("left,top,right,bottom") ; 矩形结构
Gui,New,HWNDhwnd
Gui,Show, w640 h480
DllCall("GetWindowRect","PTR",hwnd,"PTR",rc[])
MsgBox % "left: " rc.left "`ntop: " rc.top "`nright: " rc.right "`nbottom: " rc.bottom
Gui, Destroy
ExitApp
; 数组示例
;简单的数组结构。
;数组始终使用整数访问
arr:=Struct("Uint[10]")
arr.5:=10
MsgBox % arr.5
MyArray:="a,b"
arr:=Struct("MyArray[10]")
arr.1.a:=1
arr.2.b:=2
MsgBox % arr.1.a " / " arr.2.b
; 指针示例
; 简单的指针*
int:=Struct("*UInt")
int.SetCapacity(1,4)
int.1.SetCapacity(1,4)
int.1.1:=100
MsgBox % int.1.1
; 指向指针数组的指针
s:=Struct("**UInt")
s.SetCapacity(1,8) ; 指向 uint 的指针的 2 数组
s.1.SetCapacity(1,8),s.1.SetCapacity(2,8)
s.1.1.SetCapacity(1,8),s.1.2.SetCapacity(1,8)
s.1.1.1:=10
s.1.1.2:=20
s.1.2.1:=30
s.1.2.2:=40
MsgBox % s.1.1.1 "`n" s.1.1.2 "`n" s.1.2.1 "`n" s.1.2.2
s[]:=[[[50,60],[70,80]]]
MsgBox % s.1.1.1 "`n" s.1.1.2 "`n" s.1.2.1 "`n" s.1.2.2
; 字符串示例
;简单的用户定义结构
user:="UInt Id, LPTSTR Name"
users := Struct("user[2]") ; 结构体数组
users.1.Id := 1 ,users.2.Id := 2
users.1.Name := "Admin" ,users.2.Name := "User"
MsgBox % users.1.Id "`t" users.1.Name "`n" users.2.Id "`t" users.2.Name
; 我们也可以使用对象来赋值
users[]:=[{id:2,name:"Struct"},{id:2,name:"Object"}]
MsgBox % users.1.Id "`t" users.1.Name "`n" users.2.Id "`t" users.2.Name
; 字符数组
String:=Struct("TCHAR char[26]")
Loop 26
string["char"][A_Index]:=Chr(A_Index+64)
Loop 3
MsgBox % String["char"][A_Index*2] ; 显示一些字符
MsgBox % StrGet(string[],26) ; 获取完整字符串
; 正确的例子
Gui,New,HWNDhwnd
_RECT:="left,top,right,bottom"
RC:=Struct(_RECT) ; 创建结构
Gui,Add,Text,,Press Escape to continue
Gui,Show,w200 h100 ; 显示窗口
DllCall("GetWindowRect","PTR",hwnd,"PTR",rc[]) ; 获取窗口位置
rc.right := rc.right - rc.left ; 将 rc.right 设置为宽度
rc.bottom := rc.bottom - rc.top ; 将 rc.bottom 设置为高度
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
}
ExitApp
; 查找第一个文件示例
_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,UInt 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("FindClose","Uint",handle)
; Process32第一个示例
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 "];"
)
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 150
}
ToolTip
; 列出进程模块示例
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"))
Return
ListProcessModules(dwPID)
{
global _MODULEENTRY32
static TH32CS_SNAPMODULE:=0x00000008,INVALID_HANDLE_VALUE:=-1
me32 := Struct(_MODULEENTRY32)
; 对指定进程中的所有模块创建快照。
hModuleSnap := DllCall("CreateToolhelp32Snapshot","UInt", TH32CS_SNAPMODULE,"PTR", dwPID )
if( hModuleSnap = INVALID_HANDLE_VALUE )
{
MsgBox % "CreateToolhelp32Snapshot (of modules)"
return FALSE
}
; 使用结构之前先设置结构大小。
me32.dwSize := sizeof("_MODULEENTRY32")
; 检索第一个模块的信息,
; 如果失败则退出
if( !DllCall("Module32First" (A_IsUnicode?"W":""),"PTR", hModuleSnap,"PTR", me32[] ) )
{
MsgBox % "Error Module32First`n" ErrorMessage() ; // 显示失败原因
DllCall("CloseHandle","PTR", hModuleSnap ) ; // 必须清理 snapshot 对象!
return FALSE
}
;// 现在遍历该进程的模块列表,
;// 并显示每个模块的信息
while(A_Index=1 || DllCall("Module32Next" (A_IsUnicode?"W":""),"PTR",hModuleSnap,"PTR", me32[""] ) )
{
ToolTip % "`tMODULE NAME`t=`t" StrGet(me32.szModule[""])
. "`n`texecutable`t=`t" StrGet(me32.szExePath[""])
. "`n`tprocess ID`t=`t" me32.th32ProcessID
. "`n`tref count (g)`t=`t" me32.GlblcntUsage
. "`n`tref count (p)`t=`t" me32.ProccntUsage
. "`n`tbase address`t=`t" me32.modBaseAddr[""]
. "`n`tbase size`t=`t" me32.modBaseSize
Sleep 200
}
;// 不要忘记清理 snapshot 对象。
DllCall("CloseHandle","PTR",hModuleSnap)
return TRUE
}
; 枚举一个结构。
; 枚举简单结构
MyStruct:="a,b,c"
s:=Struct(MyStruct,,{a:1,b:2,c:3})
for k, v in s
MsgBox % k ": " v
; 枚举结构数组
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
; 枚举动态结构
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