明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1290|回复: 6

[讨论] LISP+DWX 之二:结构类型与传址参数

[复制链接]
发表于 2018-5-12 14:20 | 显示全部楼层 |阅读模式
本帖最后由 yxp 于 2018-5-12 14:51 编辑

问题
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 进制转换为二进制,发现两者完全相同。


完整程序如下:
  1. ;;获取当前鼠标在 Windows 系统里的坐标位置
  2. (defun c:GetCurPos( / dwx)
  3. (setq dwx (vlax-create-object "DynamicWrapperX"))
  4. (vlax-invoke dwx 'Register "user32" "GetCursorPos" "i=p" "r=l")
  5. (setq nP (vlax-invoke dwx 'MemAlloc 8 1))
  6. (vlax-invoke dwx 'GetCursorPos nP)
  7. (princ "\n当前鼠标位置(左上角为0,0)左距:")
  8. (princ (vlax-invoke dwx 'NumGet nP 0 "l"))
  9. (princ ",上距:")
  10. (princ (vlax-invoke dwx 'NumGet nP 4 "l"))
  11. (vlax-release-object dwx)
  12. (princ)
  13. )



附件
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






评分

参与人数 1明经币 +1 收起 理由
自贡黄明儒 + 1 很给力!

查看全部评分

"觉得好,就打赏"
还没有人打赏,支持一下
发表于 2018-5-12 20:39 | 显示全部楼层
:D楼主 天正批量转久研究出来没
发表于 2018-5-13 09:46 | 显示全部楼层
太高级了,我只晓得LISP这货
发表于 2018-5-13 11:00 | 显示全部楼层
太高深 只能围观
LISP都还没有整明白
发表于 2022-6-19 06:17 | 显示全部楼层
做个记号备用
发表于 2022-6-30 15:08 | 显示全部楼层
学习了 这方面的资料太少了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-3-29 02:54 , Processed in 0.169054 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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