VBA 大师
0. 先把三个常见误解纠正掉
- VBA 不等于「录制宏」。录制宏产出的是
Select/Activate串联的脆弱代码,换个工作表就失效。真正的 VBA 代码直接持有对象引用、用数组批量搬运数据、带错误处理与环境恢复。 - VBA 不等于 VB6 / VB.NET。它是嵌在宿主进程里的 COM 脚本层,运行在单线程套间(STA),代码随文档分发,没有独立可执行文件,也没有继承、泛型、异常对象。
Long在 64 位 Office 里仍是 32 位整数。 - VBA 不等于「只能操作 Excel」。同一语言运行时也存在于 Word、Outlook、Access、PowerPoint,以及 AutoCAD、SOLIDWORKS、CorelDRAW 等第三方宿主;差异在对象模型,语言核心是共通的。
一条取舍判据:公式、透视表、Power Query 能解决的,不要写 VBA。需要跨文件/跨应用编排、自定义窗体、系统 API、事件驱动或可复用工程时,才是 VBA 的主场。
1. 何时使用
- 「零基础怎么学 VBA」「有没有从入门到高阶的路线」「中文教程在哪」。
- 写代码时卡住:Range 读写慢、字典报 429、JSON 解析不了、中文写文件乱码、64 位 API 声明报错。
- 想找某个能力的可复用实现:JSON、HTTP、ADO、正则、进度条、UserForm、Ribbon、单元测试。
- 要把 VBA 变成可维护工程:错误处理、日志、调用栈、源码导出、Git、代码签名、加载项部署。
- 评估「这套 VBA 还要不要继续写」:twinBASIC / xlwings / Excel-DNA / Open XML 的迁移对照。
- 需要宏安全与防御性分析:提取、解析、检测文档里的宏(仅防御与取证方向)。
不适用:需要实时遍历 GitHub 全量新仓库(本技能是固定快照,见第 8 节);需要 AI 代为执行宏或生成可直接投放的攻击性文档(见第 9 节)。
2. 快速路由
| 你要做什么 | 看哪份 | 或直接用脚本 |
|---|---|---|
| 规划学习顺序、定阶段目标 | references/10-learning-path.md |
find_vba.py --level beginner |
| 查语法、类型、过程、数组、对象模型 | references/20-core-techniques.md |
find_vba.py --cat official |
| 类模块、接口、WinAPI、COM、内存、64 位 | references/30-advanced-techniques.md |
find_vba.py --cat interop --level advanced |
| 直接抄一段能跑的配方 | references/40-cookbook.md |
find_vba.py json |
| 排查「明明没错却结果不对」 | references/50-pitfalls.md |
— |
| 错误处理、测试、Git、部署、跨平台 | references/60-engineering.md |
find_vba.py --cat quality --cat vcs |
| 迁移到 twinBASIC / Python / .NET | references/80-modernization.md |
find_vba.py --cat modern |
| 按主题找 GitHub 仓库 | references/70-repos-by-category.md |
find_vba.py --cats |
| 数据边界与统计 | references/00-index.md |
find_vba.py --stats |
3. 七阶能力模型
| 阶 | 名称 | 能做出什么 | 通过标准 |
|---|---|---|---|
| L0 | 环境与宏基础 | 区分 .xlsx/.xlsm/.xlsb/.xlam,打开 VBE,理解宏安全与信任中心 |
能解释为什么 .xlsx 存不住宏,并能手动运行一个 Sub |
| L1 | 语言核心 | 变量、类型、过程、控制流、数组、字符串、日期、错误处理 | 不看录制宏,手写一个带参数与返回值的 Function |
| L2 | Office 对象模型 | Application / Workbook / Worksheet / Range / ListObject / 事件 | 不用 Select 完成跨表复制,并说清 ThisWorkbook 与 ActiveWorkbook 的区别 |
| L3 | 数据结构与算法 | Dictionary / Collection / 二维数组 / 排序 / 查找 / 正则 | 把 10 万行逐格循环改成一次数组读写,耗时下降一个数量级 |
| L4 | 工程化 | 统一错误处理、日志、单元测试、源码导出、Git、加载项与签名 | 一个 .xlam 加载项,代码能 diff、能跑测试、能回滚 |
| L5 | 高阶互操作 | WinAPI / COM / ADO / HTTP / JSON / Ribbon / 接口 / 64 位兼容 | 同一份代码在 32/64 位 Office 都能跑,且能调用外部 DLL 与 REST API |
| L6 | 现代化与迁移 | 判断哪些逻辑该留在 VBA、哪些该迁到 twinBASIC / Python / .NET | 给出带成本与风险对比的迁移方案,而不是「一律重写」 |
详细周表、每阶练习与验收见 references/10-learning-path.md。
4. 十二条硬规则(写代码前先看)
- 每个模块第一行
Option Explicit,并在 VBE 勾选 Require Variable Declaration。 - 计数与行号一律
Long。VBA 的Integer只有 16 位(−32768…32767),超过 32767 行直接溢出;64 位 Office 里Long仍是 32 位,够覆盖 Excel 的 1048576 行。 - 数据批量走数组:
arr = ws.Range(...).Value2→ 处理 →.Resize(...).Value2 = arr。禁止在循环里逐格读写.Cells(i, j)。 - 不写
Select/Activate/ActiveCell/Selection,直接持有Worksheet/Range对象变量。 - 用
Value2而不是Value:后者会做 Currency/Date 转换,更慢且引入区域格式差异。 On Error Resume Next只允许存在一行,下一行必须检查Err.Number并立刻On Error GoTo 0。IIf、And、Or都不短路(IIf两个分支都会求值),判空与除零要写成嵌套If...Else。- 对象赋值用
Set,用完置Nothing;互相持有的类模块要打破循环引用,否则Class_Terminate不触发。 - 环境开关必须成对恢复:
ScreenUpdating/Calculation/EnableEvents先存旧值,在统一出口恢复,异常路径也要走到。 - 64 位 API 声明用
#If VBA7+Declare PtrSafe+LongPtr;句柄与指针才用LongPtr,普通计数仍用Long。 - 字符串拼接用数组 +
Join,字符串函数优先带$后缀(Left$/Mid$返回 String 而非 Variant)。 - 显式转换、显式编码:
CLng/CDbl/CStr明确类型;写中文文件用ADODB.Stream指定utf-8,不要用默认系统代码页。
反例与修法见 references/50-pitfalls.md。
5. 标准过程骨架(可直接复制)
Option Explicit
Public Sub ProcessReport()
Const PROC As String = "ProcessReport"
Dim oldCalc As XlCalculation
Dim oldScreen As Boolean, oldEvents As Boolean
On Error GoTo ErrHandler
oldCalc = Application.Calculation
oldScreen = Application.ScreenUpdating
oldEvents = Application.EnableEvents
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
' ---- 主逻辑:一次读出,一次写回 ----
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Data")
Dim arr As Variant
arr = ws.Range("A1:D10000").Value2 ' 1-based 二维 Variant 数组
Dim i As Long
For i = LBound(arr, 1) To UBound(arr, 1)
If Len(arr(i, 1)) > 0 Then arr(i, 4) = CDbl(arr(i, 2)) * CDbl(arr(i, 3))
Next i
ThisWorkbook.Worksheets("Out").Range("A1") _
.Resize(UBound(arr, 1), UBound(arr, 2)).Value2 = arr
CleanExit:
Application.Calculation = oldCalc
Application.ScreenUpdating = oldScreen
Application.EnableEvents = oldEvents
Exit Sub
ErrHandler:
Debug.Print PROC & " | " & Err.Number & " | " & Err.Description
MsgBox "处理失败:" & Err.Description, vbExclamation
Resume CleanExit
End Sub
三个细节:出口标签必须在 Exit Sub 之前;错误处理里不要再用可能失败的语句;恢复环境后再决定是否 Err.Raise 上抛。
6. 常见任务 → 配方索引
| 任务 | 配方位置 |
|---|---|
| 10 万行批量清洗 / 汇总 | 40-cookbook.md §1 数组批量读写 |
| 去重、分组、多表关联 | 40-cookbook.md §2 Dictionary |
| 解析/生成 JSON | 40-cookbook.md §3 JsonConverter |
| 调 REST API、分页、超时 | 40-cookbook.md §4 MSXML2.ServerXMLHTTP |
| 读写 Access/SQL Server、防注入 | 40-cookbook.md §5 ADO 参数化 |
| 文本抽取与校验 | 40-cookbook.md §6 VBScript.RegExp |
| 导出 UTF-8 CSV / 日志 | 40-cookbook.md §7 ADODB.Stream |
| 进窗体录入、进度条、不卡死 | 40-cookbook.md §8 UserForm |
| 声明 WinAPI、32/64 位双兼容 | 30-advanced-techniques.md §2 |
| 类模块、接口、事件、弱引用 | 30-advanced-techniques.md §1 §4 |
7. 资源库与检索脚本
scripts/find_vba.py(纯标准库,无需安装):
cd <技能目录>
python3 scripts/find_vba.py --stats # 数据快照与分类统计
python3 scripts/find_vba.py --cats # 列出 14 个分类
python3 scripts/find_vba.py --cat learning --top 12 # 按分类查,按星数排序
python3 scripts/find_vba.py --level advanced --min-stars 100
python3 scripts/find_vba.py json # 关键词检索(名称/点评/分类/语言)
python3 scripts/find_vba.py dictionary array --any # 多词取并集
python3 scripts/find_vba.py --cat interop --json # 机器可读输出
python3 scripts/find_vba.py --archived # 只看已归档仓库
默认多词取交集;交集为空会自动降级为并集并在输出头部标注。★ 列为快照星数,⚠️ 表示仓库已归档。
完整清单与中文点评在 references/70-repos-by-category.md,结构化数据在 references/repos.json。
8. 数据边界与维护
- 资源目录来自 GitHub REST API 的多轮检索(38 组关键词/维度查询)与专家先验清单的逐仓库活体核验,候选池 504 个,经三重信号过滤与人工校准后精选 195 个不同仓库 / 201 条分类记录。
- 星数、许可证、归档状态、更新时间都是快照值,会随时间变化;仓库链接长期有效。需要刷新时用 GitHub API 重新拉取
/repos/<owner>/<repo>覆盖repos.json对应字段。 - 本技能是离线快照,不联网、不执行宏、不安装任何东西。所有链接只指向内容所有者的官方域名。
9. 安全与合规边界
- 本技能只覆盖办公自动化、软件工程与防御性分析:宏的提取、解析、检测与取证,用于理解风险与做防护。
security分类收录的均为公开检测/分析工具。刻意不收录、不链接、不讲解用于生成规避型文档、隐藏宏代码或绕过防护的仓库;这类内容不属于「教程与用法」,也不适合公开分发。- 引用第三方代码时遵守各仓库许可证(见
70-repos-by-category.md的许可证列);标记「未标注」的仓库使用前需自行确认授权。 - 打开来历不明的
.xlsm/.docm前,应在受控环境中先做静态检查;企业环境建议启用受信任位置与数字签名策略。