明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 7349|回复: 35

利用COM写工具箱面版

  [复制链接]
发表于 2019-12-26 01:48:16 | 显示全部楼层 |阅读模式
本帖最后由 guangdonglbq 于 2019-12-30 00:51 编辑

  现在有很多人写了自己的“工具箱”,由于大部分的“工具箱”是用lisp写的,界面往往就用dcl来写了,但写dcl通常是件比较麻烦的事情,所以也就出现了些开源了的工具箱面版生成库,方便大家编程。但总体来说,dcl写的界面,有点过于简陋,现有可以制作好看一些的界面的常见解决方案,有使用Opendcl,VBA,.Net(C#,VB.net,Python),ARX等的。但还有另外一种解决方案:使用简单易用的独立编程软件编写工具箱界面(exe文件),以com方式调用AutoCAD,并以发送命令或lisp语句的方式(可以是lisp程序或任何AutoCAD命令),调用写好的界面程序。  本次的程序界面解决方案:
  1.使用aardio写界面,理由:①软件比较小巧,仅5.9MB,方便使用和携带;②aardio语法类C/C++,有相关编程基础的,上手很容易;③aardio调用autocad很方便,与vba一样,一句CreateObject或GetObject就可以应用于所有版本的CAD(含AutoCAD、中望CAD、浩辰CAD),不用专门考虑引用不同的版本;
        注意,其实你可以使用任何语言写,只要写出来的程序能以com方案调用CAD软件就可以。
  2.工具箱里,点功能按钮后,利用cad的com接口函数CAD.ActiveDocument.SendCommand()函数,发送命令或lisp语句到CAD软件运行。
      3.在CAD环境里,单独写一个调用工具箱界面程序的lisp程序,用lisp的startapp函数打开工具箱面版。
      附上本方案aardio部分的源码。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x

评分

参与人数 3明经币 +5 金钱 +65 收起 理由
spp_wall + 1 + 30 很给力!
wowan1314 + 1 + 5 赞一个!
mikewolf2k + 3 + 30 很给力!

查看全部评分

发表于 2019-12-29 14:56:03 | 显示全部楼层
本帖最后由 jacenhe 于 2022-4-23 13:17 编辑

“COM 接口慢,甚至是调用 COM 接口的语言慢”—— 这个说法是不准确的。
COM 并不慢,只不过 AutoCAD 是进程外调用,相对进程内调用当然会有一点成本。
瞬间大量调用外部接口,这肯定会把微小的速度差异放大,但实际程序开发中一般没必要这样做,或者有其他方法避免。

跨进程调用在现代软件开发中其实很常用,不是非常夸张地密集调用对运行速度的影响一般可以忽略不计。
调用服务端 API 敢就更是跨过千山万水去调用了,相比进程间通信来说就更慢了,但这并不妨碍现代软件大量使用远程接口。

首先如果我们用 aardio 开发一个软件,至少图形界面这部分根本不需要与 AutoCAD 交互,也肯定存在大量不需要与 AutoCAD  直接交互的功能函数。

通过 COM 接口也可以调用 AutoCAD 执行 LISP ,而且与 LISP 交互并不一定非要通过 COM 接口,也可以使用其他编程语言动态生成 LISP 代码然后再执行。通过 COM 接口也可以调用 AutoCAD 加载 .Net 编写的 DLL,我在 aardio 里就提供了一个例子,在 aardio 里直接编译 C# 代码生成 DLL 程序集,然后再通过 COM 接口  cad.NetLoad() 加载 .Net 写的 DLL,再通过 cad.SendCommand() 就可以调用该 DLL。

参考:aardio 范例 / COM 组件 / AutoCAD



所以通过 COM 接口调用 AutoCAD 并不会丢失 LISP / .Net 的优势,而是在这个优势的基础上叠加了其他编程语言以及 COM 接口的优势。 我们使用任何一种技术,都是为了善用他的优势、扬长避短。



至于 aardio 与其他编程语言交互是非常方便的,
以 Python 为例,Google 一下 "aardio + Python " 可以找到很多 Python 用户分享的愉快体验。这是前几天一个 Python 用户给我的留言:
感谢aardio作者,我是刚开始用aardio写界面(实在不想用pyqt了),python写数据处理业务,感受到了aardio的强大和奇妙。我想把python数据处理过程的信息反馈到前端界面中,《这回让我们把 Python 玩出花来》看完后,用了几分钟搞定!!!实在令人惊讶aardio的强大!!!再次感谢aardio作者的奉献!!!

aardio 支持非常多的第三方编程语言,目前可以支持C语言、C++、C#、Java、Python、R、Javascript、Node.Js、Fortran、VB、Flash ActionScript、PHP、VBScript、PowerShell、NewLISP、AutoLISP、Delphi、FreeBASIC、Ruby、Rust、Julia、Nim、Go 语言、批处理 ...... 并且仍在继续增加中。说 aardio 资料少是一个误解,aardio 的资料不但非常多,而且可以直接利用大量第三方编程语言的资源。

aardio 语法接近 Javascript ,不需要过多的学习成本,历经 17年 活跃更新已经成熟且稳定
而且 aardio 非常小,开发环境仅 6.5 MB(包含开源的标准库、范例文档、开发环境),下载就可以使用,不需要任何复杂的配置。

曾经有知名博主针对某个 aardio 编写的开源软件 —— 与一系列其他语言编写的同类软件试用评测对比后得出的总结是:aardio 编写的软件运行最流畅,使用体验吊打同类软件,并且非常稳定从未遇到报错,而这个 aardio 软件只用了非常少的代码 —— 体积不到同类软件的十分之一,而其他用各种桌面开发工具开发的同类软件,不但界面不顺畅,各种恼人的 BUG 也非常多。所以 aardio 编写的桌面软件拥有良好的可靠性

我们先看一些 aardio 编写的开源软件:
最近很受欢迎的开源录屏软件 Gif123 就是用 aardio 写的,体积仅 820 KB,无任休何外部依赖,单文件绿色软件,兼容 XP,Vista,Win7,Win8,Win10,Win11 …… 等所有流行桌面操作系统。



开源项目 WubiLex,仅积仅 890KB,同样是单文件绿色软件。百度贴吧一个关于 WubiLex 的讨论帖子已经超过 1200 回复,WIN10系统自带五笔的码表与短语词库安装、管理工具,并可增强微软五笔的设置、热键等功能。只要一个EXE文件,不需要安装,不需要任何DLL依赖。软件已自带五笔86、98、091、新世纪码表,以及极点五笔、QQ五笔、微软五笔默认词库、昱琼词库、海峰词库等。甚至自带了郑码词库、可以一键把微软五笔替换为郑码输入法



开源项目 WinAsar,体积仅 500KB,单文件,不需要运行时,支持所有 Windows 操作系统,Electron asar 文件打包、解包工具,不需要安装 Node.js,纯 aardio 代码实现的 asar 解析器。



下面这个是 8 年前 aardio 写的开源项目,作者仅临时学了个把月 aardio



类似的还有很多,就不再截图了。

aardio 编写程序代码非常简洁,几句代码就是一个独立可运行的程序,下面我们直接上代码演示一下。


一个示例可以看到 aardio 窗口嵌入 .Net 控件有多简单:
import win.ui;
var winform = win.form(text="DataGridView")

import System.Data;
var tab = System.Data.DataTable("DT");
tab.Columns.Add(
"名称");
tab.Rows.Add({
"WangWu"});

import System.Windows.Forms;
var grid = System.Windows.Forms.CreateEmbed("DataGridView",winform);
grid.ColumnHeadersHeightSizeMode = 2;
grid.DataSource = System.Data.DataView(tab);
   
winform.show();
win.loopMessage();


下面演示一下用 aardio 调用 PowerShell,并且在 PowerShell 中调用 aardio。这甚至都不用带上体积较大的 System.Management.Automation.dll,一个轻巧的 EXE 就可以搞定一切,向下兼容到 PowerShell 2.0。
var pScript = /*

# 声明 PowerShell 参数
param($win)  

# 修改 aardio 对象属性
$win.title = "owerShell + aardio";

# 调用 aardio 对象函数
$win.msgbox("这是 PowerShell 调用 aardio 打开的对话框。")  
*/


import win;
dotNet.ps(pScript,{
  win = win;
//# 将 aardio 对象作为参数传给 PowerShell
});

aardio 直接调用系统 API 函数:

import console;

//不需要声明,直接调用原生 API 函数,语法简洁可读性好。
var result = ::User32.PtInRect( ::RECT(2,3,300,500) , 12, 66 );

console.log( result );
console.pause(
true);

将任何网络 API 甚至是任意普通网址声明为 aardio 对象:
import web.rest.jsonLiteClient;
var http = web.rest.jsonLiteClient();

//导入远程 API
var countApi = http.api("https://api.countapi.xyz/hit{/domain}{/key}")

//服务器 API 已经变成了 aardio 函数对象
var data = countApi["key"].get();

编译 C 语言代码生成 DLL 执行文件,再调用 DLL 中的 C 函数:
import tcc;  
//编译 DLL
tcc.build( "/start.dll" ).code = /***
#include <windows.h>
__declspec(dllexport) int Add( int a,int b )
{     
  return a + b;
}
***/


//加载 DLL
var dll = raw.loadDll( "/start.dll",,"cdecl" );
//调用 C函数
var result = dll.Add(12,3);

屏幕找字:
import mouse;
import string.ocrLite;
import string.ocrLite.defaultModels;

var ocr = string.ocrLite();
var ocrResult = ocr.detectScreen();
var x,y = ocrResult.findPoint("要查找的按钮文本",0.1);
mouse.moveTo(x,y,
true);

在 aardio 中调用 Python,简单得就像在 Python 中使用 Python:
import console;
import py3;

//导入 Python 模块。
var itertools = py3.import("itertools")

//调用 Python 函数,支持纯 aardio 类型参数
var permutations = itertools.permutations({"a","b","c"});

//调用 Python 内置函数 list
var pyList = py3.list(permutations);

//遍历 Python 对象成员
for( item in pyList.each() ){
  console.log(item);
//像 aardio 对象一样使用 Python 对象
}

console.pause();

播放 GIF 动画:
import win.ui;
/*DSG{{*/
var winform = win.form(text="GIF 动画";bgcolor=0xEDDDD8)
winform.add(
plus={cls=
"plus";left=0;top=0;right=760;bottom=470;repeat="scale";z=1}
)
/*}}*/

import inet.http;
winform.plus.background =
"http://download.aardio.com/v10.files/demo/plus-demo.gif";

winform.show();
win.loopMessage();

调用微软 WebView2 控件截图:
import win.ui;
/*DSG{{*/
var winform = win.form(text="WebView2 网页截图";right=1108;bottom=759)
/*}}*/

import web.view;
var wb = web.view(winform,,0/*自动调试端口*/);
winform.show();

wb.go(
"http://www.baidu.com");
wb.wait(
"baidu");

import web.socket.chrome;
var ws = wb.openRemoteDebugging();
ws.Runtime.enable();
//启用 Runtime.executionContextCreated

//截图
import crypt;
import process.imageView;
ws.Page.captureScreenshot().end =
function(result,err){
   
if(result[["data"]]){
       string.save(
"/screenshot.png",crypt.decodeBin(result[["data"]]) )
       process.imageView(
"/screenshot.png");
   }
}

win.loopMessage();

获取系统 TPM 版本信息:
import console;

import sys.tpmInfo;
var tpmInfo = sys.tpmInfo.get();

if(tpmInfo){
  console.log(
"支持 TPM");
  console.log(
"TPM 是否启用:",tpmInfo.enabled);
  console.log(
"TPM 是否激活:",tpmInfo.activated);
  console.log(
"TPM 支持版本:",tpmInfo.version)
}
else {
  console.log(
"不支持 TPM");
}

console.pause();

查看系统安装序列号:
import com.wmi;
import win.reg;

var productKey = com.wmi.get("softwarelicensingservice","OA3xOriginalProductKey");
if(!productKey) {
  productKey = win.reg.queryWow64(
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform","BackupProductKeyDefault" )   
}

import console;
console.log(
"安装序列号" ,productKey);
console.pause(
true);

调用 .Net 创建 WebService:
import console;
import dotNet;

//创建应用程序域(无参数创建唯一实例,不必手动释放)
var appDomain = dotNet.appDomain();

//动态创建Web服务
var webService = appDomain.createWebService("http://fy.webxml.com.cn/webservices/EnglishChinese.asmx")  

//调用WebService接口创建类
var englishChinese = webService.createInstance("EnglishChinese")  

//调用WebService提供的函数
var ret = englishChinese.TranslatorString("hello" );

console.dump(ret);
console.pause();




其实不用调用 .Net ,纯 aardio 代码调用 WebService 更简单,。
以前研究过 MSSOAP ,要依赖一堆 DLL 文件,这不符合 aardio 的风格。所以我自己研究了一下 SOAP 协议写了个 web.soapClient , 几句代码搞定,不依赖任何外部组件:
import console;

//导入MSSOAP支持库
import web.soapClient;

//创建SOAP客户端
seviceClient = web.soapClient("http://fy.webxml.com.cn/webservices/EnglishChinese.asmx")

//调用远程Web服务提供的函数
var transArray,err =  seviceClient.TranslatorString("hello");

//显示返回值
console.dump( string.join( transArray,'\r\n' ) ) ;

//按任意键继续
console.pause();

在 aardio 中嵌入并调用批处理:
import console
import process.batch;

//批处理 for 遍历并拆分字符串
var bat = process.batch(`
@echo off
for %%i in (abc,def,xyz) do echo %%i
`
)
console.log(bat.read(-1))

console.pause()

调用命令行,并自动触发 Ctrl + C :
import console
import process.popen

var prcs = process.popen("ping 127.0.0.1 -n 10 ")
for( all,out,err in prcs.each() ){
    console.log( out,err );
    prcs.ctrlEvent(0);
}

console.pause();

调用 Rust 语言解析 TOML :
import console;
import string.toml;

var str = string.toml.stringify({abc=123,d={1,2,3}});
console.log( str );

import process.code;
process.code(
"~\lib\string\toml\.res");
console.pause(
true);

在 aardio 里嵌入 PHP,以下短短几句代码,包含了 HTTP 服务器,PHP服务端,嵌入的浏览器组件:
import win.ui;
/*DSG{{*/
var winform = win.form(text="Hello World / PHP_CGI 服务器")
/*}}*/

var code = /*
<html>
<head>
<meta charset="utf-8">
<title>HP 测试</title>
</head>
<body>
<?php echo '<p>Hello World / PHP_CGI 服务器</p>'; ?>
</body>
</html>
*/

string.save(
"/test.php",code);

import php.simpleHttpServer;
var url = php.simpleHttpServer.startUrl("/test.php");

import web.form;
var wb = web.form(winform);
wb.go(url);

winform.show();
win.loopMessage();

执行 Ruby 语言代码:
import win.ui;
/*DSG{{*/
var winform = win.form(text="执行Ruby代码")
winform.add(
edit={cls=
"edit";left=26;top=16;right=737;bottom=435;multiline=1;z=1}
)
/*}}*/

import process.ruby;
var out = process.ruby.exec("puts '测试UTF-8'")
winform.edit.print(out);

var out = process.ruby.eval(`[1, 2, { name: "tanaka", age: 19 }]`)
winform.edit.print(out);

winform.show();
win.loopMessage();









本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x

评分

参与人数 1明经币 +1 收起 理由
363001640 + 1 赞一个!

查看全部评分

回复 支持 1 反对 0

使用道具 举报

发表于 2020-1-20 14:03:09 | 显示全部楼层
http://bbs.mjtd.com/thread-180739-2-1.html
请教一下,为什么最后一句老是出错?
console.log(name)                                vl=object.GetInterfaceObject("VL.Application.16");
console.log(vl)
                               
doc=vl.ActiveDocument;
console.log(doc)       
funcs=doc.Functions;                                console.log("funcs=");console.log(funcs);
                               
var func_done_dialog=funcs.item("done_dialog").funcall(1);
发表于 2019-12-26 07:29:12 来自手机 | 显示全部楼层
好贴,谢谢楼主分享!
发表于 2019-12-26 07:52:13 来自手机 | 显示全部楼层
楼主分享的程序都是精品,每个都值得学习
发表于 2019-12-26 08:22:08 | 显示全部楼层
谢谢楼主分享!
发表于 2019-12-26 08:57:07 | 显示全部楼层
不会用呀这个面板
发表于 2019-12-26 10:05:29 | 显示全部楼层
开了多个cad的情况下,createobject如何去判断是哪个cad?
发表于 2019-12-26 12:09:36 | 显示全部楼层
楼主怎么用啊,没用过com能不能教下如何运行如何使用
 楼主| 发表于 2019-12-26 12:44:37 | 显示全部楼层
陨落 发表于 2019-12-26 10:05
开了多个cad的情况下,createobject如何去判断是哪个cad?

先用GetObject获取活动cad对象,失败时才会尝试GreateObject。
 楼主| 发表于 2019-12-26 12:45:08 | 显示全部楼层
664571221 发表于 2019-12-26 12:09
楼主怎么用啊,没用过com能不能教下如何运行如何使用

先搜索,了解一下com
发表于 2019-12-26 14:01:35 | 显示全部楼层
guangdonglbq 发表于 2019-12-26 12:44
先用GetObject获取活动cad对象,失败时才会尝试GreateObject。

我说错了,就是getobject
你这个思路我早就用Python试过了
最大的问题就在于getobject只能get到“活动”对象,如果我开了3个cad,你告诉我哪个是“活动”对象?
为了解决这个问题我还捣鼓了半天ROT,没用,搞不定
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-11-25 02:36 , Processed in 0.192179 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表