陨落 发表于 2021-5-28 20:49:43

我也来发一个多文件选择对话框,lisp+aardio实现

本帖最后由 陨落 于 2021-5-28 20:53 编辑

之前看到大海兄发了一个多文件选择对话框的程序。不过很可惜下载下来运行不了。
正好最近研究了一下aardio,这个国产语言编写界面极其方便,于是打算用它来实现一下。
而且我发现lisp和exe之间交换数据根本不需要txt
这里分享出来。我觉得核心是lisp和exe交换数据的方式,暂时还没在别的地方看到,所以收点币。
对话框本来是想设置成cad的子窗口,但是一旦在aardio语句fsys.dlg.openEx中指定了父窗口,在lisp中用exec启动时,文件选择对话框就出不来,但是用run就可以。很费解。也希望有大神能解答一下最终效果如下:attach://113371.gif
lisp源代码在这里:



jacenhe 发表于 2022-2-13 07:45:31

本帖最后由 jacenhe 于 2024-6-3 15:31 编辑

jun353835273 发表于 2021-6-1 13:05
c#的交互要方便的多
http://bbs.mjtd.com/thread-180931-1-1.html
不错,你的建议非常好。随手拿这个 C# 代码小试了一下,为了省事直接在 aardio 里编译 C# 为 DLL,然后自动并加载到 AutoCAD,然后再在 aardio 里调用 AutoCAD 再调用这个 C# 写的 DLL:
import console;
console.showLoading("正在编译 .NET DLL");

import dotNet;
import com.cad;

//创建 AutoCAD 对象
var cad = com.cad();
cad.Visible = true;

//创建 C# 语言编译器
var compiler = cad.NetCompiler("C#");

compiler.Source = /******
using System;
using System.Collections.Generic;
using System.Text;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using Wnd = System.Windows.Forms;

public class TestFunctions
{
         
         public static ResultBufferListfunSelfiles(ResultBuffer DataIn)
         {
             ResultBuffer Ret = new ResultBuffer();
             if (DataIn == null) return null;
             TypedValue[] Tranlisp = DataIn.AsArray();
             try
             {
               if (Tranlisp.Length == 2)
               {
                     string Title = Tranlisp.Value as string;
                     string Filter = Tranlisp.Value as string;
                     string FilterIn = "(*." + Filter + ")|*." + Filter;
                     Wnd.OpenFileDialog openDlg = new Wnd.OpenFileDialog();
                     openDlg.Title = Title;
                     openDlg.Filter = FilterIn;
                     openDlg.Multiselect = true;
                     Wnd.DialogResult openRes = openDlg.ShowDialog();
                     if (openRes == Wnd.DialogResult.OK)
                     {
                         string[] strNames = openDlg.FileNames;
                         for (int i = 0; i < strNames.Length; i++)
                         {
                           Ret.Add(new TypedValue((int)LispDataType.Text, strNames[ i ]));
                         }
                     }
                     else
                     {
                         return null;
                     }
               }
             }
             catch (Autodesk.AutoCAD.Runtime.Exception)
             {
               return null;
             }
             return Ret;
         }
}

******/

var assembly = compiler.Compile("/ListfunSelfiles.dll"); //编译并返回程序集
console.log(compiler.getLastError()); //查看编译器错误信息

cad.NetLoad("/ListfunSelfiles.dll");
cad.SendCommand(`(ListfunSelfiles"打开文本" "txt")`);

console.pause();




jacenhe 发表于 2022-2-14 12:43:41


aardio 提供的 cad.SendCommand() ,cad.LoadLisp()可以执行 LISP 代码,还能支持 aardio 的模板语法,
也就是可以将 LISP 代码与 aardio 代码混写,这有一点像 PHP 与 HTML 可以混写。例如:

cad.SendCommand(`
(setq c:hello nil)
(defun c:hello(/ name)
(set 'name (getstring "What's your name? "))
(set 'msg (strcat "Hello, " name <?= time(),"这是 aardio 对象" ?>))
(write-line msg))
hello`)


上面蓝色部分就是 aardio 代码,用这个方法就可以做很多事了,例如把 EXE 自身路径传给 LISP,就不再需要用 LISP 编码解码 EXE 的二进制数据了,速度可以大幅提升。


EXE 启动时就可以做太多事了,例如用 cad.LoadLisp() 加载 LISP 代码或 LISP 文件。可以用 cad.NetLoad 加载 C# 写的 DLL。都能自动识别版本,在需要时设置 SECURELOAD 开启并恢复权限、静默加载,不会弹出警告。


aardio 可以非常方便地打包外部文件生成独立 EXE 文件。
外部文件可以直接放到工程资源目录下 —— 通过 string.load("/res/xxxx") 函数加载。
也可以在文件路径前加一个 $ 将文件的二进制数据直接编译到程序里 —— 例如:$"/xxx/xxx.dll"。并且可以用io.appData("xxx/xxx.dll", $"/xxx/xxx.dll") 运行时释放到 AppData 目录返回路径。

当然如果只是使用cad.SendCommand() 这些 COM 接口,那外部文件也可以省了。





yanshengjiang 发表于 2021-5-30 23:48:16

你好 已经购买完全看不懂做什么用的啊

能不能给点实例

陨落 发表于 2021-5-29 12:24:35

指定父窗口的问题解决了,可以用while+grread放在exec之后阻塞程序即可。但现在问题在于指定了父窗口之后整个多文件选择的对话框都不正常了,不知道是aardio的原因还是这个api本身的原因。

liuyj 发表于 2021-5-29 12:54:19

有没有别的例子?如果这个写对话框方便,就多了一个新的思路

陨落 发表于 2021-5-29 15:15:20

liuyj 发表于 2021-5-29 12:54
有没有别的例子?如果这个写对话框方便,就多了一个新的思路

有。我已经试过了,拿来做模态和非模态对话框都是OK的

xj6019 发表于 2021-5-29 18:08:07

这个东西干什么用呀

陨落 发表于 2021-5-30 23:55:58

yanshengjiang 发表于 2021-5-30 23:48
你好 已经购买完全看不懂做什么用的啊

能不能给点实例

就是用来做多文件选择哈,这是一个函数。并非实用功能。

jun353835273 发表于 2021-6-1 13:05:59

c#的交互要方便的多
http://bbs.mjtd.com/thread-180931-1-1.html

xujinhua 发表于 2021-6-1 20:40:44

这个厉害了!谢谢一直没找到

jacenhe 发表于 2021-6-11 04:52:28

LISP 调用 aardio 的三种方法

本帖最后由 jacenhe 于 2022-2-13 04:11 编辑

方法一、aardio 创建 ActiveX 控件,在 LISP 中调用。

双击打开「aardio 范例 / COM 组件 / 创建 ActiveX EXE」示例工程:



点击「发布」生成 EXE 文件:



运行生成的 EXE,显示以下界面:



然后在 AutoCAD 中以如下 LISP 代码创建并调用 aardio 控件:
(setq aarObj (vlax-get-or-create-object "AardioTestControl.Sample"))(vlax-invoke aarObj 'Add 1 3)


方法二、执行以下 LISP 代码异步启动 aardio 编写的 EXE。

(startapp "d:/test/test.exe" (strcat "/hwnd" " " (itoa(vla-get-hwnd(vlax-get-acad-object)))))其实这里取窗口句柄、传窗口句柄是多余的,只是做个演示。在 aardio 中用 process.getParent().getMainWindow() 直接就可以取到 AutoCAD 主窗口。

我们可以在 aardio 里生成并执行 LISP 代码,顺带把 EXE 路径也写进去。EXE 启动以后也可以执行 LISP 代码、操作AutoCAD 对象,下面的范例里有演示。

方法三、下面示例演示的 startExe 函数阻塞启动 aardio 编写的 EXE。

EXE 文件的完整 aardio 源代码如下:
if(_STUDIO_INVOKED) error("请复制此代码到 aardio 工程的 main.aardio 内,然后生成 EXE 文件再运行",2);

import fsys.dlg;
import process;

var cmdline = io.stdin.read(); //自标准输入读取 LISP 传入的值
var parentProcess = process.getParent(); //获取父进程对象

if(! (cmdline && parentProcess) ){
    import console
    console.showLoading("正在为 为 AutoCAD 安装 startExe( cmdline ) 函数。");
   
    import com.cad;
    var cad = com.cad()
    cad.Visible = true;
   
    //直接添加函数
    cad.SendCommand(`(defun startExe(cmdline)
    (setq wsc (vlax-get-or-create-object "WScript.Shell"))
    (setq handle (itoa(vla-get-hwnd(vlax-get-acad-object))))
    (setq wsx (vlax-invoke wsc 'EXec <?
   
    //将当前 EXE 路径传入 lisp 代码,模板参数放入数组可自动处理转义字符,首尾自动加双引号。
    ={ io._exepath }
    ?>))
    (setq stat(vlax-get wsx 'status ))
   
    (setq stdin(vlax-get wsx 'StdIn ))
    (vlax-invoke stdin 'Write (strcat cmdline "\n"))
   
    (setq stdout(vlax-get wsx 'StdOut ))
    (setq out1 (vlax-invoke stdout 'Readall))
    out1
    )`)
   
    console.log("已为 AutoCAD 安装 startExe( cmdline ) 函数");
    console.pause();
    return;
}


import process;
import string.cmdline;

//解析命令行参数
var argv = string.cmdline.argv(` ` + cmdline);

//获取 AutoCAD 主窗口句柄
var hwndAutoCAD = parentProcess.getMainWindow();
//注意这时候 AutoCAD 是阻塞状态,不应也不必要设置所有者窗口为 hwndAutoCAD

//请在 AutoCAD 输入命令 (startExe "/c=dlg")
if(argv.c = "dlg"){
    var path = fsys.dlg.open();
   
    //把返回值写到标准输出
    if(path) io.stdout.write(path);
}
else {
    io.stdout.write("暂未支持此参数");
}

在 aardio 中创建一个空白工程,复制上面的代码到 main.aardio 中然后生成 EXE 就行了。
直接双击运行 EXE 文件会自动注册 startExe( cmdline ) 函数。
然后在 LISP 里可以这样调用:(startExe "/c=dlg")
这种方式调用过程中是阻塞状态,此时如果将任何窗口(不一定是 LISP 弹出的窗口)的父窗口设为 AutoCAD 主窗口都会卡死,直到执行的命令返回。所以这里没必要指定父窗口(准确说是所有者窗口)




页: [1] 2 3
查看完整版本: 我也来发一个多文件选择对话框,lisp+aardio实现