com.cad.task 在兼容 CAD 的 COM 命令通道之上执行 AutoLISP,并通过本地文件返回数据。它不依赖 Autos、特定窗口类名、Visual LISP COM 函数接口或 .NET 插件。回执确认的是程序执行和序列化结果,不代替几何或业务验收。
cad.CreateLispTask(code,args,doc,options):先创建任务,不提交。自动化优先使用,可在产生副作用前保存任务路径。cad.SubmitLisp(...):创建并尝试提交,返回 task,err。即使提交报错,也可能返回任务对象,应保留它。cad.RunLisp(...):创建、保存journal、唯一提交并等待,返回result,err,task。结果含taskPath/elapsed及实际journal;journal写失败不提交。cad.ResumeLisp(path,timeout,doc):恢复原回执,返回同一元组;省略doc可离线。com.cad.task.open(path[,doc]):跨线程、跨会话恢复任务。读取回执不需要 CAD 正在运行。增强实例入口可省略doc,此时只使用已有活动图纸,不自动新建;底层task.create仍要求显式doc。code 是原始 LISP 源码,不是 aardio 模板,也不是文件名。最后一个表达式的值为结果,args 是 LISP 中的局部变量。不要使用 ac$ 前缀的内部变量,也不要在任务中切换/关闭目标图纸或嵌套提交任务。
import com.cad;
import com.cad.task;
var cad = com.cad();
if(!cad) error("无法连接或启动 CAD");
if(!cad.IsQuiescent()) error("CAD 当前忙碌,请先检查原任务");
var doc = cad.Documents.Add(); // 本例明确新建测试图纸。
var task,err = cad.CreateLispTask(
`(list (cons "text" (car args)) (cons "answer" (+ (cadr args) 5)))`,
["中文",7],doc
);
if(!task) error(err);
// 在提交前持久化路径;进程意外退出也能重新查回执。
var recoveryFile = io.appData("aardio/com.cad/last-task.txt",task.path);
print("任务目录",task.path);
var sent,err = task.submit();
if(!sent) {
print("提交未确认,勿重发",err,task.path);
return;
}
var result,err = task.wait();
print(result,err); // completed 时 data 为 {text="中文";answer=12}
恢复时只读原任务,不另建 ID 重试:
import com.cad.task;
var path,err = string.load(io.appData("aardio/com.cad/last-task.txt"));
if(!path) error(err);
var task,err = com.cad.task.open(path);
if(!task) error(err);
var result,err = task.wait(5000);
print(result,err);
read() 和默认的 wait() 只读取任务目录,不读取 COM 文档;省略 doc 打开的任务始终可以离线等回执。wait() 泵送窗口/STA 消息,不使用长时间纯 sleep。只有创建时显式设 nudge=true 且仍持有原 doc 时,wait 才可能刷新命令队列(见下文)。收到回执后 CAD 仍可能正在退出包装器;后续 COM 查询如被暂时拒绝,可有限重试无副作用查询,不重放任务源码。
RunLisp与技能调用同一com.cad.task.run/runTask,journal位于 %LOCALAPPDATA%\aardio\com.cad\journal。底层create只指定doc时不猜产品,默认post/utf8;通常使用增强实例入口。详见兼容说明。
| state | 意义 |
|---|---|
| prepared | 已创建,本机尚无提交标记 |
| submitted | 已认领一次提交机会;不证明 CAD 已接收或执行 |
| running | CAD 已写 started 标记,尚无终态回执 |
| completed | 执行与结果序列化成功,ok=true、terminal=true |
| error | parse / execute / serialize / transport 等阶段失败,terminal=true |
| rejected | CAD 端发现不是原目标文档或实例 |
| expired | 超过最迟开始时间,未进入用户源码 |
| cancelled | CAD 在执行用户源码前接受了取消请求 |
| timeout | 本次 wait 等待超时;terminal=false,observedState 保留实际快照 |
read() 失败返回 null,err。wait() 对非成功终态返回 result,err;超时也返回快照及错误说明,而不是伪造终态。请检查 result.ok 和 result.terminal,不要只检查 result 是否非 null。CAD 端语法检查会拒绝括号不完整、未闭合字符串/块注释、额外右括号,避免原始源码破坏传输表达式。
submit() 只有一次提交认领。提交标记使用独占创建,多对象/线程/进程争用时只有一个可派发;该认领内对明确的 COM 拒绝接收可有限重试。timeout 只限制等待回执;startTimeout 限制从创建任务到 CAD 开始执行的时间。两者都不强行中断已开始的 LISP。cancel() 仅写执行前取消请求。返回 true 表示文件写入成功,只有 cancelled 回执才确认 CAD 接受。已经 running 的任务可以继续完成。| 字段 | 默认值 | 说明 |
|---|---|---|
| directory | %LOCALAPPDATA%\aardio\com.cad\tasks |
其下创建唯一请求目录;应使用 CAD 和调用方都可读写的本地路径 |
| method | AutoCAD/浩辰post,中望send | 创建时按增强实例ProgId选择,显式值优先;提交失败后不换方法重放 |
| timeout | 10000 | wait 默认等待毫秒数,0 表示立即查询;最大 86400000 |
| startTimeout | 30000 | 从创建时计算的最迟开始毫秒数;最大 86400000 |
| nudge | false | true 才允许 wait 自动刷新未开始的 Post 队列;需要原 doc,会同步调用 SendCommand,可能阻塞 |
| nudgeDelay | 800 | 显式启用 nudge 时,从本次 wait 开始等候的毫秒数;0有效,最大86400000 |
| resultEncoding | AutoCAD utf8,中望/浩辰 ansi | UTF-8要求支持三参数open;ANSI受代码页限制,先验证文字往返 |
| codepage | 本机系统 ANSI 代码页 | resultEncoding="ansi" 时用于解码,应与 CAD 输出一致 |
| idleTimeout | 3000 | RunLisp/runTask前后有限等空闲,0不额外等待;不能打断阻塞COM |
method=send 的 COM 调用本身可能阻塞;wait 的超时无法打断一个尚未返回的 COM 方法。PostCommand 也不构成硬实时保证。 强隔离要求应由调用方使用独立工作进程实现,而不是让底层库绑定 Autos。对不兼容的 CAD 先做纯查询小探针,不静默降级或修改安全设置。
PostCommand 排队到空闲时处理;向非活动文档提交时可能使目标文档成为活动文档,不保证保持当前文档不变。submitted 未开始也可能是交互输入、模态窗口、许可证或系统阻塞,不能一概归因命令通道。优先查原任务及环境,不重发业务源码。
确需刷新时,com.cad.task.open(path,doc) 得到原任务,再调用 task.nudge()。它只对仍 submitted 的 post 任务发送 (princ) 空操作;核对文档名称、文档/应用 HWND,要求原目标仍活动且 CAD 空闲。不激活其他文档,不发送任务源码;成功后记录 nudged。
创建时 nudge=true 可让每次 wait 在达到 nudgeDelay 后最多尝试一次;已有 nudged 标记不再刷新。默认false,旧请求缺少该字段同样不刷新。wait(0) 仅查询,不刷新;超时快照可能含 nudgeError 说明未能刷新的原因。成功刷新也不代表业务完成,仍以原终态回执为准。
nudge 使用同步 SendCommand,可能驱动该实例中其他已排队命令;COM 调用未返回时,wait 超时无法中断它。 如要求纯异步等待,请保持默认值。刷新不等于 Esc、任务取消或回滚。
减少跨进程往返有利于批量工作,但不能把 LISP 循环耗时等同于任务总耗时。2026-09-19 本机 AutoCAD 2026 对照:均新建300个相同的圆、返回300个Handle、缓存ModelSpace、统一重生成一次,三轮交错测量:
这里完整任务从创建到收到回执计时;当时版本LISP内绘图及重生成仅47–110毫秒,不能将它当作端到端耗时。这是2026-09-19传输优化时的runner与数据;后续增加结果类型支持后命令长度不同,不能把旧基准当作后续版本的新测量。
这是单机测量,不是性能保证。完整任务还包含代码生成、提交、CAD 排队、序列化和回执等待。适合批量合并操作,不宜把每个实体都拆成一次任务;少量对象可直接 COM。不要为了缩短等待时间而取消完成确认,也不要把 method=send 当作无条件更快、更安全的替代。
{handle="..."};句柄必须与原文档配对使用。{handle="..."};应用对象等没有 Handle 的对象仍需自行提取属性。VARIANT 自动解包;SAFEARRAY 转正规数组;PICKSET 转 [{handle="..."},…],受相同结果项数限制;普通符号转名称字符串,T/nil 规则不变。结果解析只用 JSON,不 eval 返回文本。rtos 的科学计数模式、精度参数16输出,并去除尾数中冗余的零;不是所有 CAD 版本的 IEEE 754 无损往返承诺。几何检查按单位/量级用容差,精确ID用字符串。配套 JSON 库修复了长科学计数字面值被错误转为 size64 的问题;集成时同步更新 lib/JSON/_.aardio,纯大整数字面值的既有处理保留。目录保存 request.json、command.txt、submitted、started、result.json,以及可选 cancel/submit-error.txt/nudged。命令文件在发送前校验哈希,结果先关闭临时文件再改名发布。
目录内含代码、参数和结果,可能包含敏感信息;由调用方控制访问与保留期限。只在确认终态且不再需要审计/恢复后主动清理。禁止自动删除未知任务的目录。硬盘损坏、文件被手工修改、CAD 退出、身份句柄复用等不在“只执行一次”的保证范围内。
文档绑定同时检查文档名称、文档 HWND、应用 HWND;不依赖标题和窗口类名。关闭重开图纸、另存改名或重启 CAD 后,不应提交之前 prepared 的任务,应先人工/业务核对。若原任务 submitted/running,始终以核对回执和实际图纸为先,不能直接重放。