本帖最后由 baitang36 于 2022-12-8 14:27 编辑
首先,fas文件是不会调用command这个函数的,lsp中的command函数在编译时都被改成了保留函数ads-cmd
如果强制调用commad,会有什么结果呢?call_command.fas就是我的实验程序,加载它时会调用command,结果只是提示一句:错误: 无法应用特殊格式: COMMAND
从内存中挖出COMMAND的代码如下:
00000000: 14 01 00 00 01
00000005: 09 b4 02 ;"VLMSG.DLL"
00000008: 33 34 76 00 00
00000013: 51 02 b3 02 01 00 ;string-resource
00000019: 09 d9 00 ;"COMMAND"
00000022: 51 01 a0 01 01 00 ;al-intern
00000028: 51 02 e2 02 01 00 ;_msg-err
00000034: 16
写成lsp就是(_msg-err(string-resource "VLMSG.DLL" 30260 )(al-intern "COMMAND"))
确实是只显示一句错误信息。
再试验一下ads-cmd
命令: (load "c:/00/trf_9")
T
命令: (tranf "ads-cmd")
T
命令: !ads-cmd
#<SUBR @1749f438 ads-cmd>
命令: (ads-cmd)
*取消*
命令: (ads-cmd "line")
line 指定第一点: nil
指定第一点:
指定下一点或 [放弃(U)]:
ads-cmd这个函数可以没有参数或一个参数。lsp的一句comand会编译成多个ads-cmd
ads-com最终是调用acad.exe的acedcommand实现的。
再看一下vl-cmdf
挖出内存中的代码:
00000000: 14 01 00 00 01
00000005: 05 00
00000007: 51 01 f6 01 01 00 ;reslist->lresb
00000013: 51 01 05 01 01 00 ;ads-cmd-pure
00000019: 16
写成lsp就是(defun vl-cmdf (var0) (ads-cmd-pure (reslist->lresb var0)))
可以看出它调用了reslist->lresb和ads-cmd-pure这两个保留函数。
ads-cmd-pure是调用acad.exe的acedcmd来实现的。
command-s在64位的ACAD中是用c++来实现的,没有调用fas保留函数,它是调用accore.dll 中的acedcmdS实现的,函数名多了一个S
结论:
command是用fas保留函数实现的,并且由于多次调用ads-cmd函数,速度最慢。
vl-cmdf 是用fas保留函数实现的,用一个表一次输入所有参数,速度比command快。
command-s是直接用c++写的,速度最快。
网友答:
((if command-s command-s vl-cmdf)"_.select" ss "")网友答: 本帖最后由 kozmosovia 于 2025-12-20 11:03 编辑
都没人认真去读过cad的帮助:https://help.autodesk.com/view/O ... 0-95E7-7E19A4EE19A1
里面已经详细讲了command和command-s的区别:
DeepSeek的翻译如下:
command-s 函数是 command 函数的一个变体,它对命令标记的内容有一些限制,但由于内部逻辑的不同,它不仅比 command 更快,而且可以在 error处理程序中使用。
命令标记是提供给 command-s 函数的单个参数。它可以是字符串、实数、整数、点、图元名、列表等。以下示例展示了 AutoCAD 的 LINE 命令和三个命令标记:
(command-s "._line" "0,0" "5,7" "")
"-s" 后缀表示以"子例程"方式执行提供的命令标记。在这种形式下,AutoCAD 直接从 AutoLISP 调用,在一个临时命令处理器中处理提供的命令标记,该处理器独立于主文档命令处理器,然后返回,从而终止临时命令处理器。正在执行的命令必须在同一个 command-s 函数中启动和完成。
相比之下,command 函数仍然是提供的命令标记的"协程"执行方式,AutoLISP 依次对标记求值,将结果发送给 AutoCAD,然后返回以允许 AutoCAD 处理该标记。接着 AutoCAD 回调 AutoLISP,AutoLISP 恢复对表达式的求值。在这种逻辑流程中,后续的标记表达式可以查询 AutoCAD 之前标记处理的结果并使用它。
总之,"协程"风格的命令标记处理在功能上更强大,但在使用时有限制。"子例程"风格的命令标记处理可以在更广泛的上下文中使用,但会预先处理所有命令标记,实际执行过程是非交互式的。对于同一组命令标记,command-s 函数的速度明显更快。
已知注意事项
使用 command-s 函数时,必须考虑以下几点:
在单个 command-s 表达式中输入的命令标记流必须代表一个完整的命令及其输入。当所有命令标记都处理完毕时,任何正在进行的命令都将被取消。以下用法对 command-s 函数无效:
(command-s "._line")
(command-s "2,2" "12.25,9" "")
所有命令标记在交给 AutoCAD 执行之前都会被求值。相反,command 函数实际上是对每个命令标记求值,然后将结果提供给 AutoCAD 处理,然后再处理下一个命令标记。
不能使用"暂停"命令标记。可以与绘图区域或命令窗口交互的表达式可以使用,但它们都将在 AutoCAD 接收和处理其中的任何一个之前被处理。
以下用法对 command-s 函数无效:
(command-s "._line" "0,0" PAUSE "")
注意:尽管 command-s 函数与 command 函数类似,但如果在输入 AutoLISP 表达式时已有 AutoCAD 命令正在执行,则在尝试使用 U 或 UNDO 回退系统状态时应谨慎。在这种情况下,运行 UNDO 的结果可能导致正在执行的命令失败,甚至使 AutoCAD 崩溃。
根据https://www.cadforum.cz/en/qaID.asp?tip=4170的解释,vl-cmf在调用前会校验输入参数,只有参数全部合法后才会真实调用,且返回值会是T,表示调用成功:
(command "._line" (getpoint "point?") '(0 0) "") : 会先执行command,然后执行getpoint,成功后返回nil
(vl-cmdf"._line" (getpoint "point?") '(0 0) "") : 会先执行getpoint,然后执行command,成功后返回T
(command-s "._line" (getpoint "point?") '(0 0) "") : 会先执行getpoint,然后执行command,成功后返回nil
合法方式调用:
(command "_.line")
(command (getpoint "Point?") '(0 0) "")
(vl-cmdf "_.line")
(vl-cmdf (getpoint "Point?") '(0 0) "")
不合法方式调用:
(command-s "_.line")
(command-s (getpoint "Point?") '(0 0) "")
网友答: 透彻!向大师学习!网友答: command和command-s对CAD版本有要求,比较讨厌。网友答: 大佬太牛了网友答: 厉害了,竟然从内存中深挖网友答:
判断一下就行,只怕结果不同
(if (>= (atoi (getvar "AcadVer")) 20) ;2015
(command-s "_.select" ss "")
(vl-cmdf "_.select" ss "")
)网友答: 很有用,谢谢分享。网友答: 佩服大佬的钻研精神
网友答:
如果能够根据不同版本编写一个自适应程序就好,暂时还没有思路
首先,fas文件是不会调用command这个函数的,lsp中的command函数在编译时都被改成了保留函数ads-cmd
如果强制调用commad,会有什么结果呢?call_command.fas就是我的实验程序,加载它时会调用command,结果只是提示一句:错误: 无法应用特殊格式: COMMAND
从内存中挖出COMMAND的代码如下:
00000000: 14 01 00 00 01
00000005: 09 b4 02 ;"VLMSG.DLL"
00000008: 33 34 76 00 00
00000013: 51 02 b3 02 01 00 ;string-resource
00000019: 09 d9 00 ;"COMMAND"
00000022: 51 01 a0 01 01 00 ;al-intern
00000028: 51 02 e2 02 01 00 ;_msg-err
00000034: 16
写成lsp就是(_msg-err(string-resource "VLMSG.DLL" 30260 )(al-intern "COMMAND"))
确实是只显示一句错误信息。
再试验一下ads-cmd
命令: (load "c:/00/trf_9")
T
命令: (tranf "ads-cmd")
T
命令: !ads-cmd
#<SUBR @1749f438 ads-cmd>
命令: (ads-cmd)
*取消*
命令: (ads-cmd "line")
line 指定第一点: nil
指定第一点:
指定下一点或 [放弃(U)]:
ads-cmd这个函数可以没有参数或一个参数。lsp的一句comand会编译成多个ads-cmd
ads-com最终是调用acad.exe的acedcommand实现的。
再看一下vl-cmdf
挖出内存中的代码:
00000000: 14 01 00 00 01
00000005: 05 00
00000007: 51 01 f6 01 01 00 ;reslist->lresb
00000013: 51 01 05 01 01 00 ;ads-cmd-pure
00000019: 16
写成lsp就是(defun vl-cmdf (var0) (ads-cmd-pure (reslist->lresb var0)))
可以看出它调用了reslist->lresb和ads-cmd-pure这两个保留函数。
ads-cmd-pure是调用acad.exe的acedcmd来实现的。
command-s在64位的ACAD中是用c++来实现的,没有调用fas保留函数,它是调用accore.dll 中的acedcmdS实现的,函数名多了一个S
结论:
command是用fas保留函数实现的,并且由于多次调用ads-cmd函数,速度最慢。
vl-cmdf 是用fas保留函数实现的,用一个表一次输入所有参数,速度比command快。
command-s是直接用c++写的,速度最快。
网友答:
自贡黄明儒 发表于 2022-12-8 16:45
判断一下就行,只怕结果不同
(if (>= (atoi (getvar "AcadVer")) 20) ;2015
((if command-s command-s vl-cmdf)"_.select" ss "")网友答: 本帖最后由 kozmosovia 于 2025-12-20 11:03 编辑
都没人认真去读过cad的帮助:https://help.autodesk.com/view/O ... 0-95E7-7E19A4EE19A1
里面已经详细讲了command和command-s的区别:
DeepSeek的翻译如下:
command-s 函数是 command 函数的一个变体,它对命令标记的内容有一些限制,但由于内部逻辑的不同,它不仅比 command 更快,而且可以在 error处理程序中使用。
命令标记是提供给 command-s 函数的单个参数。它可以是字符串、实数、整数、点、图元名、列表等。以下示例展示了 AutoCAD 的 LINE 命令和三个命令标记:
(command-s "._line" "0,0" "5,7" "")
"-s" 后缀表示以"子例程"方式执行提供的命令标记。在这种形式下,AutoCAD 直接从 AutoLISP 调用,在一个临时命令处理器中处理提供的命令标记,该处理器独立于主文档命令处理器,然后返回,从而终止临时命令处理器。正在执行的命令必须在同一个 command-s 函数中启动和完成。
相比之下,command 函数仍然是提供的命令标记的"协程"执行方式,AutoLISP 依次对标记求值,将结果发送给 AutoCAD,然后返回以允许 AutoCAD 处理该标记。接着 AutoCAD 回调 AutoLISP,AutoLISP 恢复对表达式的求值。在这种逻辑流程中,后续的标记表达式可以查询 AutoCAD 之前标记处理的结果并使用它。
总之,"协程"风格的命令标记处理在功能上更强大,但在使用时有限制。"子例程"风格的命令标记处理可以在更广泛的上下文中使用,但会预先处理所有命令标记,实际执行过程是非交互式的。对于同一组命令标记,command-s 函数的速度明显更快。
已知注意事项
使用 command-s 函数时,必须考虑以下几点:
在单个 command-s 表达式中输入的命令标记流必须代表一个完整的命令及其输入。当所有命令标记都处理完毕时,任何正在进行的命令都将被取消。以下用法对 command-s 函数无效:
(command-s "._line")
(command-s "2,2" "12.25,9" "")
所有命令标记在交给 AutoCAD 执行之前都会被求值。相反,command 函数实际上是对每个命令标记求值,然后将结果提供给 AutoCAD 处理,然后再处理下一个命令标记。
不能使用"暂停"命令标记。可以与绘图区域或命令窗口交互的表达式可以使用,但它们都将在 AutoCAD 接收和处理其中的任何一个之前被处理。
以下用法对 command-s 函数无效:
(command-s "._line" "0,0" PAUSE "")
注意:尽管 command-s 函数与 command 函数类似,但如果在输入 AutoLISP 表达式时已有 AutoCAD 命令正在执行,则在尝试使用 U 或 UNDO 回退系统状态时应谨慎。在这种情况下,运行 UNDO 的结果可能导致正在执行的命令失败,甚至使 AutoCAD 崩溃。
根据https://www.cadforum.cz/en/qaID.asp?tip=4170的解释,vl-cmf在调用前会校验输入参数,只有参数全部合法后才会真实调用,且返回值会是T,表示调用成功:
(command "._line" (getpoint "point?") '(0 0) "") : 会先执行command,然后执行getpoint,成功后返回nil
(vl-cmdf"._line" (getpoint "point?") '(0 0) "") : 会先执行getpoint,然后执行command,成功后返回T
(command-s "._line" (getpoint "point?") '(0 0) "") : 会先执行getpoint,然后执行command,成功后返回nil
合法方式调用:
(command "_.line")
(command (getpoint "Point?") '(0 0) "")
(vl-cmdf "_.line")
(vl-cmdf (getpoint "Point?") '(0 0) "")
不合法方式调用:
(command-s "_.line")
(command-s (getpoint "Point?") '(0 0) "")
网友答: 透彻!向大师学习!网友答: command和command-s对CAD版本有要求,比较讨厌。网友答: 大佬太牛了网友答: 厉害了,竟然从内存中深挖网友答:
rocking2008 发表于 2022-12-8 14:51
command和command-s对CAD版本有要求,比较讨厌。
判断一下就行,只怕结果不同
(if (>= (atoi (getvar "AcadVer")) 20) ;2015
(command-s "_.select" ss "")
(vl-cmdf "_.select" ss "")
)网友答: 很有用,谢谢分享。网友答: 佩服大佬的钻研精神
网友答:
如果能够根据不同版本编写一个自适应程序就好,暂时还没有思路