设为首页收藏本站

就爱编程论坛

 找回密码
 注册

人人连接登陆

无需注册,直接登录

用新浪微博连接

一步搞定

QQ登录

只需一步,快速开始

查看: 433|回复: 0
打印 上一主题 下一主题

CAD的API编程指南(上)--DynamicWrapperX [复制链接]

Rank: 9Rank: 9Rank: 9

  • TA的每日心情
    无聊
    2025-5-27 03:37:20
  • 签到天数: 366 天

    [LV.9]以坛为家II

    论坛先锋 学习至圣 荣誉成员 论坛元老 活跃之星 终极领袖

    我玩的应用:

    跳转到指定楼层
    楼主
    发表于 2012-3-25 22:17:43 |只看该作者 |倒序浏览
    可以看下这个:http://bbs.mjtd.com/thread-85724-1-1.html
    是一个类似的插件使用方法


    越飞越高讲堂(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"))


    普通浏览复制代码保存代码打印代码
    •   (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"))



      (setq *APP (vlax-get-acad-object))<br />   (setq *DOC (vla-get-ActiveDocument *APP))<br />   (setq hCAD (vla-get-hwnd *APP))<br />   (setq hDOC (vla-get-hwnd *DOC))<br />   (setq wrap (vlax-create-object "DynamicWrapperX"))<br />



    几个简单的例子:
    •   ;; 例如一个简单的消息框
    •   (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)                              ;通过喇叭发出声音.


    普通浏览复制代码保存代码打印代码
    •   ;; 例如一个简单的消息框
    •   (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)                              ;通过喇叭发出声音.



      ;; 例如一个简单的消息框<br />   (vlax-invoke wrap 'Register "user32.dll" "MessageBoxW" "i=hwwu" "r=l")<br />   ;; 'Register 注册;<br />   ;; "User32.dll",可以省略为"USER32",也可以是自己的dll,例如"MyLib.dll";<br />   ;; "MessageBoxW" ,API函数名字,功能是弹出一个消息框;<br />   ;; "i=hwwu",是参数列表,见函数原型:<br />   ;; int MessageBox(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT UType);<br />   ;; h,父窗口句柄,w,宽字符,消息内容,w宽字符,标题文字,u,无符号整数,指的是消息框的类型<br />   ;; "r=l"代表返回数值是整数。<br />   (vlax-invoke wrap 'MessageBoxW hCAD "Hello,DynWrap" "Test for API" 2)<br />   ;; 返回值代表如下: <br />   ;; IDOK 1                    按下"OK"<br />   ;; IDCANCEL 2                按下"取消"<br />   ;; IDABORT 3          按下"放弃"<br />   ;; IDRETRY 4           按下"重试"<br />   ;; IDIGNORE 5           按下"忽略"<br />   ;; IDYES 6                按下"是"<br />   ;; IDNO 7           按下"否"<br />   ;; IDCLOSE 8          按下"关闭"<br />   ;; IDHELP 9                按下"帮助"<br /> <br />  ;; 获得当前进程的命令行<br />   (vlax-invoke wrap 'Register "kernel32" "GetCommandLine" "r=s")<br />   ;; 这个函数没有参数,故而没有"i="<br />   (vlax-invoke wrap 'GetCommandLine)<br />   ;; 譬如返回:"C:\\Program Files\\AutoCAD 2006\\acad.exe\" 这样,我们就知道程序的所在目录和名称。<br /> <br />  ;; 发出蜂鸣声<br />   (vlax-invoke wrap 'Register "kernel32" "Beep" "i=uu")             ;蜂鸣声有返回值但可以不需要.<br />   (vlax-invoke wrap 'Beep 800 1000)                              ;通过喇叭发出声音.<br />



    参数符号代表的类型:
    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))                        ;最后读取缓冲区内容


    普通浏览复制代码保存代码打印代码
    •   ;; 取得某个地址的内容,例如读取字符串的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))                        ;最后读取缓冲区内容



      ;; 取得某个地址的内容,例如读取字符串的ASCII代码<br />   ;; 其实就是(vl-string->list "Hello, world! It's me.")<br />   ;l 举这个例子仅仅是说明其用法。<br />   (setq str "Hello, world! It's me.")<br />   (setq sLen (strlen str))<br />   (setq codes "")<br />  (setq i 0)<br />   (repeat sLen<br />     (setq code (vlax-invoke wrap 'NumGet Str (* i 2) "t"))        ;乘以2是因为偏移必须是两个字节"t"<br />     (setq codes (strcat codes (itoa code) " "))<br />     (setq i (1+ i))<br />  )<br />   (alert codes)                                <br />                                           <br />    <br />  ;; 读取并写入内存,例如反转字符串.<br />   ;; 这个例子就是反转字符串。<br />  ;; 对中文字符串要复杂些<br /> <br />   (setq buf (vlax-invoke wrap 'Space sLen))                        <br />   (setq pBuf (vlax-invoke wrap 'StrPtr Buf "s"))                ;获得缓冲区地址,用来读写<br />   (setq i 0)<br />   (setq j (1- sLen))                                                ;最后一个下标要字符串长度减1<br />   (repeat sLen<br />     (setq code (vlax-invoke wrap 'NumGet Str (* i 2) "t"))        ;从左到右读<br />     (vlax-invoke wrap 'NumPut code pBuf (* j 2) "t")            ;从右到左写入缓冲区<br />     (setq j (1- j))                                                ;偏移地址增加<br />     (setq i (1+ i))                                                ;偏移地址减少<br />   )        <br />   (alert (vlax-invoke wrap 'StrGet pBuf))                        ;最后读取缓冲区内容<br />



    运用上面方法也可以用来通过改变地址内容改变变量值,即对函数参数的传址使用。

    更精彩的在后面:

    具体运用和实例剖析:
    请见下面的完整的例子:其中已经有注释,包含了详细的解释。


    在此特别感谢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楼。


    该贴已经同步到 admin的微博
    分享到: QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    分享分享0 收藏收藏0 支持支持0 反对反对0 分享到人人 转发到微博
    [img=http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=fRUcHhYWGAQ9GxIFEBwUEVMeEhA]http://rescdn.qqmail.com/zh_CN/htmledition/images/function/qm_open/ico_mailme_02.png[/img]

    使用道具 举报

    您需要登录后才可以回帖 登录 | 注册 人人连接登陆

    晴云孤魂's Blog|就爱编程搜帖|手机版|Archiver|就爱编程论坛     

    GMT+8, 2025-7-1 19:00 , Processed in 0.090611 second(s), 26 queries .

    Powered by Discuz! X2

    © 2001-2011 Comsenz Inc.

    回顶部