# 脚本编译器指令

## 目录

- 介绍
- 控制脚本行为的指令:

- IgnoreBegin
- IgnoreEnd
- IgnoreKeep

- 控制可执行文件元数据的指令:

- 介绍
- AddResource: 为 .exe 添加一个资源.
- Bin / Base: 指定使用的 AutoHotkey 的基版本.
- ConsoleApp: 设置 Console 模式.
- Cont: 指定指令的延续行.
- Debug: 显示指令的调试文本.
- ExeName: 指定 .exe 的位置和名称.
- Let: 设置一个用户变量.
- Nop: Does nothing.
- Obey: 执行一个命令或表达式.
- PostExec: 编译后运行程序.
- ResourceID: 为主脚本指定一个非标准的资源 ID.
- SetMainIcon: 设置主图标.
- SetProp: 设置 .exe 的一个属性.
- Set: 设置各种属性.
- UpdateManifest: 更改 .exe 的 manifest.
- UseResourceLang: 更改资源语言.

## 介绍

脚本编译器指令允许用户指定如何通过 Ahk2Exe 编译脚本的细节. 一些功能是:

- 能够改变版本信息(如名称, 描述, 版本...).
- 能够向编译的脚本添加资源.
- 能够调整编译的一些选项.
- 能够从编译的脚本中删除部分代码, 反之亦然.

脚本编译器在源代码中寻找特殊的注释, 并将其识别为编译器指令. 所有的编译器指令都是由字符串 `@Ahk2Exe-` 引入的, 前面有注释标志(通常为 `;`).

## 控制脚本行为的指令

可以通过将已编译脚本中的代码片段包装在指令中来删除它们:

    MsgBox "这条信息同时出现在已编译和未编译的脚本中"
    ;@Ahk2Exe-IgnoreBegin
    MsgBox "这条信息不会出现在编译的脚本中"
    ;@Ahk2Exe-IgnoreEnd
    MsgBox "这条信息同时出现在已编译和未编译的脚本中"

反过来说也是可以的, 即标记代码片段只在编译后的脚本中执行:

    /*@Ahk2Exe-Keep
    MsgBox "这条信息只出现在编译的脚本中"
    */
    MsgBox "这条信息同时出现在已编译和未编译的脚本中"

这比 A_IsCompiled 的优势在于, 在预处理过程中, 代码被完全从编译脚本中移除, 从而使编译脚本更小. 反之亦然: 不需要检查 A_IsCompiled 因为代码在未编译的脚本中的注释块中.

## 控制可执行程序元数据的指令

### 介绍

在这些指令的参数中, 支持以下转义序列: ````, ``,`, ``n`, ``r` 和 ``t`. 无论参数位置如何, 逗号 始终 需要转义. "Integer" 是指无符号的 16 位整数(0..0xFFFF).

如果需要, 指令参数可以通过使用 `%`(百分号) 括住变量名来引用以下标准内置变量列表:

组 1: A_AhkPath, A_AppData, A_AppDataCommon, A_ComputerName, A_ComSpec, A_Desktop, A_DesktopCommon, A_MyDocuments, A_ProgramFiles, A_Programs, A_ProgramsCommon, A_ScriptDir, A_ScriptFullPath, A_ScriptName, A_Space, A_StartMenu, A_StartMenuCommon, A_Startup, A_StartupCommon, A_Tab, A_Temp, A_UserName, A_WinDir.

组 2: A_AhkVersion, A_IsCompiled, A_PtrSize.

除了这些变量名之外, 特殊变量 A_WorkFileName 还保存着处理后的 .exe 文件的临时名称. 这可以用来将文件名作为参数传递给任何需要访问生成的 .exe 文件的 PostExec 指令.

此外, 特殊变量 A_BasePath 包含所选基文件的完整路径和名称.

另外, 特殊变量 A_PriorLine 包含了紧接当前编译器指令之前的源代码行. 只忽略中间的空白行和注释, 以及任何中间的编译器指令行. 这个变量可以用来从脚本源代码中 "提取" 常量信息, 并在以后的编译器指令中使用它. 一个例子是访问脚本的版本号, 因为它可能会经常改变. 以这种方式访问版本号, 意味着在源代码中只需要更改一次, 更改的内容会被复制到必要的指令中. (有关详情, 请参阅下面的 RegEx 示例.)

同样, 也可以使用 Let 和 Obey 指令来创建形如 `U_Name` 的特殊用户变量, 如下所示.

除了可用于指令参数外, 所有变量都可以从任何 RT_MENU, RT_DIALOG, RT_STRING, RT_ACCELERATORS, RT_HTML 和 RT_MANIFEST 文件中访问, 提供给下面的 AddResource 指令.

如果需要, 从上述变量返回的值可以通过在内置变量名称结尾, 结束 `%` 的前面, 包括最多 2 个参数(称为 p2 和 p3) 来进行操作, 所有参数都用波浪号 `~` 分隔. 在 RegExReplace 函数的第 2 个和第 3 个参数中, p2 和 p3 参数将作为原义使用, 以操作返回的值. (请参阅正则快速参考.) 请注意, p3 是可选的.

要在 p2 或 p3 中包含波浪号作为数据, 在其前面加上重音符, 即 ``~`. 要在 p2 或 p3 中包含重音符作为数据, 请将其加倍, 即 ````.

RegEx 示例:

-     %A_ScriptName~\.[^\.]+$~.exe%

  这将在实际的脚本名称中用 `.exe` 替换扩展名加上前面的句号.
  (`\.[^\.]+$~.exe` 表示扫描 `.` 后面跟着的 1 个或多个非-`.` 字符, 并后面跟着结束字符, 并将其替换为 `.exe`)

- 假设有一个源码行后面有两个编译器指令, 如下所示:

      CodeVersion := "1.2.3.4", company := "My Company"

      ;@Ahk2Exe-Let U_version = %A_PriorLine~U)^(.+"){1}(.+)".*$~$2%

      ;@Ahk2Exe-Let U_company = %A_PriorLine~U)^(.+"){3}(.+)".*$~$2%

  这些指令将版本号 `1.2.3.4` 复制到特殊变量 `U_version`, 将公司名称 `My Company` 复制到特殊变量 `U_company` 中, 供后面其他指令使用.
  (第一个正则表达式中的 `{1}` 在第二个正则表达式中改为 `{3}` 以便在第三个 `"` 之后选择提取公司名称.)

其他示例: 其他的工作示例可以从这里下载和检查.

### AddResource

将资源添加到已编译的可执行文件中. (另请参阅下面的 UseResourceLang)

    ;@Ahk2Exe-AddResource FileName , ResourceName

FileName
  要添加的资源的文件名. 如果没有指定绝对路径, 则假定该文件位于(或相对于) 脚本自己的目录中. 资源的类型(作为整数或字符串) 可以通过附加一个星号显式指定: `*type Filename`. 如果省略, Ahk2Exe 会根据文件扩展名自动检测类型.
ResourceName
  (可选) 资源将具有的名称(可以为整数或字符串). 如果省略, 则默认为文件的名称(没有路径), 大写.

以下是常见的标准资源类型和默认触发这些资源类型的扩展名的清单.

- 2 (RT_BITMAP): `.bmp`, `.dib`
- 4 (RT_MENU)
- 5 (RT_DIALOG)
- 6 (RT_STRING)
- 9 (RT_ACCELERATORS)
- 10 (RT_RCDATA): 每一个其他的扩展名.
- 11 (RT_MESSAGETABLE)
- 12 (RT_GROUP_CURSOR): `.cur`(尚未支持)
- 14 (RT_GROUP_ICON): `.ico`
- 23 (RT_HTML): `.htm`, `.html`, `.mht`
- 24 (RT_MANIFEST): `.manifest`. 如果没有指定资源的名称, 则默认为 `1`

示例 1: 替换标准图标(除主图标外):

    ;@Ahk2Exe-AddResource Icon1.ico, 160  ; 替换 '蓝色 H'
    ;@Ahk2Exe-AddResource Icon2.ico, 206  ; 替换 '绿色 S'
    ;@Ahk2Exe-AddResource Icon3.ico, 207  ; 替换 '红色 H'
    ;@Ahk2Exe-AddResource Icon4.ico, 208  ; 替换 '红色 S'

示例 2: 要把另一个脚本作为单独的 RCDATA 资源包括在内(请参阅嵌入式脚本):

    ;@Ahk2Exe-AddResource MyScript1.ahk, #2
    ;@Ahk2Exe-AddResource MyScript2.ahk, MYRESOURCE

注意, 使用此指令添加的每个脚本将由编译器完全单独处理, 并且可以包含更多的指令. 如果有任何相冲突的指令, 编译器将使用最后遇到的那个指令.

### Bin / Base

指定用于生成 .exe 文件的 AutoHotkey 的基础版本. 这个指令可以被 GUI 或 CLI 中指定的基文件参数所覆盖. 如果有必要, 这个指令可以被多次指定, 但只能在最顶层的脚本文件中指定(也就是说, 不能在 #Include 文件中). 编译器将为每个发现的 Bin/Base 指令至少运行一次. (如果要在这个指令上附加一个实际的注释, 必须使用 `;` 标志. 要想真正注释这个指令, 请在第一个注释标志后插入一个空格.)

    ;@Ahk2Exe-Bin  [Path\]Name , [Exe_path\][Name], Codepage ; 不推荐
    ;@Ahk2Exe-Base [Path\]Name , [Exe_path\][Name], Codepage

[Path\]Name
  要使用的 *.bin 或 *.exe 文件. 如果没有提供扩展名, 则假定为 `.bin`. 如果没有指定绝对路径, 则假定该文件位于(或相对于) 编译器自己的目录中. 可以为 Name 指定一个 DOS 掩码, 例如 `ANSI*`, `Unicode 32*`, `Unicode 64*` 或为这三种掩码指定 `*bit`. 编译器将为每个匹配的 *.bin 或 *.exe 文件运行. 任何使用内置变量替换的情况都必须是来自上述的组 1.
[Exe_path\][Name]
  (可选) 要给 .exe 的文件名. 任何提供的扩展名都将被替换为 `.exe`. 如果没有指定路径, 则会在脚本文件夹中创建 .exe 文件. 如果没有指定名称, .exe 将使用默认名称. (这个参数可以被 ExeName 指令覆盖.)
Codepage
  (可选) 覆盖用于处理脚本文件的默认代码页. (脚本应该以 Unicode 字节顺序标记(BOM) 开始, 因此不需要使用这个参数.)

### ConsoleApp

将可执行子系统更改为控制台模式.

    ;@Ahk2Exe-ConsoleApp

### Cont

为前指令指定一个延续行. 这允许格式化一个长行指令, 以便在源代码中容易阅读.

    ;@Ahk2Exe-Cont Text

Text
  在处理前一行指令之前, 要附加到该行的文字. 文本开始于 `Cont` 关键字后面的单个空格之后.

### Debug

显示带有支持文本的消息框, 用于调试.

    ;@Ahk2Exe-Debug Text

Text
  要显示的文本. 在 `%` 符号之间包含的任何特殊变量, 请参阅 (manipulated) 部分的内容.

### ExeName

指定生成的 .exe 文件的位置和名称. (另请参阅 Base 指令.) 这个指令可以被 GUI 或 CLI 中指定的输出文件覆盖.

    ;@Ahk2Exe-ExeName [Path\][Name]

[Path\][Name]
  .exe 文件的名称. 任何提供的扩展名都将被替换为 `.exe`. 如果没有指定路径, .exe 将在脚本文件夹中创建. 如果没有指定名称, .exe 将使用默认名称.

示例:

    ;@Ahk2Exe-Obey U_bits, = %A_PtrSize% * 8
    ;@Ahk2Exe-Obey U_type, = "%A_IsUnicode%" ? "Unicode" : "ANSI"
    ;@Ahk2Exe-ExeName %A_ScriptName~\.[^\.]+$%_%U_type%_%U_bits%

### Let

创建(或修改) 一个或多个用户变量, 这些变量可以通过 `%U_Name%` 来访问, 类似于内置变量(见上文).

    ;@Ahk2Exe-Let Name = Value , Name = Value, ...

Name
  变量的名称(带或不带前缀 `U_`).
Value
  要使用的值.

### Nop

什么也不做.

    ;@Ahk2Exe-Nop Text

Text
  (可选) 任何文本, 会被忽略.

示例:

    Ver := A_AhkVersion "" ; 如果加引号的原义文字不为空, 执行 'SetVersion'
    ;@Ahk2Exe-Obey U_V, = "%A_PriorLine~U)^(.+")(.*)".*$~$2%" ? "SetVersion" : "Nop"
    ;@Ahk2Exe-%U_V%        %A_AhkVersion%%A_PriorLine~U)^(.+")(.*)".*$~$2%

### Obey

执行独立于 AutoHotkey 的命令或表达式, 结果为 `U_Name`.

    ;@Ahk2Exe-Obey Name, CmdOrExp , Extra

Name
  要接收结果的变量名称(带或不带前缀 `U_`).
CmdOrExp

  要执行的命令或表达式.

  Command 格式必须使用 Name 作为输出变量(通常是第一个参数), 例如

      ;@Ahk2Exe-Obey U_date, FormatTime U_date`, R D2 T2

  Expression 格式必须以 `=` 开头, 例如

      ;@Ahk2Exe-Obey U_type, = "%A_IsUnicode%" ? "Unicode" : "ANSI"

  表达式可以用命令格式来写, 例如

      ;@Ahk2Exe-Obey U_bits, U_bits := %A_PtrSize% * 8

  如果需要, 用 ``n` 分隔多个命令和表达式.

Extra
  (可选) 数字(1-9) 指定要返回的额外结果的数量. 例如, 如果 extra = 2, 结果将以 `U_name`, `U_name1` 和 `U_name2` 的形式返回. `name`s 中的值必须先由表达式或命令设置.

### PostExec

指定在编译成功后, 在任何压缩程序应用于 .exe 文件之前(或之后) 要执行的程序. 该指令可以多次出现, 并将按照编译器遇到的顺序, 在由 `When` 参数指定的适当队列中执行.

    ;@Ahk2Exe-PostExec Program [parameters] , When, WorkingDir, Hidden, IgnoreErrors

Program [parameters]
  要执行的程序, 加上参数. 要允许访问已处理的 .exe 文件, 请指定特殊变量 A_WorkFileName 作为加引号的参数, 如 `"%A_WorkFileName%"`. 如果程序更改了 .exe, 则必须将更改的 .exe 移回程序指定的输入文件 `%A_WorkFileName%`. (注意, .exe 将包含二进制数据.)
When

  (可选) 在执行任何压缩之前运行, 则置空. 否则设置为压缩后运行的数字如下:

  - 0 - 仅在没有指定压缩时运行.
  - 1 - 仅在指定 MPRESS 压缩时运行.
  - 2 - 仅在指定 UPX 压缩时运行.
WorkingDir
  (可选) 程序的工作目录. 即使包含空格, 也不要用双引号括起来. 如果省略, 将使用编译器的目录(Ahk2Exe).
Hidden
  (可选) 如果设置为 1, 程序将被隐藏启动.
IgnoreErrors
  (可选) 如果设置为 1, 则不会向用户报告程序启动或运行过程中发生的任何错误.

示例 1: (要使用前两个例子, 首先要下载 BinMod.ahk 并根据下载的脚本中的说明进行编译.)

这个例子可以用来删除生成的 .exe 文件中对 "AutoHotkey" 的引用, 以掩盖它是一个编译过的 AutoHotkey 脚本:

    ;@Ahk2Exe-Obey U_au, = "%A_IsUnicode%" ? 2 : 1    ; Script ANSI or Unicode?
    ;@Ahk2Exe-PostExec "BinMod.exe" "%A_WorkFileName%"
    ;@Ahk2Exe-Cont  "%U_au%2.>AUTOHOTKEY SCRIPT<. DATA              "

示例 2: 这个例子将改变一个 UPX 压缩的 .exe 文件, 使它不能用 `UPX -d` 来解压:

    ;@Ahk2Exe-PostExec "BinMod.exe" "%A_WorkFileName%"
    ;@Ahk2Exe-Cont  "11.UPX." "1.UPX!.", 2

(BinMod.ahk 脚本中还有一些其他的例子.)

示例 3: 如果在 CLI 或 GUI 中没有指定压缩, 则此示例指定要在在编译脚本上使用的压缩程序. 编译器通常使用的默认参数如下所示.

对于 MPRESS:

    ;@Ahk2Exe-PostExec "MPRESS.exe" "%A_WorkFileName%" -q -x, 0,, 1

对于 UPX:

    ;@Ahk2Exe-PostExec "UPX.exe" "%A_WorkFileName%"
    ;@Ahk2Exe-Cont  -q --all-methods --compress-icons=0, 0,, 1

### ResourceID

指定一个非标准的资源 ID, 用于使用 .exe 基文件编译的主脚本(请参阅嵌入脚本). 这个指令可以被 GUI 或 CLI 中指定的资源 ID 所覆盖. 如果该指令出现在由 AddResource 指令插入的脚本中, 则会被忽略.

    ;@Ahk2Exe-ResourceID Name

Name
  要使用的资源 ID. 数字资源 ID 应该由一个哈希符号(#) 和一个十进制数字组成.

### SetMainIcon

覆盖用于编译的自定义 EXE 图标. (要改变其他图标, 请参阅 AddResource 的示例.) 这个指令可以被 GUI 或 CLI 中指定的图标文件覆盖. 如果编译文件之前存在一个不同的图标, 新图标可能不会立即在 Windows 资源管理器中可见, 但是可以通过从 Ahk2Exe 的 `File` 菜单中选择 `Refresh Windows Icons` 来显示新图标.

    ;@Ahk2Exe-SetMainIcon IcoFile

IcoFile
  (可选) 要使用的图标文件. 如果省略, 则使用默认的 AutoHotkey 图标.

### SetProp

更改已编译可执行文件的版本信息中的属性. 注意, 无论指定属性的顺序如何, 所有属性都按字母顺序处理.

    ;@Ahk2Exe-SetProp Value

Prop

  要更改的属性的名称. 必须是下列名单之一.

  属性 | 描述
  --- | ---
  CompanyName | 更改公司名称.
  Copyright | 更改法定版权信息.
  Description | 更改文件说明. 在 Windows 8 及以上版本中, 这也会改变任务管理器中 "Processes" 下的脚本名称.
  FileVersion | 更改文件版本, 包括文本和原始二进制格式. (有关详情, 请参阅下面的 Version.)
  InternalName | 更改内部名称.
  Language | 更改语言代码. 请注意, 十六进制数字必须有 `0x` 前缀.
  LegalTrademarks | 更改合法商标信息.
  Name | 更改产品名称和内部名称.
  OrigFilename | 更改原始文件名信息.
  ProductName | 更改产品名称.
  ProductVersion | 更改产品版本, 包括文本和原始二进制格式. (有关详情, 请参阅下面的 Version.)
  Version | 更改文件版本和产品版本, 包括文本和原始二进制格式. Ahk2Exe 用可能出现在版本文本开头的以周期限定的数字(最多 4 个) 填充二进制版本字段. 未填写的字段被设置为零. 例如, `1.3-alpha` 会产生 `1.3.0.0` 的二进制版本号. 如果这个属性没有被修改, 它默认为用于编译脚本的 AutoHotkey 版本.

Value
  要设置属性的值.

### Set

改变 SetProp 指令未覆盖的编译后的可执行文件版本信息中的其他杂项属性. 请注意, 所有的属性都是按字母顺序处理的, 而不考虑它们被指定的顺序. 此指令仅用于特殊用途.

    ;@Ahk2Exe-Set Prop, Value

Prop
  要更改的属性名称.
Value
  属性将设置的值.

### UpdateManifest

更改 .exe 清单中的详细信息. 此指令仅供特殊用途.

    ;@Ahk2Exe-UpdateManifest RequireAdmin , Name, Version, UIAccess

RequireAdmin
  设置为 1, 可执行文件运行时需要管理员权限. 设置为 2, 可执行文件运行时请求最高可用权限. 设置为 0, 则保持不变.
Name
  (可选) 要在清单中设置的名称.
Version
  (可选) 要在清单中设置的版本.
UIAccess
  (可选) 设置为 1, 使清单中的 UIAccess 为 true.

### UseResourceLang

更改 AddResource 使用的资源语言. 这条指令是位置性的, 会影响它后面所有的 AddResource 指令.

    ;@Ahk2Exe-UseResourceLang LangCode

LangCode
  语言代码. 请注意, 十六进制数字必须带有 `0x` 前缀. 默认的资源语言是美国英语(0x0409).

dftg