Lisp 家族中,AutoLISP/Visual LISP (主要用于 AutoCAD 环境)可以直接操作 Windows 注册表,而标准的 Common Lisp 通常需要借助外部库或调用 Windows API 来实现。在 AutoCAD 的 Visual LISP 环境中,通过 ActiveX 技术访问 WScript.Shell 对象是操作注册表的标准方法。
1. 核心能力与数据类型支持
Visual LISP 通过 ActiveX 接口操作注册表,其支持的数据类型取决于底层 WScript.Shell 对象的实现能力。虽然 Lisp 本身动态性强,但在写入注册表时,数据会被转换为 Windows 注册表的标准物理类型。
| Lisp 端数据形态 | 注册表物理类型 | 说明与限制 |
|---|---|---|
| 字符串 (String) | REG_SZ |
最常用类型,用于存储路径、配置文本等 。 |
| 整数 (Integer) | REG_DWORD |
Visual LISP 通常将数值自动转换为 32 位双字类型 。 |
| 布尔值 (T/Nil) | REG_DWORD |
T 转为 1,Nil 转为 0,本质仍为数值型存储 。 |
| 二进制数据 | REG_BINARY |
原生支持较弱。需通过变体 (Variant) 和安全数组 (SafeArray) 封装字节流才能写入 。 |
| 变体型 (Variant) | 多种类型 | Visual LISP 的核心交互类型,用于在 Lisp 和 COM对象间传递不同格式的数据 。 |
注意 :标准 Common Lisp 若无特定库(如
cl-registry或直接 FFI 调用advapi32.dll),不具备内置的注册表操作函数。以下示例基于 AutoCAD 环境下的 Visual LISP。
2. 代码实战:读写注册表
以下代码展示了如何在 Visual LISP 中初始化 COM 环境,利用 WScript.Shell 对象进行读写操作,并处理不同类型的数据。
lisp
;;; 功能:演示 Visual LISP操作注册表 (读/写/删除)
;;; 环境要求:AutoCAD (加载 Visual LISP扩展)
;;; 原理:通过 ActiveX 调用 WScript.Shell 对象
(defun c:RegTest ()
(vl-load-com) ; 加载 ActiveX 支持库,必须首先执行
(setq wsh (vlax-create-object "WScript.Shell")) ; 创建脚本宿主对象
(if wsh
(progn
(princ "
--- 开始注册表操作测试 ---")
;; 定义根键常量 (对应 HKEY_CURRENT_USER)
;; HKCU = &H80000001
(setq hkcu "&H80000001")
(setq subKey "Software\\MyLispApp\\Config")
(setq fullPath (strcat "HKCU\\" subKey)) ; WScript 使用字符串路径格式
;; --- 1. 写入数据 ---
;; 写入字符串 (REG_SZ)
(vl-catch-all-apply '(lambda () (vlax-invoke-method wsh 'RegWrite
(strcat fullPath "\\Version")
"1.0.5" "REG_SZ")
)
)
(princ "
已写入字符串版本信息。")
;; 写入数值 (REG_DWORD)
;; WScript.RegWrite 第三个参数指定类型,数值默认为 DWORD
(vl-catch-allapply
'(lambda ()
(vlax-invoke-method wsh 'RegWrite
(strcat fullPath "\\EnableFlag")
1
"REG_DWORD")
) )
(princ "
已写入数值开关 (1)。")
;; --- 2. 读取数据 ---
;; 注意:WScript.Shell 没有直接的 RegRead 返回类型区分,需自行解析 ;; 此处演示读取刚才写入的值
(setq readVer (vl-catch-all-apply '(lambda () (vlax-invoke-method wsh 'RegRead (strcat fullPath "\\Version")))
))
(if (not (vl-catch-all-error-p readVer))
(princ (strcat "
读取版本成功:" (vl-princ-to-string readVer)))
(princ "
读取版本失败。")
)
(setq readFlag (vl-catch-all-apply
'(lambda () (vlax-invoke-method wsh 'RegRead (strcat fullPath "\\EnableFlag")))
))
(if (not (vl-catch-all-error-p readFlag))
(princ (strcat "
读取开关成功:" (itoa readFlag)))
(princ "
读取开关失败。")
)
;; --- 3. 删除数据 ---
;; 删除一个具体的值 (Value)
(vl-catch-all-apply
'(lambda ()
(vlax-invoke-method wsh 'RegDelete (strcat fullPath "\\EnableFlag"))
)
)
(princ "
已删除 EnableFlag 键值。")
;; 释放对象
(vlax-release-object wsh)
(princ "
--- 测试结束 ---")
)
(princ "
无法创建 WScript.Shell 对象。")
)
(princ)
)
3. 关键机制解析
- ActiveX 桥接 :Visual LISP 自身不包含注册表命令,必须通过
(vl-load-com)加载 ActiveX 支持,然后创建WScript.ShellCOM 对象来间接操作 。 - 变体 (Variant) 的作用 :在 Lisp 与 COM 对象交互时,数据会自动包装成"变体"类型。这使得同一个 Lisp 函数可以接收字符串、整数或布尔值,并根据上下文传递给注册表相应的类型(如
REG_SZ或REG_DWORD)。 - 二进制数据处理 :若需保存二进制数据(
REG_BINARY),不能直接传入 Lisp 列表。必须先在 Lisp 中构建"安全数组"(SafeArray),将其封装为变体,再传递给注册表写入方法,过程较为复杂且容易出错 。 - 路径格式差异 :使用
WScript.Shell时,路径通常采用"HKCU\Software\..."的字符串形式,而非 API 常用的句柄加子键路径的形式,且根键需使用特定的十六进制字符串常量或简写(如 HKCU, HKLM)。