Project1
标题: 求推荐Win32API的相关教程 [打印本页]
作者: 大葱有营养 时间: 2020-8-24 19:14
标题: 求推荐Win32API的相关教程
有一点ruby脚本基础,但是对Win32API相关一窍不通,看别人这方面脚本也看不懂,想从头开始学,苦于没有路子
查了下发现XP和VA区图书馆的Win32API教程都没了(晴兰大大的,好像相关帖子都没了,是不是出啥事了,不敢多问……)
看大家都说要看手册,不过光看手册感觉又多又杂不够清晰,不知道有没有相关教程资源可供自学,希望大大们能分享一下,不好意思这里伸手党了,希望海涵。
作者: KB.Driver 时间: 2020-8-24 20:54
本帖最后由 KB.Driver 于 2020-8-24 20:57 编辑
rgss自动加载了win32api,不考虑外置库的话,可以直接用这个。
常量 = Win32API.new(DLL名, 函数名, 参数数组, 返回值)
1、首先,你需要从dll里加载函数。
虽然我们也可以用外置的dll,但最常用的还是user32.dll
2、需要函数名,这个一般就需要查手册了,手册可以看这个、
http://www.yfvb.com/help/win32sdk/webhelpleft.htm
这个的好处是中文的,缺点就是不够新不够全。如果有版本要求请找英文的文档。
进去以后点“API参考”-“函数”然后找你需要的函数。
打个比方,在这里找到这样一个函数:
它的功能是返回当前正在被使用的窗口的句柄(hwnd)
句柄是一个long整数,用来唯一标识窗口
接下来我们怎么调用它?
3、参数数组
这个函数比较简单,从手册得知它的参数是void(无)
表示参数的类型时, L代表Long P代表Pointer I代表Int V代表Void (在实际使用的时候HResult和各种Handle都是Long,字符串是P)
那么我们就写'V',这里大写小写其实都没有关系
只有一个参数时一般用字符串就行,但是有多个参数时要用字符串数组比如["L", "P"]或者%W{ L P }
4、返回值
从手册已经得知返回的句柄是long,那么我们写'L'
5、测试
根据上面的分析,要载入这个函数,我们就这样写
GetForegroundWindow = Win32API.new("user32.dll", "GetForegroundWindow", "V", "L")
GetForegroundWindow = Win32API.new("user32.dll", "GetForegroundWindow", "V", "L")
之后要调用函数时,我们使用
函数名.call(参数)
这里我们可以用hwnd = GetForegroundWindow.call,因为不需要参数所以不用写括号,但要记得把返回值赋值给变量。
6、动手
那么获得了窗口的句柄有什么用呢?
我们可以修改窗口的标题,修改窗口的位置与显示状态(最大、最小化……)
下面就试着修改标题吧。
我们先找到文档:
接着载入函数:
SetWindowText = Win32API.new("user32.dll", "SetWindowText", %W{ L P }, "I")
SetWindowText = Win32API.new("user32.dll", "SetWindowText", %W{ L P }, "I")
还记得吗?字符串体现为P,因为字符串是字符指针。而BOOL体现为I,因为C语言的逻辑变量是用1和0表示的。
下面就来试着修改游戏的标题吧:
GetForegroundWindow = Win32API.new("user32.dll", "GetForegroundWindow", "V", "L")
SetWindowText = Win32API.new("user32.dll", "SetWindowText", %W{ L P }, "I")
$hwnd = GetForegroundWindow.call
class << Graphics
alias cld99_update_win32api update
def update
@count ||= 0
@count += 1
SetWindowText.call($hwnd, "Time:"+ Time.now.to_s)
if @count > 10000
SceneManager.exit
end
end
end
GetForegroundWindow = Win32API.new("user32.dll", "GetForegroundWindow", "V", "L")
SetWindowText = Win32API.new("user32.dll", "SetWindowText", %W{ L P }, "I")
$hwnd = GetForegroundWindow.call
class << Graphics
alias cld99_update_win32api update
def update
@count ||= 0
@count += 1
SetWindowText.call($hwnd, "Time:"+ Time.now.to_s)
if @count > 10000
SceneManager.exit
end
end
end
好像写的比较糟糕,因为我发现Graphics自身的update会重新把标题修改回去……晕
总之基础的是这些,还有调数据的会用到Cstruct,需要String#pack和Array.unpack,如果用到再学也可以。
这些都是网上有资料的,查ruby调win32api就有了。
作者: SixRC 时间: 2020-8-24 22:07
楼上写的好认真
补充一点点
Win32API.new(DLL名, 函数名, 参数数组, 返回值) 中
dll 后缀可省略
参数数组可以直接写成 "ll" 这样
有意义的参数类型只有 l p 因为RM是32位 i l n 都是32位整形 没有任何区别 同时 v 可以直接省略 或传 nil
对于不需要的返回值可以直接传 空字符串 / nil 因为不需要 例如返回bool 假如不去判断是否成功 就不需要这个结果 当然写别的也完全没问题 就是偷懒时候可以省略
有一点非常要注意的是
假如返回值是短型 short 那么必须手动把返回值的高16位截掉 因为RM的ruby版本 是不支持 s 的 只有 l
决定数据类型的是处理它的方式
特殊情况下若保留多余的高16位 而你以为收到短整型 其实有多余信息 程序会崩
许多涉及字符串的win32api 都有两个版本 一个A ansi 一个W utf16le
SetWindowText 就是 没有指定 ruby默认用A版本
然后 ansi 在中文是 GB2312 RM是utf8 假如传中文就会乱码 需要先转码
作者: guoxiaomi 时间: 2020-8-25 21:17
本帖最后由 guoxiaomi 于 2020-8-25 21:33 编辑
尝试了一下传入 float / float* 和 double*,
- #define EXPORT __declspec(dllexport)
- EXPORT int fun1(float a)
- {
- return a * a;
- }
- EXPORT int fun2(float *a)
- {
- return (*a) * (*a);
- }
- EXPORT int fun3(double *a)
- {
- return (*a) * (*a);
- }
复制代码
然后3个方法这样调用应该是没啥问题的……
- fun1 = Win32API.new("main.dll", "fun1", "i", "i")
- fun2 = Win32API.new("main.dll", "fun2", "p", "i")
- fun3 = Win32API.new("main.dll", "fun3", "p", "i")
- x = 2.5
- p fun1.call([x].pack("e").unpack("L")[0])
- p fun2.call([x].pack("e"))
- p fun3.call([x].pack("E"))
复制代码
返回值:666
返回float值好像出了问题……算了不管了
作者: SixRC 时间: 2020-8-25 23:15
本帖最后由 SixRC 于 2020-8-25 23:24 编辑
直接返回float值是不行啊
汇编有堆栈 通用寄存器 浮点数堆栈
32位默认情况下 调用函数时 参数入堆栈(包括浮点数) 返回时 一般把返回值放在寄存器 eax 中
而返回浮点数值 则是把返回值放在浮点数堆栈
所以假如写一个接口 返回值是 float ruby端因为没考虑这个 只会取 eax 的值 而直接无视浮点数堆栈
所以要返回也很简单嘛 就是转换一下类型传回去 ruby端再转换一下
EXPORT int fun4(float *a)
{
float t = (*a) * (*a);
return *(int *)&t;
}
EXPORT int fun4(float *a)
{
float t = (*a) * (*a);
return *(int *)&t;
}
fun4 = Win32API.new("a.dll", "fun4", "p", "i")
x = 2.5
s = fun4.call([x].pack("e"))
p [s].pack("l").unpack("e")
fun4 = Win32API.new("a.dll", "fun4", "p", "i")
x = 2.5
s = fun4.call([x].pack("e"))
p [s].pack("l").unpack("e")
不过直接传一个空字符串进去当输出缓存 或者直接输出到输入的内存里 会更方便吧
欢迎光临 Project1 (https://rpg.blue/) |
Powered by Discuz! X3.1 |