- UID
- 64627
- 积分
- 419
- 精华
- 贡献
-
- 威望
-
- 活跃度
-
- D豆
-
- 在线时间
- 小时
- 注册时间
- 2003-7-13
- 最后登录
- 1970-1-1
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本帖最后由 newer 于 2018-5-14 09:31 编辑
这几天闲的无聊,突然发现所有的 lisp 函数都是有指针的
比如:(princ setq) #<SUBR @000000003364d520 SETQ>
那个 @ 后面跟的就是 16 进制的指针,代表 setq 函数存储在内存里的地址
而且,64 位 CAD 存储了 64 个 2 进制,也就是 16 个 16 进制
32 位 CAD 存储了 32 位 2 进制,也就是 8 个 16 进制
利用这个规律可以判断 CAD 是 64 位还是 32 位,代码如下:
 - ;;CAD 位数判断,如果是 64 位返回 t,否则返回 nil
- (defun isACAD64 ()
- (= 17
- (strlen
- (vl-prin1-to-string
- (cadr (read (strcat "(" (vl-prin1-to-string +) ")")))
- )
- )
- )
- )
同样,定义了一个 defun 函数也可以得到该函数的指针,再利用 Windows API 调用这个函数
使用时需要将 16 进制的指针转换为 10 进制,代码如下:
 - ;;查询任意 lisp 函数的指针, 示例: (getPtrs setq)
- (defun getPtrs (cm / hex ss m n sum)
- (setq hex '(("F" . 15)
- ("E" . 14)
- ("D" . 13)
- ("C" . 12)
- ("B" . 11)
- ("A" . 10)
- ("9" . 9)
- ("8" . 8)
- ("7" . 7)
- ("6" . 6)
- ("5" . 5)
- ("4" . 4)
- ("3" . 3)
- ("2" . 2)
- ("1" . 1)
- ("0" . 0)
- )
- )
- (if (= 'SUBR (type cm))
- (progn (setq ss (substr (vl-prin1-to-string cm)
- 9
- (if (isACAD64)
- 16
- 8
- )
- )
- ss (strcase ss)
- n (strlen ss)
- m 0
- sum 0
- )
- (while (> n 0)
- (setq sum (+ (* (cdr (assoc (substr ss n 1) hex)) (expt 16 m)) sum)
- n (1- n)
- m (1+ m)
- )
- )
- sum
- )
- )
- )
例如,API 定时器
Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
第一个参数 hWnd 代表当前父窗口的句柄,默认为 0
第二个参数 nIDEvent 是定时器的编号,可以从 1 开始
第三个参数是定期激发的时间间隔,单位毫秒
第四个参数是回调函数的指针。
这样,调用 SetTimer API 函数可以完美实现 lisp 的多线程和定时器效果。
试验一下 dwx 调用 API ?
LISP+DWX 之二:结构类型与传址参数
问题
lisp 基本数据类型有整型、实型、字符型、表等,其中表是最主要的数据类型,lisp也因此而得名。
而在 API 函数中有大量的结构类型(这是来自 C、C++ 的叫法),那么结构体如何与 lisp 交换数据?
解决方法
lisp 函数调用时,我们通常都是用传值的方式(ByVal),调用后并不影响参数本来的值。
例如 (setq a 2)(sqrt a) 将 a 值传给运算函数 sqrt,得到 1.414 的返回值,不用担心参数 a 值改变。
在 lisp+dwx 中,可以先分配一块内存,并将地址传给 API 函数,我们称这种方式为传址(ByRef),
然后通过分析返回值在内存里的数据结构,得到我们想要的东西。
示例
API函数: 获取鼠标指针的当前位置,在 VB 中声明语法如下
Declare Function GetCursorPos Lib "user32" Alias "GetCursorPos" (lpPoint As POINTAPI) As Long
这个函数用 lpPoint 来接收当前鼠标位置的信息,lpPoint 是一个结构变量,记录了鼠标在屏幕上的坐标,
在 VB 中可以轻松的定义一个 POINTAPI 类型
Private Type POINTAPI
X As Long
Y As Long
End type
需要 x,y 值的时候,用 POINTAPI.x, POINTAPI.y 即可表示,这是面向对象的数据结构
但是 lisp 中没有 Type 型数据,用 dwx 解决如下:
;;创建 dwx 对象
(setq dwx (vlax-create-object "DynamicWrapperX"))
;;将 API 函数绑定(注册)为 dwx 的方法
;;说明: i=p 表示输入一个参数, p 为指针类型; 这里我们准备用内存块的地址来响应,因此是 p 类型
;;r=l 表示返回一个参数, l 是长整型;根据 API 说明,返回 1 代表成功,0 代表失败
(vlax-invoke dwx 'Register "user32" "GetCursorPos" "i=p" "r=l")
;;分配一块内存充当结构体,用内存块的指针作为结构体的参数
;;说明: MemAlloc 方法分配 20 个字节够存储坐标,实际上 8 个字节就够了,但我的电脑有 16GB 的内存。
;;参数 1 表示将新开辟的内存块全部归零,返回值 nP 是新分配内存地址,称为内存指针存入 nP 变量
(setq nP (vlax-invoke dwx 'MemAlloc 20 1))
;;API 函数调用后,np 指向的内存值就会发生变化
(vlax-invoke dwx 'GetCursorPos nP)
但是我们并不知道像素坐标 x,y 值在内存块里是怎么存储的,可以假设是这么存储的
0000xxxx00000yyyy00000000
验证测试,先读两个字节,n 为短整型,占 2 字节
(vlax-invoke dwx 'NumGet nP 0 "n")
返回值 765 ,看来我们已经得到了 x 的像素;跳过 2 字节,继续读内存,返回 0
(vlax-invoke dwx 'NumGet nP 2 "n")
继续跳过 2 字节,得到 y 坐标 978
(vlax-invoke dwx 'NumGet nP 4 "n")
这说明了像素坐标 x,y 的结构体在内存里占 4 个字节是 "l" 类型,而且是数字倒着存储的,
细思极妙,这样能更有效的读入数据,不至于一开始先读入一堆 0
765 占 2 字节 00000010 11111101
978 占 2 字节 11010010 00000011
按我们的猜想将 x y 按字节颠倒一下,可以得出鼠标位置在内存存储为:
11111101 00000010 00000000 00000000 11010010 00000011 00000000 00000000
继续验证,读入该块内存块的前 10 个字节,返回 16 进制的字符串(hex值)
(vlax-invoke dwx 'MemRead nP 10)
得到 "FD020000D20300000000" 将 16 进制转换为二进制,发现两者完全相同。
 - ;;获取当前鼠标在 Windows 系统里的坐标位置
- (defun c:GetCurPos (/ dwx)
- (setq dwx (vlax-create-object "DynamicWrapperX"))
- (vlax-invoke
- dwx 'Register "user32" "GetCursorPos" "i=p" "r=l"
- )
- (setq nP (vlax-invoke dwx 'MemAlloc 8 1))
- (vlax-invoke dwx 'GetCursorPos nP)
- (princ "\n当前鼠标位置(左上角为0,0)左距:")
- (princ (vlax-invoke dwx 'NumGet nP 0 "l"))
- (princ ",上距:")
- (princ (vlax-invoke dwx 'NumGet nP 4 "l"))
- (vlax-release-object dwx)
- (princ)
- )
附件
1. dwx 函数语法详见:http://dynwrapx.script-coding.com/dwx/pages/dynwrapx.php?lang=en
2. dwx 数据类型,包括输入参数 i (input)和返回值参数 r (return)的类型
m — 双长整型,默认是有符号的,占 8 字节 64 位,整数,包括 LONGLONG 等
q — 无符号双长整型(无负整数),占 8 字节 64 位 64 位,整数,有 ULONGLONG 等
l — 长整型,占 4 字节 32 位,整数,有 LONG, INT, BOOL 等
u — 无符号长整型,占 4 字节 32 位,整数,有 ULONG, UINT, DWORD 等
h — 句柄,整数,32 位系统占 32 个位, 64 位系统占 64 位,包括 HANDLE, HWND, HMODULE, HINSTANCE, HICON,
p — 指针,整数,对于数字,它与 u(x86)或 q(x64)相同,也可以用于传递对象或字符串
n — 短整型,占 2 字节 16 位,整数,包括 SHORT 类型
t — 无符号短整型,占 2 字节 16 位,整数,包括 USHORT, WORD, WCHAR, OLECHAR 类型
c — 字符型,1 字节,整数,包括 CHAR
b — 无符号字符型,1 字节,整数,包括 UCHAR, BYTE
f — 单精度,占 4 字节 32 位,浮点数,包括 FLOAT
d — 双精度,占 8 字节 64 位,浮点数,包括 DOUBLE
w — Unicode 字符串,包括:BSTR, LPWSTR, LPOLESTR, OLECHAR *, WCHAR * 等
s — ANSI 字符串 (默认 codepage),LPSTR, LPCSTR, CHAR *, ...
z — OEM/DOS 字符串 (默认 codepage) — LPSTR, LPCSTR, CHAR *, ...
v — 指向变体结构的一个指针类型
3. dwx 插件下载帖子中的 imaut_vlx.rar 文件,在 CAD 中加载后点击注册 详见: http://bbs.mjtd.com/thread-176996-1-1.html
dynwrapx64位注册.rar
Dynwrapx2.1.1.1.zip
|
评分
-
查看全部评分
|