设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 2068|回复: 11
打印 上一主题 下一主题

[有事请教] 求推荐Win32API的相关教程

[复制链接]

Lv3.寻梦者

梦石
0
星屑
2614
在线时间
288 小时
注册时间
2018-5-13
帖子
26
跳转到指定楼层
1
发表于 2020-8-24 19:14:28 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
有一点ruby脚本基础,但是对Win32API相关一窍不通,看别人这方面脚本也看不懂,想从头开始学,苦于没有路子
查了下发现XP和VA区图书馆的Win32API教程都没了(晴兰大大的,好像相关帖子都没了,是不是出啥事了,不敢多问……)
看大家都说要看手册,不过光看手册感觉又多又杂不够清晰,不知道有没有相关教程资源可供自学,希望大大们能分享一下,不好意思这里伸手党了,希望海涵。
游戏设计爱好者

Lv5.捕梦者

梦石
10
星屑
39592
在线时间
1920 小时
注册时间
2010-11-14
帖子
3320

R考场第七期纪念奖

2
发表于 2020-8-24 20:54:37 | 只看该作者
本帖最后由 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、测试
根据上面的分析,要载入这个函数,我们就这样写
RUBY 代码复制
  1. GetForegroundWindow = Win32API.new("user32.dll", "GetForegroundWindow", "V", "L")

之后要调用函数时,我们使用
函数名.call(参数)
这里我们可以用hwnd = GetForegroundWindow.call,因为不需要参数所以不用写括号,但要记得把返回值赋值给变量。

6、动手
那么获得了窗口的句柄有什么用呢?
我们可以修改窗口的标题,修改窗口的位置与显示状态(最大、最小化……)
下面就试着修改标题吧。

我们先找到文档:


接着载入函数:
RUBY 代码复制
  1. SetWindowText = Win32API.new("user32.dll", "SetWindowText", %W{ L P }, "I")

还记得吗?字符串体现为P,因为字符串是字符指针。而BOOL体现为I,因为C语言的逻辑变量是用1和0表示的。

下面就来试着修改游戏的标题吧:

RUBY 代码复制
  1. GetForegroundWindow = Win32API.new("user32.dll", "GetForegroundWindow", "V", "L")
  2. SetWindowText = Win32API.new("user32.dll", "SetWindowText", %W{ L P }, "I")
  3.  
  4. $hwnd = GetForegroundWindow.call
  5.  
  6. class << Graphics
  7.   alias cld99_update_win32api update
  8.   def update
  9.     @count ||= 0
  10.     @count += 1
  11.     SetWindowText.call($hwnd, "Time:"+ Time.now.to_s)
  12.     if @count > 10000
  13.       SceneManager.exit
  14.     end
  15.   end
  16. end


好像写的比较糟糕,因为我发现Graphics自身的update会重新把标题修改回去……晕

总之基础的是这些,还有调数据的会用到Cstruct,需要String#pack和Array.unpack,如果用到再学也可以。
这些都是网上有资料的,查ruby调win32api就有了。


评分

参与人数 2星屑 +1666 +1 收起 理由
fux2 + 1666 理应塞糖
SixRC + 1 精品文章

查看全部评分

用头画头像,用脚写脚本
回复 支持 1 反对 0

使用道具 举报

Lv4.逐梦者

梦石
0
星屑
13562
在线时间
2753 小时
注册时间
2014-10-4
帖子
756

R考场第七期纪念奖

3
发表于 2020-8-24 22:07:37 | 只看该作者
楼上写的好认真
补充一点点
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  假如传中文就会乱码 需要先转码

点评

大概懂了  发表于 2020-8-25 15:35
pack吧 传入形式是字符串 实质是浮点数指针  发表于 2020-8-25 12:12
所以合适的方法就是传一个字符串,然后用atof函数转成浮点数?  发表于 2020-8-25 05:57
同理可以传入双浮点数 只要分两个整数传进去就行 就是浮点pack 整型unpack再传参 返回接口要是自己写 就也能转换回来 不过只有单精度  发表于 2020-8-25 00:54
理论上是可以传入单浮点数 因为我发现浮点数也是堆栈传参 比如传入 0x40000000 就是传入单浮点2.0 但返回值在浮点数堆栈 但默认取eax作返回值 没法绕过  发表于 2020-8-25 00:49

评分

参与人数 1+1 收起 理由
KB.Driver + 1 我还是才疏学浅,知其然而不知其所以然.

查看全部评分

回复 支持 1 反对 0

使用道具 举报

Lv5.捕梦者 (版主)

梦石
1
星屑
23994
在线时间
3339 小时
注册时间
2011-7-8
帖子
3926

开拓者

4
发表于 2020-8-25 21:17:17 | 只看该作者
本帖最后由 guoxiaomi 于 2020-8-25 21:33 编辑
SixRC 发表于 2020-8-24 22:07
楼上写的好认真
补充一点点
Win32API.new(DLL名, 函数名, 参数数组, 返回值)   中


尝试了一下传入 float / float* 和 double*,
  1. #define EXPORT __declspec(dllexport)

  2. EXPORT int fun1(float a)
  3. {
  4.     return a * a;
  5. }

  6. EXPORT int fun2(float *a)
  7. {
  8.     return (*a) * (*a);
  9. }

  10. EXPORT int fun3(double *a)
  11. {
  12.     return (*a) * (*a);
  13. }
复制代码

然后3个方法这样调用应该是没啥问题的……
  1. fun1 = Win32API.new("main.dll", "fun1", "i", "i")
  2. fun2 = Win32API.new("main.dll", "fun2", "p", "i")
  3. fun3 = Win32API.new("main.dll", "fun3", "p", "i")
  4. x = 2.5

  5. p fun1.call([x].pack("e").unpack("L")[0])
  6. p fun2.call([x].pack("e"))
  7. p fun3.call([x].pack("E"))
复制代码

返回值:666

返回float值好像出了问题……算了不管了
熟悉rgss和ruby,xp区版主~
正在填坑:《膜拜组传奇》讲述膜拜组和学霸们的故事。
已上steam:与TXBD合作的Reformers《变革者》
* 战斗调用公共事件 *
* RGSOS 网络脚本 *
回复 支持 反对

使用道具 举报

Lv4.逐梦者

梦石
0
星屑
13562
在线时间
2753 小时
注册时间
2014-10-4
帖子
756

R考场第七期纪念奖

5
发表于 2020-8-25 23:15:08 | 只看该作者
本帖最后由 SixRC 于 2020-8-25 23:24 编辑
guoxiaomi 发表于 2020-8-25 21:17
尝试了一下传入 float / float* 和 double*,

然后3个方法这样调用应该是没啥问题的……


直接返回float值是不行啊
汇编有堆栈 通用寄存器 浮点数堆栈
32位默认情况下 调用函数时 参数入堆栈(包括浮点数) 返回时 一般把返回值放在寄存器 eax 中
而返回浮点数值 则是把返回值放在浮点数堆栈

所以假如写一个接口 返回值是 float  ruby端因为没考虑这个 只会取 eax 的值 而直接无视浮点数堆栈
所以要返回也很简单嘛 就是转换一下类型传回去 ruby端再转换一下
C 代码复制
  1. EXPORT int fun4(float *a)
  2. {
  3.     float t = (*a) * (*a);
  4.     return *(int *)&t;
  5. }

RUBY 代码复制
  1. fun4 = Win32API.new("a.dll", "fun4", "p", "i")
  2. x = 2.5
  3. s = fun4.call([x].pack("e"))
  4. p [s].pack("l").unpack("e")


不过直接传一个空字符串进去当输出缓存 或者直接输出到输入的内存里 会更方便吧

评分

参与人数 1+1 收起 理由
guoxiaomi + 1 我很赞同

查看全部评分

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-25 09:50

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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