# DllCall() （调用动态链接库文件）

该命令可以调用一个DLL文件中的函数，例如标准的Windows API 函数。

Result := DllCall("[DllFile\]Function" [, Type1, Arg1, Type2, Arg2, "Cdecl ReturnType"])

#### 参数

Result | DllCall 返回调用函数的返回值。如果该函数没有返回值，则结果是未定义的整数类型。如果函数在调用是发生错误error，则返回值为空（即一个空的字符串类型）。
[DllFile\]Function | 要调用的函数可表示为，DLL或者EXE文件的名字加上反斜杠 \ 再加上函数名。例如：“MyDLL\MyFunction”（如果未指明文件的后缀，则默认其为".dll"文件）。如果不是一个绝对路径，则假定DllFile （DLL 文件）在系统目录或者在 A_WorkingDir （当前工作目录）。 如 果该函数在 User32.dll, Kernel32.dll, ComCtl32.dll, Gdi32.dll 这几个DLL文件中，则DllFile文 件名可以被忽略。例如 "User32\IsWindowVisible" 等同于 "IsWindowVisible"。对于那些标准的DLL文件，其 API函数的后缀“A”字母也可以被忽略。如"MessageBox" 等同于"MessageBoxA" 。 对于重复调用的情况，使用 loading it beforehand （预先装载DLL文件），可对执行效 率有显著的改善。 在v1.0.46.08+版本中，这个参数也可以是指向需要调用函数的内存地址的整数。如 COM 和 RegisterCallback() 所提供的地址。
Type1, Arg1 | 这样的每一对数据，表示需要传递给函数的一个参数。参数的个数没有限制。Type 是用来描述传递参数的类型，具体见下表 types table （参数的类型的描述）说明， Arg 是给函数传递的参数的具体数值。
Cdecl ReturnType | Cdecl：该参数一般被忽略，因为大多数函数使用的是标准调用习惯而很少是符合“C”标准的调用习惯。如果在忽略这个参数后， 产生了错误信息 ErrorLevel An，n 表示你传递参数的个数，你可能需要填上Cdecl 参数，声明为以 C 语言方式调用。 如果需要在返回的类型前面增加参数Cdecl 时， 请用空格或tab将他们分开，如：“Cdecl Str” ReturnType （返回值的类型）：如果该函数值类型是一个32-bit的有符号整型（Int），BOOL，或是无返回值，ReturnType 可以被忽略。否则必须从下表中 types table 指定一个参数类型。也支持传址传递 asterisk suffix 。

#### 参数及返回值的类型描述

Str | 表示该参数是一个如"Blue" 或 MyVar 的字符串类型。如果函数需要修改这个字符串，或这参 数是个不被保护的变量，他其中的内容会被更新。例如，下面的代码将变量 MyVar 里的内容改为大写：DllCall("CharUpper", "str", MyVar) 。 然而，如果函数需要储存一个超过当前变量容量的大型字符串，确保在调用函数前该变量的容量足够大。这个可以通过调用函数 VarSetCapacity(MyVar, 123) 来实现，其中123是为变量MyVar 保留的容量。 一个 str 的参数不能是一个赋值的表达式（如 i+1），如果那样，函数将不能成功调用，并且，错误信息会设置为-2。 str 类型一般用于描述参数为 LPSTR, LPCSTR, LPTSTR, char * 或类似的类型。 同样支持星号后缀 "str *" asterisk variable （传址引用类型），但很少使用。他被用于参数类似于"char **" 或 "LPSTR *"的类型。
Int64 | 表示该参数是一个64-bit 的整型，其范围是 -9223372036854775808 (-0x8000000000000000) 到 9223372036854775807 (0x7FFFFFFFFFFFFFFF)
Int | 表示该参数是一个32-bit的整数类型（参数大多数情况为整数类型），其范围是 -2147483648 (-0x80000000) 到 2147483647 (0x7FFFFFFF)。Int 有时也写作“Long”。 Int 也用于描述 BOOL 类型的参数（BOOL 类型的参数值只能是1或0）。 无符号整型 unsigned (UInt)也是使用频繁的类型，可以表示如 DWORD 和 COLORREF 类型。他也被用于所有的句柄类型，如HWND, HBRUSH, 和 HBITMAP 类型。 注意：如要传递的值是 NULL 或是指针，可传递整数 0 。
Short | 表示参数为 16-bit 的整型，其范围是 -32768 (-0x8000) 到 32767 (0x7FFF)。一个无符号短整型 unsigned Short (UShort) 可用于函数的参数为WORD类型。
Char | 表示参数为 8-bit 的整型，其范围是 -128 (-0x80) 到 127 (0x7F）。一个无符号字符 unsigned character (UChar)可用于函数的参数为BYTE类型。
Float | 表示参数为 32-bit 的浮点型，具有6位精确度。
Double | 表示参数为 32-bit 的浮点型，具有15位精确度。
* or P (suffix) | 在上述类型后，附加一个星号（可以在之前有空格）表示函数的参数需要传递的是变量的地 址而不是变量的数值（当然函数原型要接受该类型的参数）。该参数的值有可能会被函数修改，一个未被保护的变量作为一个参数传入，其内容也会随时被更新。例 如，下面的例子向函数MyFunction传递了变量MyVar的地址，其变量 MyVar 可以被MyFunction 函数随时更新以反映其变化：DllCall("MyDll\MyFunction", "int *", MyVar) 一般来说，星号可用于描述任何参数类型或返回类型是以 "LP" 开头的（字符串类型 LPSTR 除外，他应使用 "str" 类型）。例如常见的 LPDWORD，他就是指向 DWORD 类型变量的指针类型。DWORD 是一个32-bit的整型，所以用"UInt *" 或 "UintP"来表示 LPDWORD 类型。 注意："char *"与 "str" 的类型是不一样的，因为 "char *" 传递的是是一个8-bit数字的地址，但 "str" 传递的是一个序列字符的地址。并且对于函数需要向变量储存数据的传址引用类型的参数，不需要调用 VarSetCapacity 来设置其容量。
U (prefix) | 在上述的整数类型前加上前缀 "U" 表示无符号整型 ( 如 UInt64, UInt, UShort 和 UChar )。严格地说，这只对返回值类型和传址引用类型有必要，因为有符号或无符号对参数的传递没有影响（Int64除外）。 一个32-bit的无符号整型 (UInt) 可以替代如 DWORD, HWND, 或类似的类型。一个 HWND 值（窗口句柄）和窗口的 unique ID 也是一样的。 如果把一个负数类型当成一个无符号整数，则这个负整数会被转换到无符号的范围内。例如，把 -1 作为一个无符号类型UInt，他的值会变成 0xFFFFFFFF。然而，这种情况对于 64-bit整数 (UInt64) 不成立。 对由一个函数产生的无符号64-bit整型不完全支持 。对于大于或等于0x8000000000000000的数，若省略前缀 U 后，则会将函数得到的任何负数，转换成一个很大的正数。例如一个被设计其返回值为 UInt64（64位整型）类型的函数，返回结果为 Int64 类型的 -1，则脚本实际返回的值将是0xFFFFFFFFFFFFFFF。

注意： 当描述一个不包含空格或星号的参数类型或是返回值类型时，其引号可以忽略，如，str 与 "str" 等同，CDecl 与 "CDecl" 等同。另外，字母 P 可以替代星号，以便允许忽略其周围的引号。如：UIntP。

#### ErrorLevel 错误信息

ErrorLevel 会赋值为以下几种情况中的一个，不论调用成功或是失败。

0: 成功。

-1 (负1): 函数 [DllFile\]Function 的参数是一个浮点类型。需要一个字符串或是一个正数的参数。

-2: return type （返回值类型）或一个描述参数类型的 arg types 数据无效。这个错误可能是因为向字符串（str）类型变量传递了一个赋值表达式所引起的。

-3: 指定的 DLL文件不能够使用。若没有指定DLL文件的路径，则文件不存在于系统目录或是 A_WorkingDir（当前工作目录）。这个错误也可能是因为用户没有读取文件的权限所引起的。

-4: 无法在DLL文件中找到指定的函数。

N (任意正数)：表示函数被调用，但发生了异常错误，错误序号为 N （例如，0xC0000005 表示“读取错误”）。这种情况下函数会返回一个空值（空字符串），但传址引用类型的变量会被更新。例如可能是因为引用了一个无效的 NULL 指针而导致的异常错误。由于 Cdecl 函数不可能产生"An" 错误（下一段提到），也可能是因为传入的参数过少而产生了异常。

An（字母 A 后面加一个整数 n）：表示函数被调用，但传入的参数过少。"n" 表示错误参数列表的字节数。如果 n 为正数，表示传入的参数类型太多（或是参数类型太大），也有可能是函数调用需要 CDecl 声明。如果 n 是负数，表示传入的参数类型太少。这种情况可以通过改正参数类型来保证函数的正常运行。若函数返回值为空，也可能是因为产生了异常而导致的错误。

#### 异常和 A_LastError

尽管具有内建的异常处理机制，但仍有可能因为使用 DllCall 而使脚本假死。这种情况会产生于，当函数不是直接产生了异常而是产生了一些不恰当的数据，如产生了一个野指针或是一个没有结束符的字符串。这可能不是因为 函数本身产生的错误，而是脚本传入了一个不恰当的参数，例如一个野指针或是一个容量不足的字符串 "str" 。当对参数类型或返回类的型描述不恰当的时，也可能使脚本假死。例如把一个普通的整数类型错误的声明为一个传址引用类型 asterisk variable 或是 str 。

内建的变量 A_LastError 包含了系统函数 GetLastError() 返回的结果。该函数会在函数调用后被立即执行（对效率的影响不可知）。A_LastError 是一个介于 0 与 4294967295 之间的数（通常以十进制表示而不是十六进制）。像 ErrorLevel 一样，A_LastError 也是一个独立的线程。也就是说其他的线程 threads 无法中断他。然而 A_LastError 可受到 Run/RunWait 的影响。

#### 性能

当需要重复调用 DLL 时，事先明确的装载可以显著提高运行效率（标准的 standard DLL 如 User32 文件可以不需要，因为他们总是挂起的）。以下是一个在每次调用 DllCall 时不需要重复进行 LoadLibrary 和 FreeLibrary 的例子：

    hModule := DllCall("LoadLibrary", "str", "MyFunctions.dll") ; 避免了每次在循环中调用 DllCall() 时都进行装载文件。
    Loop, C:\My Documents\*.*, , 1
    result := DllCall("MyFunctions\BackupFile", "str", A_LoopFileFullPath)
    DllCall("FreeLibrary", "UInt", hModule) ; 为了释放内存，DLL 在使用完后进行卸载。

在 1.0.46.08+ 版本中，通过预先查找函数的地址甚至可以获得更快的性能。例如：

    ; 在下面的例子中，如果 DLL 还没有没加载，使用 LoadLibrary 替换 GetModuleHandle 。
    MulDivProc := DllCall("GetProcAddress", uint, DllCall("GetModuleHandle", str, "kernel32"), str, "MulDiv")
    Loop 500
        DllCall(MulDivProc, int, 3, int, 4, int, 3)

最后，向一个函数传入一个字符串变量，不会改变字符串的长度，如果将变量的地址 by address （如，&MyVar）传递给函数而不是以字符串 "str" （特别是一些长字符串）的形式，可以提高运行效率。以下是一个将字符串改写为大写的例子：DllCall("CharUpper", uint, &MyVar)

#### 结构体和数组

一个结构体是一些成员变量（空间）在内存中连续排列的集合。大多数成员变量是整型。

一些函数可以接受结构体的地址（或是一个内存块数组）的类型参数，可以调用他以二进制的形式向结构体写入数据。一般步骤如下：

1）调用 VarSetCapacity(MyStruct, 123, 0) 确保目标变量足够大以便储存结构体数据。将 123 替换为结构体的大小。后面的 0 是可选项；他会初始化所有的成员变量为二进制形式的 0 ，这样通常可以有效的避免在下一步频繁的调用 NumPut() 。

2）如果目标函数需要其结构体变量初始化，调用 NumPut(123, MyStruct, 4) 初始化其中的每个成员变量为非 0 数据 。替换 123 为需要向成员变量存入的整数（或使用 &Var 形式存入一个变量的地址 address）。替换 4 为成员变量的偏移量（“偏移量”请详见第四步）。

3）调用目标函数，以 UInt 类型的形式传递结构体 MyStruct 的地址 address 。例如 DllCall("MyDll\MyFunc", UInt, &MyStruct) 。函数调用后会检查、改变一些传入的结构体成员变量。

4）利用 MyInteger := NumGet(MyStruct, 4) 命令从结构体中获取想要的成员变量。替换 4 为目标成员变量在结构体中的偏移量。第一个成员变量的偏移量总是 0 。第二个成员变量的偏移量为第一个成员变量的偏移量 0 加上第一个成员变量的大小（一般为 4 字节）。后面的成员变量的偏移量等于前一个成员变量的偏移量加上前一个成员变量的大小。大多数成员变量 -- 如DWORD, Int 和 other types of 32-bit integers （其他32位整型）其大小都是 4 字节 。

参见 Structure Examples 结构体详细用法的例子。

#### 已知的局限性

当一个 variable's address 函数的地址（如 &MyVar）传递给一个函数时，这个函数改变了这个变量内容的长度，如果在此时使用了这个变量，可能就会产生错误。想要解决这个问题，有以下两种方法：1）使用 "str" 类型而不是 uint/address 类型；2）在 v1.0.44.03+ 版本，在调用 DllCall 命令后，使用 VarSetCapacity(MyVar, -1) 命令更新变量的内部容量。

任何存入二进制数据 0 的变量都会被函数隐藏掉其右边的 0 ；这种情况下的数据不能被多数的命令或函数改变或使用。但可以被当作地址或解引用(& and *)及 DllCall 自身操作。

当一个字符串传入函数后，该函数可能会返回一个地址不同但内容相同的字符串。例如在某些程序中调用 CharLower(CharUpper(MyVar)) 可以将 MyVar 里的内容转换为小写，但当在脚本中调用 DllCall() 完成相同的功能后，MyVar 里的内容可能仍是大写的，这是因为 CharLower 函数是对一个与 MyVar 内容相同的临时字符串变量进行操作（而不是直接对变量 MyVar 操作）。

    MyVar = ABC
    result := DllCall("CharLower", str, DllCall("CharUpper", str, MyVar, str), str)

如果想让以上的代码直接对变量 MyVar 中的内容进行修改，可以将以上两个带有下划线的 "str" 改为 UInt。这种改变会将 CharUpper 函数的返回值转换为地址，然后再以整数类型传递给函数 CharLower 。

#### VBScript, JScript 和 组件对象模型（COM）

VBScript 和 JScript 可以通过 Windows Scripting for AutoHotkey（AHK 中的 Window 脚本）嵌入到AHK脚本中，他们是通过访问COM组件来完成的。

同样，可直接调用 DllCall 命令来使用COM对象，参考范例：www.autohotkey.com/wiki/index.php?title=COM_Wrappers

#### 相关命令

PostMessage, OnMessage(), RegisterCallback(), Run, VarSetCapacity, Functions, SysGet, MSDN Library

#### 示例

    ; 例子：调用Windows API 函数 "MessageBox" 并报告用户按下了哪个按钮。
    WhichButton := DllCall("MessageBox", "int", "0", "str", "Press Yes or No", "str", "Title of box", "int", 4)
    MsgBox You pressed button #%WhichButton%.

    ; 例子：改变桌面为指定的Bitmap文件（.bmp）文件。
    DllCall("SystemParametersInfo", UInt, 0x14, UInt, 0, Str, A_WinDir . "\winnt.bmp", UInt, 2)

    ; 例子：调用API函数 "IsWindowVisible" 来判断记事本窗口是否可见。
    DetectHiddenWindows On
    if not DllCall("IsWindowVisible", "UInt", WinExist("无标题 - 记事本"))
    ; WinExist()函数返回窗口的句柄。
    MsgBox 窗口不可见

    ; 例子：调用 API 的 wsprintf() 函数，在一个长度为 10 字节的字符串中填上432，其他空位用 0 填充，也就是(0000000432)。
    VarSetCapacity(ZeroPaddedNumber, 20) ;确保变量的容量足够大以便能够容纳新的字符串。
    DllCall("wsprintf", "str", ZeroPaddedNumber, "str", "%010d", "int", 432, "Cdecl") ;需要声明 Cdecl 的调用方法。
    MsgBox %ZeroPaddedNumber%

    ; 例子：调用 QueryPerformanceCounter() 函数的一个示范，他提供了比 A_TickCount's 的 10ms 更精确的计时器。
    DllCall("QueryPerformanceCounter", "Int64 *", CounterBefore)
    Sleep 1000
    DllCall("QueryPerformanceCounter", "Int64 *", CounterAfter)
    MsgBox % "Elapsed QPC time is " . CounterAfter - CounterBefore

    ; 例子: 这是一个用快捷键来减慢鼠标的移动速度，以便能够精确的定位。
    ; 按下F1键降低移动速度，释放回复原来的速度。
    F1::
    SPI_GETMOUSESPEED = 0x70
    SPI_SETMOUSESPEED = 0x71
    ; 得到当前鼠标的速度以便稍后恢复：
    DllCall("SystemParametersInfo", UInt, SPI_GETMOUSESPEED, UInt, 0, UIntP, OrigMouseSpeed, UInt, 0)
    ; 现在降低鼠标的移动速度，第三个参数为速度设定（范围是1-20，10为默认值）：
    DllCall("SystemParametersInfo", UInt, SPI_SETMOUSESPEED, UInt, 0, UInt, 3, UInt, 0)
    KeyWait F1 ; 这句话可防止按键重复调用 DllCall。
    return
    F1 up::DllCall("SystemParametersInfo", UInt, 0x71, UInt, 0, UInt, OrigMouseSpeed, UInt, 0); 恢复原来的鼠标速度

    ; 例子：当传入一个窗口的 ID 和其控件的类名或控件上的文字
    ; 下面的函数就可以返回该控件的 HWND（句柄）。
    ; 在v1.0.43.06+版本中:下面的命令能够更准确的完成该例子的功能。（该例子省略）
    ControlGet, OutputVar, Hwnd,, ClassNN, WinTitle

    ; 例子：监视活动窗口并显示其垂直滚动条的位置。
    ; 因为焦点控件随时更新，所以需要用到 v1.0.43.06+ 本版中的 ControlGet Hwnd 命令。

    #Persistent
    SetTimer, WatchScrollBar, 100
    return

    WatchScrollBar:
    ActiveWindow := WinExist("A")
    if not ActiveWindow ; No active window.
    return
    ControlGetFocus, FocusedControl, ahk_id %ActiveWindow%
    if not FocusedControl ; No focused control.
    return
    ; 在 ToolTip 中显示垂直或水平滚动条的位置：
    ControlGet, ChildHWND, Hwnd,, %FocusedControl%, ahk_id %ActiveWindow%
    ToolTip % DllCall("GetScrollPos", "UInt", ChildHWND, "Int", 1)
    ; 最后一个参数若为 1 表示 SB_VERT 垂直滚动条,为 0 表示 SB_HORZ 水平滚动条。
    return

    ; 例子：这个脚本向文件中写入一些文字，然后再把它们读入到内存中。(需要 v1.0.34+ 版本).
    ; 这个方法可以实现对一个文件同时并发读写的操作。
    FileSelectFile, FileName, S16,, Create a new file:
    if FileName =
    return
    GENERIC_WRITE = 0x40000000 ; Open the file for writing rather than reading.
    CREATE_ALWAYS = 2 ; 创建新文件 (如果该文件存在则覆盖).
    hFile := DllCall("CreateFile", str, FileName, Uint, GENERIC_WRITE, Uint, 0, UInt, 0, UInt, CREATE_ALWAYS, Uint, 0, UInt, 0)
    if not hFile
    {
     MsgBox 不能对文件 "%FileName%" 进行写操作
     return
    }
    TestString = This is a test string.`r`n ; 向新文件中写入文字，使用 `r`n（不要用 `n ）来表示新的一行
    DllCall("WriteFile", UInt, hFile, str, TestString, UInt, StrLen(TestString), UIntP, BytesActuallyWritten, UInt, 0)
    DllCall("CloseHandle", UInt, hFile) ; Close the file.
    ; 现在文件已经成功的写入，再把它的内容读到内存中来
    GENERIC_READ = 0x80000000 ; 以读取方式而不是写入方式来打开文件
    OPEN_EXISTING = 3 ; 这个参数表示要打开的文件必须存在
    FILE_SHARE_READ = 0x1 ; 这一行以及下一行表示，允许其他进程在我们打开文件的同时也能够打开该文件
    FILE_SHARE_WRITE = 0x2
    hFile := DllCall("CreateFile", str, FileName, UInt, GENERIC_READ, UInt, FILE_SHARE_READ|FILE_SHARE_WRITE, UInt, 0, UInt, OPEN_EXISTING, Uint, 0, UInt, 0)
    if not hFile
    {
     MsgBox 不能够读取文件 "%FileName%"
     return
    }
    ; 清空变量以便能够检查是否正确读入，但要确保该变量的容量可以容纳将要读入的文字
    BytesToRead := VarSetCapacity(TestString, StrLen(TestString))
    DllCall("ReadFile", UInt, hFile, str, TestString, UInt, BytesToRead, UIntP, BytesActuallyRead, UInt, 0)
    DllCall("CloseHandle", UInt, hFile) ; Close the file.
    MsgBox 以下是读取文本的内容: %TestString%

    ; 例子：当按下 Win+C 时隐藏鼠标指针，再次压下时显示。
    ; 这个脚本来自 www.autohotkey.com/forum/topic6107.html
    OnExit, ShowCursor ; 确保当脚本退出时，鼠标指针可见。
    return
    ShowCursor:
    SystemCursor("On")
    ExitApp
    #c::SystemCursor("Toggle") ; Win+C 快捷键切换显示和隐藏
    SystemCursor(OnOff=1) ; 初始化= "I"或"Init"; 隐藏 = 0 或 "Off"; 相反 = -1 或 "T" 或 "Toggle"; 显示 = 其他
    {
    static AndMask, XorMask, $, h_cursor
    ,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13 ; 系统指针
    , b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13 ; 空白指针
    , h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13 ; 默认指针的句柄
    if (OnOff = "Init" or OnOff = "I" or $ = "") ; 请求或第一次调用时初始化
    {
    $ = h ; active default cursors
    VarSetCapacity( h_cursor,4444, 1 )
    VarSetCapacity( AndMask, 32*4, 0xFF )
    VarSetCapacity( XorMask, 32*4, 0 )
    system_cursors = 32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650
    StringSplit c, system_cursors, `,
    Loop %c0%
    {
    h_cursor := DllCall( "LoadCursor", "uint",0, "uint",c%A_Index% )
    h%A_Index% := DllCall( "CopyImage", "uint",h_cursor, "uint",2, "int",0, "int",0, "uint",0 )
    b%A_Index% := DllCall("CreateCursor","uint",0, "int",0, "int",0
    , "int",32, "int",32, "uint",&AndMask, "uint",&XorMask )
    }
    }
    if (OnOff = 0 or OnOff = "Off" or $ = "h" and (OnOff < 0 or OnOff = "Toggle" or OnOff = "T"))
    $ = b ; 使用空白指针
    else
    $ = h ; 使用储存的指针
    Loop %c0%
    {
    h_cursor := DllCall( "CopyImage", "uint",%$%%A_Index%, "uint",2, "int",0, "int",0, "uint",0 )
    DllCall( "SetSystemCursor", "uint",h_cursor, "uint",c%A_Index% )
    }
    }

    ; 结构体例子：把结构体 RECT 的地址传递给 GetWindowRect() 函数。
    ; 完成把窗口的左，上，右，下（相对与屏幕的位置）储存到该结构体的成员中。
    Run Notepad
    WinWait 无标题 - 记事本 ; 也可以设置为 "last found window" 使用 WinExist() 得到记事本句柄
    VarSetCapacity(Rect, 16) ; 一个 RECT 结构体包含了 4 个 32-bit 的整型，（其容量为 4×4=16）
    DllCall("GetWindowRect", UInt, WinExist(), UInt, &Rect) ; WinExist() 函数返回一个句柄
    MsgBox % "Left " . NumGet(Rect, 0, true) . " Top " . NumGet(Rect, 4, true)
     . " Right " . NumGet(Rect, 8, true) . " Bottom " . NumGet(Rect, 12, true)

    ; 结构体例子：向函数 FillRect() 传递一个 RECT 结构体，在屏幕上临时画出红色矩形
    VarSetCapacity(Rect, 16, 0) ; 设置容量为 4 个 4 字节的整型即 16 ，并初始化为 0 。
    NumPut(A_ScreenWidth//2, Rect, 8) ; 第三个整数在结构体中为 "rect.right"
    NumPut(A_ScreenHeight//2, Rect, 12) ; 第四个整数在结构体中为s "rect.bottom".
    hDC := DllCall("GetDC", UInt, 0) ; 传入 0 获得桌面的设备上下文
    hBrush := DllCall("CreateSolidBrush", UInt, 0x0000FF) ; 创建一个红色画刷（0x0000FF 是RGB格式的红色）
    DllCall("FillRect", UInt, hDC, Str, Rect, UInt, hBrush) ; 用上面创建的画刷填充指定的矩形
    DllCall("ReleaseDC", UInt, 0, UInt, hDC) ; 释放 DC
    DllCall("DeleteObject", UInt, hBrush) ; 释放画刷

    ; 结构体例子：改变系统时间为指定的日期，请注意如果时间改为未来的日期，可能使一些软件过早的运行计划的任务。
    SetSystemTime("20051008142211") ; 传入一个 timestamp 参数 （本地时间 Local 而非全球时间 UTC ）
    SetSystemTime(YYYYMMDDHHMISS)
    ; 设置系统时间为指定日期时间，调用必须确保传入的参数是一个有效的时间格式数据（本地时间而非全球时间)
    ; 返回值为非零表示调用成功，否则为失败
    {
    ; 把时间参数从 local 转换为 UTC 以便 SetSystemTime() 函数能够调用
    UTC_Delta -= %A_NowUTC%, Seconds ; 四舍五入使秒更加精确
    UTC_Delta := Round(-UTC_Delta/60) ; 四舍五入使分更加精确
    YYYYMMDDHHMISS += %UTC_Delta%, Minutes ; 把时间转换为UTC格式
    VarSetCapacity(SystemTime, 16, 0) ; 这个结构体是由 8 个 UShorts 组成，所以容量为 8×2=16
    StringLeft, Int, YYYYMMDDHHMISS, 4 ; YYYY (年)
    NumPut(Int, SystemTime, 0, 2)
     StringMid, Int, YYYYMMDDHHMISS, 5, 2 ; MM (月份, 1-12)
    NumPut(Int, SystemTime, 2, 2)
    StringMid, Int, YYYYMMDDHHMISS, 7, 2 ; DD (日)
    NumPut(Int, SystemTime, 6, 2)
    StringMid, Int, YYYYMMDDHHMISS, 9, 2 ; HH (小时 0-23)
    NumPut(Int, SystemTime, 8, 2)
    StringMid, Int, YYYYMMDDHHMISS, 11, 2 ; MI (分)
    NumPut(Int, SystemTime, 10, 2)
    StringMid, Int, YYYYMMDDHHMISS, 13, 2 ; SS (秒)
    NumPut(Int, SystemTime, 12, 2)
    return DllCall("SetSystemTime", UInt, &SystemTime)
    }

    更多结构体的例子：
    1）WinLIRC client script 的范例，介绍了如何使用 DllCall() 来完成 TCP/IP 服务器端和客户端的数据交互和网络链接。
    2）在 www.autohotkey.com/forum/topic17230.html 这里介绍了如何利用结构体来使用系统提供的标准对话框，如字体，颜色，图标的选取对话框。

BLooM.2 Fantasy OnLine 08.07.30 翻译