- 积分
- 39619
- 明经币
- 个
- 注册时间
- 2006-8-18
- 在线时间
- 小时
- 威望
-
- 金钱
- 个
- 贡献
-
- 激情
-
|
本帖最后由 highflybir 于 2011-11-20 09:46 编辑
越飞越高讲堂(2)
CAD中如何利用API 编程呢?
对于arx来说,这点根本就不是问题,直接用api函数,因为它已经成了C++的内部函数了。对于VBA来说,也不太成问题。利用VBIDE中插入模块,申明API函数,就可以用了。对于VLISP来说,就需要借助其他工具了,譬如调用编译好的dll, 或者调用其他的例如EXCEL的VBA,或者调用CAD的VBA,都需要用读写文件的方式或者暂时写入VBIDE的方式,这方面的研究nonsmall和aroom等都发表了帖子,研究得很详细了。下面我要用另外一种方式来实现它。
(上部)DynWrapX和VLISP中的API
首先申明:此文属于首创,如需转载请说明来源和作者!
不用OpenDCL,不用VB和VBA,不用ARX,下面的一些你能做到吗?
你想使得你的对话框(我这里特指DCL)添加菜单吗?你想在你的DCL中添加真彩色图片或者做成各种特效,譬如渐变的背景?你想运用各种API函数为你的程序锦上添花吗?甚至完成以前不敢想象的事情?你想函数对参数传址使用么?你想得到比grread还强大的效果吗?你想创建一个非模态的DCL吗?甚至你想在LISP中嵌入汇编语言吗?等等。
如果你有了DynamicWrapperX这个插件,你什么都可以做了。
DynamicWrapperX 是一个ActiveX部件,它允许调用DLL库里面的函数,特别是API 的函数。可用于 Jscript和VBscript。它由汇编语言写成。短小精悍,才 13Kb,压缩后才5kb,比OpenDCL.arx甚至自己做的.dll文件都小很多,你甚至可以将它打包到vlx文件中。虽然它很小,但是很给力。
它可以极大程度地扩展LISP的编程范围,赋予DCL和VLISP更多功能。它可以适应不同的CAD版本,兼容windows98~windows 7。
首先给出这个插件的英文帮助和下载地址:
http://www.script-coding.com/dynwrapx_eng.html
我这里另贴上:
DynWrapX.dll 文件这个是DynamicWrapperX 插件
Win32API.txt 文件这个不是必需的,是api 函数的查看文件,api viewer用的WIN32API.TXT -- Win32 API Declarations for Visual Basic
如何在系统中注册:
在windows下有两种方法:
1.运行 regsvr32.exe 插件路径\dynwrapx.dll, 注册给所有用户;
2.运行 regsvr32.exe /i 插件路径\dynwrapx.dll, 注册给当前用户;
如果你把它拷贝到system32目录下,直接运行 regsvr32.exe dynwrapx.dll就可了。
反注册用 regsvr32.exe /u插件路径\dynwrapx.dll和 regsvr32.exe /u /i 插件路径\dynwrapx.dll。
在windows 7 下,读者应该注意这点:需要以管理员身份注册运行。建议拷贝到其他目录注册运行。
http://support.microsoft.com/kb/827659
内部函数简介:
1. Register( DllName, FuncName [, i=ParamTypes] [, r=RetValType] )
注册一个DLL中的函数,dllName,dll文件名,funcName,dll里面的函数名,i参数类型,r返回值类型。
2. RegisterCallback( FuncRef [, i=ParamTypes] [, r=RetValType] )
注册一个回调函数,FuncRef按址引用的函数名,i参数类型,r返回值类型。
3. NumGet( Address [, Offset] [, Type] )
得到某个指针的内容,Address指针地址,Offset偏移值,Type数值类型。
4. NumPut( Var, Address [, Offset] [, Type] )
改变某个指针的内容,Var,要赋值的变量,Address指针地址,Offset偏移值,Type数值类型。
5. StrPtr( Var [, Type] )
得到一个字符串的指针(实际也是创见一个指针的方法),var 字符串,type是类型
6. StrGet( Address [, Type] )
读取某个指针的值,Address地址,type类型。
7. Space( Count [, Char] )
创建指定长度和指定字符的字符串。Count,字符串长度,char指定的字符
创建、释放和注册函数:
创建:(setq wrap (vlax-create-object "DynamicWrapperX"))
释放:(vlax-release-object wrap)
注册函数: (vlax-invoke wrap 'Register "user32.dll" "MessageBoxW" "i=hwwu" "r=l")
可以看出,这个甚至比VB中API函数的引用更简单。
;; 关于MessgeBox函数参见 http://baike.baidu.com/view/927800.htm
先创建几个下面用得着的对象
- (setq *APP (vlax-get-acad-object))
- (setq *DOC (vla-get-ActiveDocument *APP))
- (setq hCAD (vla-get-hwnd *APP))
- (setq hDOC (vla-get-hwnd *DOC))
- (setq wrap (vlax-create-object "DynamicWrapperX"))
几个简单的例子:
- ;; 例如一个简单的消息框
- (vlax-invoke wrap 'Register "user32.dll" "MessageBoxW" "i=hwwu" "r=l")
- ;; 'Register 注册;
- ;; "User32.dll",可以省略为"USER32",也可以是自己的dll,例如"MyLib.dll";
- ;; "MessageBoxW" ,API函数名字,功能是弹出一个消息框;
- ;; "i=hwwu",是参数列表,见函数原型:
- ;; int MessageBox(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT UType);
- ;; h,父窗口句柄,w,宽字符,消息内容,w宽字符,标题文字,u,无符号整数,指的是消息框的类型
- ;; "r=l"代表返回数值是整数。
- (vlax-invoke wrap 'MessageBoxW hCAD "Hello,DynWrap" "Test for API" 2)
- ;; 返回值代表如下:
- ;; IDOK 1 按下"OK"
- ;; IDCANCEL 2 按下"取消"
- ;; IDABORT 3 按下"放弃"
- ;; IDRETRY 4 按下"重试"
- ;; IDIGNORE 5 按下"忽略"
- ;; IDYES 6 按下"是"
- ;; IDNO 7 按下"否"
- ;; IDCLOSE 8 按下"关闭"
- ;; IDHELP 9 按下"帮助"
- ;; 获得当前进程的命令行
- (vlax-invoke wrap 'Register "kernel32" "GetCommandLine" "r=s")
- ;; 这个函数没有参数,故而没有"i="
- (vlax-invoke wrap 'GetCommandLine)
- ;; 譬如返回:"C:\\Program Files\\AutoCAD 2006\\acad.exe\" 这样,我们就知道程序的所在目录和名称。
- ;; 发出蜂鸣声
- (vlax-invoke wrap 'Register "kernel32" "Beep" "i=uu") ;蜂鸣声有返回值但可以不需要.
- (vlax-invoke wrap 'Beep 800 1000) ;通过喇叭发出声音.
参数符号代表的类型:
l - 32位整数 - LONG, INT, LPARAM, LRESULT, etc, 范围: -2147483648 ... 2147483647;
u - 无符号32位整数 - ULONG, UINT, DWORD, WPARAM, ... , 范围: 0 ... 4294967295;
注意,在lisp中,无符号的整数如果超出2147483647 会溢出,例如(+ 2147483647 1)
返回-2147483648
h - 句柄 - HANDLE, HWND, HMODULE, HINSTANCE, HICON, ... , 范围: -2147483648 ... 4294967295;
p - 指针; 就是一个数值,对象或者字符串的地址。
n - 16位整数- 短整数, 范围: -32768 ... 32767;
t - 无符号16位整数- USHORT, WORD, WCHAR, OLECHAR, ... , 范围: 0 ... 65535;
c - 8位整数- CHAR, 范围: -128 ... 127;
b - 无符号8位整数- UCHAR, BYTE, ... , 范围: 0 ... 255;
f – 浮点数 - FLOAT;
d – 双精度数 - DOUBLE;
w - Unicode 字符串 - BSTR, LPWSTR, LPOLESTR, OLECHAR *, WCHAR *, ...;
s - ANSI/Windows 字符 (默认代码页) - LPSTR, LPCSTR, CHAR *, ...;
z - OEM/DOS字符(默认代码页) - LPSTR, LPCSTR, CHAR *, ...
返回值也是如此。但是我们在lisp中用到最多的是l数值型,可以代表指针,也可以代表长整数,短整数,甚至布尔值等等。
关于字符串的宽字符和ASCII字符,请读者自行参考相关资料。
RegisterCallBack方法:
鉴于LISP对于函数的地址取得的方式和对参数的保护模式,所以这个函数对LISP意义不大,略去。
其他方法:
NumGet( Address [, Offset] [, Type] )
从一个地址中获取数值。Address,基址,Offset偏移量,能用于循环读写一系列的数值。Type,数值类型,默认”l”,即长整数,只能小写字母。返回值就是这个地址中的内容。
NumPut( Var, Address [, Offset] [, Type] )
写入数值到内存中。Var,要写入的变量,剩下的几个参数跟NumGet相同。返回值是写入的字节数。
上面两个函数,允许你在基址占用的内存中存取数据(结构,数组等)。
StrPtr( Var [, Type] )
创建一个字符串指针,然后你可以在这个字符串占用的内存中存取数据(结构,数组等)。Var,是字符串变量或者常量,type是字符串类型,可以是”w”(默认方式),”s”,”z”。返回一个指针(即一个长整数)。
StrGet( Address [, Type] )
从指定地址中,读取字符串,并返回其拷贝。Address可以是数值变量的地址,也可以是字符串的首址,type 同StrPtr。
Space( Count [, Char] )
创建指定长度指定字符的字符串。Count,数量,Char,指定字符,如果没这个参数,指定字符就是空格。
下面是其用法例子:
- ;; 取得某个地址的内容,例如读取字符串的ASCII代码
- ;; 其实就是(vl-string->list "Hello, world! It's me.")
- ;l 举这个例子仅仅是说明其用法。
- (setq str "Hello, world! It's me.")
- (setq sLen (strlen str))
- (setq codes "")
- (setq i 0)
- (repeat sLen
- (setq code (vlax-invoke wrap 'NumGet Str (* i 2) "t")) ;乘以2是因为偏移必须是两个字节"t"
- (setq codes (strcat codes (itoa code) " "))
- (setq i (1+ i))
- )
- (alert codes)
-
-
- ;; 读取并写入内存,例如反转字符串.
- ;; 这个例子就是反转字符串。
- ;; 对中文字符串要复杂些
- (setq buf (vlax-invoke wrap 'Space sLen))
- (setq pBuf (vlax-invoke wrap 'StrPtr Buf "s")) ;获得缓冲区地址,用来读写
- (setq i 0)
- (setq j (1- sLen)) ;最后一个下标要字符串长度减1
- (repeat sLen
- (setq code (vlax-invoke wrap 'NumGet Str (* i 2) "t")) ;从左到右读
- (vlax-invoke wrap 'NumPut code pBuf (* j 2) "t") ;从右到左写入缓冲区
- (setq j (1- j)) ;偏移地址增加
- (setq i (1+ i)) ;偏移地址减少
- )
- (alert (vlax-invoke wrap 'StrGet pBuf)) ;最后读取缓冲区内容
运用上面方法也可以用来通过改变地址内容改变变量值,即对函数参数的传址使用。
更精彩的在后面:
具体运用和实例剖析:
请见下面的完整的例子:其中已经有注释,包含了详细的解释。
在此特别感谢nonsmall,在编写这个程序过程中得到了他的很多帮助及其建议。
另外一些关于用LISP调用API的链接:
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=72145&highlight=API
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=74063&highlight=API
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=60155&highlight=API
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=60884&highlight=API
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=84651&highlight=API
提醒:因为用到了API,可能会对内存有读写,所以编程前应保存工程。注意对内存的释放和存取可操作性。
多谢Caiqs的建议,"如果你有了DynamicWrapperX这个插件,你什么都可以做了。"这句话我夸大其词了,具体有哪些不能做的,请参考70楼。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?注册
x
评分
-
查看全部评分
|