赞 | 0 |
VIP | 0 |
好人卡 | 1 |
积分 | 1 |
经验 | 993 |
最后登录 | 2014-2-21 |
在线时间 | 36 小时 |
Lv1.梦旅人
- 梦石
- 0
- 星屑
- 50
- 在线时间
- 36 小时
- 注册时间
- 2008-2-22
- 帖子
- 35
|
本帖最后由 芙兰朵露·斯卡雷特 于 2011-5-14 15:54 编辑
Array#pack , String#unpack and Win32API
1. Array#pack and String#unpack
无论是什么编程语言, 总是把需要的数据或者正在使用的数据放进内存里, 给 CPU 调用. 内存的结构, 从 ASM 的初级使用者来说(其实就是咱了 > <) 是一维的, 数据总是连接成像字符串一样的结构.
那么, 如果把 Array 看成是 C 里的结构体, 也就是每个元素都是一个成员的话, Array#pack 方法就可以看成是将 Ruby 的 Array 转换成 C 里的结构体. 中间作为过渡的, 就是 内存 了.
String#unpack 的功能刚好和 Array#pack 相反.
举个简单的例子:
C 代码:- struct CStruct
- {
- int x;
- long y;
- };
复制代码 定义一个有 int 的成员变量 x 和 long 的成员变量 y
如果我们要从 RGSS2 的角度来创建这个结构体的话, 那么, 就需要使用 Array#pack:
RGSS2 代码:
- cstruct = [10, 20].pack("il")
复制代码 是的, 就是这样, pack 后面的参数告诉编译器, 将第一个 10 格式化成 C 里的 int (就是那个 "i"), 20 格式化成 long (就是 "l"). 这样 ,返回的结果就是 C 里的结构体的内存映像, 这个代码等价于:
C 代码:
- CStruct cstruct;
- cstruct.x = 10;
- cstruct.y = 20l;
复制代码 这两者的 内存映像 是相同的.
2. Array#pack and String#unpack 的参数
这个方法参数有非常的多, 具体的可以查看: http://rpg.blue/manual/ruby/pack_template_string.html
个人的看法, 这个参数的值, 可以看成是将元素依次的格式化成一个含有类型的值. 比如上面说到的, "i" 其实就是等价于 C 里的 int , "l" 等价于 long , "C" 等价于 unsigned char 一样.
3. Array#pack , String#unpack and Win32API
以上都是废话, 接下来才是福利.
pack 和 unpack 和 Win32API 这个类关系密切. 我们从一个例子中说明这个的用法.
一个简单的例子:
假设我们需要获取 VX 窗口相对于桌面的坐标和 VX 窗口的长度, 高度, 那么, 我们就需要查询一个有这个功能的 API . 于是百度到这个:
函数功能:该函数返回指定窗口的边框矩形的尺寸。该尺寸以相对于屏幕坐标左上角的屏幕坐标给出。
函数原型:BOOL GetWindowRect(HWND hWnd,LPRECT lpRect);
速查:Windows NT:3.1以上版本:Windows:95以上版本;Windows CE:1.0以上版本;头文件:Winuser.h;库文件:User32.lib。
这样我们就知道了这个 API 的大部分信息, 于是开始创建 Win32API 的一个实例.
- get_window_rect = Win32API.new("user32.dll", "GetWindowRect",
- "pp", # 第二个参数是一个结构体, 只能传递一个地址, 也就是 "p" 给它.
- "i")
复制代码 那么, 如何调用这个 API 呢? 第一个参数是窗口句柄, 这个难度不大. 第二个参数是什么? 于是我们继续百度, 结果如下:
typedef struct tagRECT
{
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT, NEAR *NPRECT, FAR *LPRECT;
显而易见的, 它是一个结构体, 里面的成员变量都是 long 类型的, 于是, 我们需要先创建一个这个结构体的实例:
RGSS2 代码:
- lpRect = [0, 0, 0, 0].pack("llll")
复制代码 我们也可以这么写:
- lpRect = [0, 0, 0, 0].pack("l4")
复制代码 这样, 参数都知道了, 于是调用这个 API :
RGSS2 代码:
- lpRect = [0, 0, 0, 0].pack("llll")
- get_window_rect.call($hwnd, lpRect);
复制代码 不过要注意一点, 现在的 lpRect 只是一个字符串, LPRECT 结构的内存映像, 那么, 我们需要 unpack 成我们需要的数组:
RGSS2 代码:
- rect = lpRect.unpack("l4")
复制代码 这样就获取了, 窗口的左上和右下的坐标. 这里需要注意的是, WIndow 的矩形的定义和 RGSS2 的矩形是不一样的. 于是进一步的转换:
RGSS2 代码:
- rect = lpRect.unpack("l4")
- vx_window_rect = Rect.new(rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1])
复制代码 这样就获取了 VX 窗口的矩形了, 包含了窗口左上角的坐标和窗口的长宽. |
|