简介:这份文档面向需要处理加密 CAD 图纸的设计人员与制图学习者,聚焦多重插入引用这一常见图纸加密技术,提供可落地的炸开与解密思路。内容围绕三种解除保护的方式展开:借助 AutoLISP 文件快速加载、通过加密插件命令转换块类型,以及自行编写 lsp 脚本完成多重插入块与普通块之间的双向转换,并穿插讲解 AutoLISP 编程基础、ENTSEL 与 ENTGET 取块信息、DEFUN 自定义函数等知识点,帮助读者理解加密原理而非机械套用。资源包共 1 个 doc 文件,约 18KB,篇幅精炼、便于随查随用。目前已有 455 人学习,适合希望掌握图纸解密与块编辑技巧、提升 CAD 实操能力的读者参考。
1. 图纸被锁死那一刻,我才想起这份老文档
接手一套外部协作图纸,打开一看,图块能选中、能移动,就是炸不开,属性面板里显示的是“多重插入块”。这不是图纸坏了,而是被人用多重插入引用(MInsertBlock)做了保护——一个块引用被塞进了行列阵列参数,AutoCAD 的常规 explode 命令对它直接失效。很多做施工图、竣工图交付的人都会遇到这个场景:对方只给你看,不给你改,图纸就成了一个黑匣子。
这份文档记录的就是拆这种锁的几种办法:用现成的 AutoLISP 小工具一键转换,或者自己写一段 lsp,把多重插入块还原成普通块再分解。它适合两类人:一类是手上有加密图纸、需要恢复编辑能力的制图与深化设计人员;另一类是懂一点 AutoLISP、想搞清楚块引用数据结构到底怎么被改动的开发者。下面我按“先看清它是什么、再跑起来、最后能改”的顺序,把这份文档里的方法拆开讲。
2. 多重插入引用的本质:块引用被改了哪几个组码
2.1 普通块和多重插入块在数据层面的差别
要炸开,先得知道锁在哪。AutoCAD 里每个图元都是一张关联表(association list),entget取出来就是一堆(组码 . 值)的配对。普通块引用的类型标识是INSERT,实体类型名写在组码 100 里,值为AcDbBlockReference。而多重插入块的类型标识同样是INSERT,但 100 组码的值变成了AcDbMInsertBlock,同时多了两个关键组码:70 是列数,71 是行数,44 是列间距,45 是行间距。
也就是说,加密方并没有真的“加密”图形数据,而是把块引用改造成了阵列形式,并让 explode 命令拒绝处理这种类型。文档里那段 lsp 的核心思路非常直接:把 70、71 改回 0,把 44、45 的间距清零,把 100 组码从AcDbMInsertBlock换回AcDbBlockReference,然后用entmake重建图元、entdel删掉原图元。改完之后,它在 AutoCAD 眼里就是一个普通块引用了,explode 自然可用。
这里有个容易忽略的点:为什么不能直接改完原图元就完事?因为 AutoCAD 对已存在图元的类型标识(100 组码)修改是有限制的,直接 subst 后 entmod 往往不生效,所以文档里的写法是“重建 + 删除”,这是老版本 CAD 上比较稳的路子。
2.2 三个方法各自的适用边界
文档给了三条路,实际用起来差别不小,我按可靠性排一下:
| 方法 | 触发方式 | 依赖 | 适用场景 |
|---|---|---|---|
| 方法一 | 拖入 wjjm 文件,命令行输入 wjjm | 外部 lsp 工具文件 | 手头有工具、想最快出结果 |
| 方法二 | 命令行输入 CYN- | 已安装的加密插件 | 插件环境已就绪的批量作业 |
| 方法三 | 加载自写 exm.lsp,运行 exm | 无外部依赖,纯代码 | 想理解原理、需要自己改逻辑 |
方法一和方法二本质上是别人封装好的命令,你只需要会加载、会敲命令;方法三才是这份文档真正的技术含量所在,因为它把转换逻辑完整摊开了,而且顺带给了反向的lockb命令——能把普通块再变回多重插入块。这个反向能力在二次开发里很有用,比如你要做图纸保护演示、或者测试自己的解密流程是否可逆。
提示:方法一里文档同时出现了
wjjm和wjmm两种输入写法,这是原文的笔误,实际以加载后的命令定义为准,敲之前先在命令行看提示。
3. 把 exm.lsp 跑起来:从加载到炸开的完整操作
3.1 环境准备与文件加载
这份代码面向的是 AutoCAD 的 AutoLISP 解释器,2009 年前后的版本就能跑,后续版本基本兼容。不需要额外装编译器,把代码存成纯文本、扩展名改成.lsp即可。加载方式有两种:菜单里“工具 → 加载应用程序”,选中文件加载;或者直接在命令行敲(load "路径/exm.lsp")。后者在调试时更顺手,因为路径写错会立刻报错,而不是在对话框里点半天。
加载成功后命令行不会有明显反馈,这是正常的——DEFUN只是注册了函数,没执行。你可以敲exm回车,如果提示“点取多重块”,说明函数已经挂上了。这一步翻车的常见原因是文件编码:用某些编辑器存成 UTF-8 带 BOM,老版本 CAD 读进去第一行就报错,建议存 ANSI 或纯 ASCII。
3.2 核心转换函数逐段拆解
下面这段是文档里exm命令的整理版,我补了注释,逻辑和原文一致:
(DEFUN C:exm () (setvar "cmdecho" 0) ; 关闭命令回显,避免刷屏 (SETQ STM (car (ENTSEL "\n点取多重块"))) ; 选一个图元,取实体名 (while stm ; 循环处理,直到用户空选 (setq e (entget stm)) ; 取出图元的关联表 (setq stlx (cdr (assoc 0 e))) ; 读组码0,判断是不是 INSERT (if (= stlx "INSERT") (PROGN (setq r_zm70 (assoc 70 e)) ; 列数 (setq c_zm71 (assoc 71 e)) ; 行数 (setq r_dist_zm44 (assoc 44 e)) ; 列间距 (setq c_dist_zm45 (assoc 45 e)) ; 行间距 (setq e (subst (cons 44 0) r_dist_zm44 e)) ; 列间距清零 (setq e (subst (cons 45 0) c_dist_zm45 e)) ; 行间距清零 (setq e (subst (cons 70 0) r_zm70 e)) ; 列数归零 (setq e (subst (cons 71 0) c_zm71 e)) ; 行数归零 (setq e (subst (list 100 "AcDbBlockReference") (list 100 "AcDbMInsertBlock") e)) ; 类型名换回普通块 (entmake e) ; 用改好的表重建图元 (entdel stm) ; 删除原图元 ) ) (SETQ STM (car (ENTSEL "\n点取下一多重块"))) ; 继续选下一个 ) (setvar "cmdecho" 1) ; 恢复命令回显 )逐段说清楚。ENTSEL返回的是一个列表,第一个元素是实体名,car取出来就是我们要操作的图元句柄。entget把这个句柄翻译成关联表,后面所有assoc都是在这张表里按组码找配对。四个subst是替换操作:subst的签名是(subst 新项 旧项 表),它把表里和旧项相等的那一项换成新项,所以必须先assoc把旧项取出来当锚点。
entmake是重建,它接受一张完整的关联表,在图形数据库里生成新图元;entdel删除旧图元。这一对组合是整段代码的关键,也是为什么不能只entmod的原因。最后的while让命令可以连续处理多个块,按 Esc 或空选退出。
3.3 反向命令 lockb 与验证方式
文档里还给了lockb,逻辑是exm的镜像:把 70、71 置 1,100 组码换成AcDbMInsertBlock。它的用途是把你改好的普通块重新“锁”回去,方便做对照测试。验证是否成功,最直接的办法是转换后选中图元看属性面板——类型从“多重插入块”变回“块参照”,然后敲explode能炸开、能看到内部图元,就说明通了。
如果炸开后发现图形位置偏移,多半是原图本身带了非零的 44、45 间距,清零后阵列展开的基准变了。这种情况不要慌,转换前先记下原间距值,必要时用move校正,或者干脆在exm里保留间距、只改类型标识试试——不同加密工具的做法不完全一样,得按实际图纸调。
4. 避坑与排查:转换过程中最容易翻车的几处
4.1 现象:加载成功但命令无效
原因通常是函数名大小写或前缀问题。AutoLISP 里C:exm定义的是命令行命令exm,如果你把代码里的C:删了,函数就只能用(exm)这种带括号的形式调用,直接敲exm会提示未知命令。解决方法是保留C:前缀,或者改用括号调用。另外确认加载的是改过编码的那份文件,别加载了旧缓存。
4.2 现象:entmake 返回 nil,图元没生成
这是最常见的失败。entmake对关联表的完整性要求很高,缺组码、组码顺序乱、或者 100 组码的子类标记不匹配,都会静默返回 nil。排查办法是在entmake前加一句(print e),把表打出来看结构;重点检查 100 组码是不是紧跟在 0 组码之后、2 组码(块名)是否还在。如果原图元是匿名块或动态块,重建时块名可能失效,需要先确认块定义还在。
4.3 现象:转换后图元消失或跑到原点
原因多半是entdel执行了但entmake没成功,等于删了没建。也可能是坐标系问题:entget取出的 10 组码是插入点,如果原图在 UCS 下操作,重建后可能落到 WCS 原点附近。解决方法是先在小样本图上试,确认entmake返回值非 nil 再批量跑;批量前务必备份原图,这类操作没有后悔药。
4.4 现象:部分块能转、部分块报错
不同加密工具产出的多重插入块,组码组合不完全一样。有的只改 70、71 不改 100,有的把 44、45 设成极小值而非零。硬套一套替换逻辑就会在个别块上失败。稳妥做法是把subst改成条件判断:先assoc看组码在不在,在才替换,不在就跳过。这样代码容错性会好很多,也不至于因为一个块失败中断整个while循环。
注意:任何批量转换前,先把原图另存一份。这类脚本直接操作图形数据库,出错时原图元已被
entdel,没有撤销余地。
5. 二次开发:把一次性脚本改成可复用的图纸处理工具
跑通一次不算本事,能把它变成日常可复用的工具才有价值。我一般会做三件事。第一,把exm从“手动点选”改成“框选批量”:用ssget配合过滤条件(0 . "INSERT")一次性拿到所有块引用,再在循环里判断 100 组码是否为AcDbMInsertBlock,是才转换。这样处理几十张图时不用一个个点。
;; 批量版:框选区域内所有多重插入块并转换 (DEFUN C:exmall (/ ss i ent ed) (setvar "cmdecho" 0) (setq ss (ssget '((0 . "INSERT")))) ; 只选块引用 (if ss (progn (setq i 0) (while (< i (sslength ss)) (setq ent (ssname ss i)) (setq ed (entget ent)) ;; 只处理类型名为 MInsertBlock 的 (if (member (list 100 "AcDbMInsertBlock") ed) (progn (setq ed (subst (cons 70 0) (assoc 70 ed) ed)) (setq ed (subst (cons 71 0) (assoc 71 ed) ed)) (setq ed (subst (list 100 "AcDbBlockReference") (list 100 "AcDbMInsertBlock") ed)) (if (entmake ed) (entdel ent)) ; 建成功才删旧的 ) ) (setq i (1+ i)) ) ) ) (setvar "cmdecho" 1) (princ) )这段的关键改动是ssget过滤和member判断:前者把选择范围收窄到块引用,后者确保只动真正的多重插入块,普通块原样保留。entmake外面套了if,建失败就不删,避免丢图元。
第二,把转换结果做成可核对的日志:每处理一个块,把块名、原行列数、转换结果写到一个文本文件里,出问题时能回溯是哪个块没转成功。第三,如果团队里多人用,把 lsp 放到支持文件搜索路径下,用acaddoc.lsp自动加载,省得每次手动拖。
验证方法我习惯用“三步对照”:转换前截图记录图元数量和位置,转换后统计块引用数量是否一致,再随机抽几个块炸开看内部图元是否完整。三步都过,才敢往正式图纸上套。
说个血泪教训:早期我图省事,直接在客户交付图上跑批量脚本,没先备份,结果有个动态块重建失败被删了,只能让对方重新发图。从那以后我每次跑这类脚本,都强制先另存一份、再在小样本上验证entmake返回值,确认无误才放开批量。希望这份拆解能帮你少走一遍我踩过的路。
本文还有配套的精品资源,点击获取