赞 | 0 |
VIP | 25 |
好人卡 | 0 |
积分 | 1 |
经验 | 126953 |
最后登录 | 2020-5-5 |
在线时间 | 39 小时 |
Lv1.梦旅人 粉蜘蛛秀秀
- 梦石
- 0
- 星屑
- 76
- 在线时间
- 39 小时
- 注册时间
- 2007-6-4
- 帖子
- 384
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
秀秀Win32API教程之一(基础篇)
此类教程也有过 不过好像很多人不太容易理解
所以打算在写一个 希望这篇教程大家看过后能理解 并且会使用
毕竟RM能支持win32API 还是很强大的
首先需要一本Win32API手册 方便查找函数和参数
这个东西 google搜索下 应该很容易能找到
我一般使用的就是这个for vb的 说明很详细
http://rpg.blue/upload_program/files/Win32APIfor_VB_97540875.rar
有了Win32API手册 我们可以开始研究了
研究对象:主站上发布过的修改RM窗口大小的范例
先不要着急看范例 我们有必要先了解下Win32API的基点基本知识
1.Win32的程序是在Win32API基础上诞生的,比如Windows自身的一些程序的运行
也是依靠Win32API 比如 运行RM的时候 会先生成一个窗口 这个窗口就是依靠
Win32API函数创建的
2.Win32API只能在32位windows操作系统下运行 比如dos系统,lunix,都不可以调用
Win32API,他们各自有各自调用操作系统功能函数,早期的dos系统有中断指令
lunix有lunix自己的API函数 而我们讨论的是Win32API
3.API中的函数 都是存放在DLL中的
DLL是Windows动态链接库 Win32编程的接口 所以要使用API函数
必须要知道这个API函数 包含在哪个DLL中 这些可以查看API手册
Windows核心其实是由3个DLL组成
KERNEL32.dll (系统服务功能 内存管理功能 任务管理等等...)
USER32.dll (用户接口服务 窗口功能 消息传递等等...)
GDI32.dll (图形设备接口 跟图形有关)
这三个文件都包含在windows目录下的system32子目录下
RM里面调用API函数 所需要的dll 必须存放在这个目录下 或者 RM工程的根目录
所以使用外部的dll要注意存放的位置
RM最常用的是 KERNEL32.dll 和 USER32.dll
GDI32.dll 是跟图形有关 RM对图形的显示,绘制和操作 已经足够使用 如Bitmap类
所以没必要使用GDI32.dll里面的函数了
还有一些其他的dll 比如Wsock32.dll 也是系统自带的
里面的函数都跟网络有关 所以不是windows运行的核心 但是开发网络必须要用到他
RM如果要做一些跟网络相关的 就必须用到这个dll了
4.RM中是如何调用Win32API的呢 来看个例子
gps = Win32API.new('kernel32', 'GetPrivateProfileString',%w(p p p p l p), 'l')
跟RM里面生成对象的方法一样
生成一个Win32API对象 后面会带四个参数
第一个参数:是函数所需要的dll文件 前面已经说过了
如果不是系统的必须要放在指定的目录
第二个参数:函数名称 必须是dll里面能导出的函数名称 如果不是自己写的dll
就不必关心它了 API参考手册上有的函数 基本上都是能调用的
第三个参数:这个API函数所带的参数类型的列表
并不是刚才建立API对象带的四个参数 有关参数类型后面会说到
%w()是 Win32API用设定参数类型的一种方法
其实还有2种方法
包含在""字符串里面
[""]包含在数组里面
这也是ruby语言多样化的特点
就好比数组可以用[]表示 也可以用%w{}表示 一样的道理
以下三种表示方法是一样的
%w(p p p p l p)
"pppplp"
["p","p","p","p","l","p"]
在执行这个函数的时候 windows 会先把这个列表里的参数 逆序一个一个地压入堆栈
然后再一个一个地弹出执行
说道这里可能有些人 不明白了 所以只好说明下了
为什么要逆序压入堆栈 又为什么弹出执行呢
这里要说下内存了 为了便于管理内存的空间其实被划分成了若干
比如我们设置的常量 就是存储在内存的常量区
变量和参数之类的 存储在堆栈区
我们写的函数代码什么的 就存放在程序代码区
有了这些概念 应该很容易理解 参数是存放在堆栈区了
堆栈是怎么运作的呢
假设堆栈是一个数组 存入堆栈就相当于数组的push 一个一个地压入
为什么堆栈要用压入这个词呢 字面上理解就是
先被push进去的被后push进去的压在下面 所以压在最下面的要出来就比较困难
必须上面的先出去 被压在下面的才能出去
这样形容应该能理解了吧 所以调用参数的时候就是逆序压入堆栈
比如四个参数 第四个先push 第一个最后push
到真正调用的时候 由于第一个参数最后一个被压入 所以是在最上面的
所以第一个被弹出执行 跟数组的pop差不多
这就是我个人理解的 堆栈 就是数组的先push后pop 先进后出的概念
第四个参数
是这个API函数的返回值 跟一般的函数差不多 就是返回一个值
5.API函数的参数类型
其实API函数手册上都有说明的 但是还是我来讲解一下吧
大概有这几种 i,l,p,v
i 代表整型
l 代表长整型 和整型的唯一区别 就是能存放的位数多 开辟的内存空间大一点
p 代表指针型 如果参数返回的是一个字符串的 就要用p
为什么呢 字符串可能会占据很大一片内存空间 不可能像i或者l型那样去开辟指定的空间
所以在定义了字符串之后 内存中已经自动开辟好空间 存放了字符串 所以p指针就是存放
了字符串的内存地址 调用之后 系统会根据这个地址找到这个字符串 再读取出
v 代表无参数 如果是第四个参数函数返回值得话 就是函数不需要返回 相当于return 直接返回 没有返回值
6.call函数
gps = Win32API.new('kernel32', 'GetPrivateProfileString',%w(p p p p l p), 'l')
这个是刚才说过的 建立了Win32API对象
这个对象拥有的方法 其实就是这个API函数的方法
使用方法看一个例子
gps.call(section, key, "", val, 256, GAME_INI_FILE)
其实就是一个call方法 后面带的一些参数
必须要跟生成时候的参数数量一致 否则会发生参数数量不对而引发错误
这里带的参数就是一些功能了 而不是一些参数类型 比如窗口的大小 位置什么的
具体要查看手册了
综合看一下 建立API对象的时候 其实并没有执行 只不过是初始化一些参数阿什么的
真正执行的是call方法 所以一定要牢记了
知道了以上基础知识之后 我们可以开始看一个例子了
class Win32API
GAME_INI_FILE = ".\\Game.ini"
def Win32API.GetPrivateProfileString(section, key)
val = "\0"*256
gps = Win32API.new('kernel32', 'GetPrivateProfileString',%w(p p p p l p), 'l')
gps.call(section, key, "", val, 256, GAME_INI_FILE)
val.delete!("\0")
return val
end
def Win32API.FindWindow(class_name, title)
fw = Win32API.new('user32', 'FindWindow', %(p, p), 'i')
hWnd = fw.call(class_name, title)
return hWnd
end
HWND_TOP = 0
HWND_TOPMOST = -1
SWP_NOMOVE = 2
def Win32API.SetWindowPos(hWnd, w, h)
swp = Win32API.new('user32', 'SetWindowPos', %(l, l, i, i, i, i, i), 'i')
ok = swp.call(hWnd, HWND_TOP, 200, 200, w, h, SWP_NOMOVE)
return ok
end
end
title = Win32API.GetPrivateProfileString("Game", "Title")
hWnd = Win32API.FindWindow("RGSS Player", title)
ok = Win32API.SetWindowPos(hWnd,320,480)
if(ok == 0)
p "変更失敗"
end
这个范例 如果是ruby初学者的话 还很难看懂 因为有一些面向对象的知识
所以还是有必要详细地讲解
大家知道调用Win32API的时候 需要一个new方法来初始化
再ruby中new方法是 类的一个特殊方法 直接执行初始化函数initialize
所以可以认定Win32API是一个类
这里有一个方法可以判断系统内部的一些东西到底是类 还是 模块
刚才的判断有.new的方法 是一个类
如果没有.new 而直接跟方法的 可以认定是模块
比如 Graphics.update
可以判断是Graphics模块里的一个模块方法update
好了知道这些就足够了
接着先分析一下这个范例 大致是这样
1.扩展Win32API类里的方法
GetPrivateProfileString
FindWindow
SetWindowPos
2.执行 GetPrivateProfileString 方法获取ini文件中的窗口标题信息
3.执行 FindWindow 方法 根据 GetPrivateProfileString 返回值(标题信息)
获取窗口句柄(什么是句柄 后面会解释)
4.执行 SetWindowPos 方法 根据 FindWindow 方法返回的句柄来设置窗口
这样分析下来 看似比较清楚但还是有些不理解的地方 我们接着来逐个分析把
先看第一个方法 GetPrivateProfileString
GAME_INI_FILE = ".\\Game.ini"
def Win32API.GetPrivateProfileString(section, key)
val = "\0"*256
gps = Win32API.new('kernel32', 'GetPrivateProfileString',%w(p p p p l p), 'l')
gps.call(section, key, "", val, 256, GAME_INI_FILE)
val.delete!("\0")
return val
end
程序开始的时候 定义了一个常量 GAME_INI_FILE = ".\\Game.ini"
很好理解 保存了当前目录下的Game.ini这个文件名的字符串
.代表当前 ..代表上级 \\代表目录
所以.\\Game.ini表示当前目录下的Game.ini文件
接着看 下面定义了 GetPrivateProfileString 函数 并且带2个参数 需要传入
val = "\0"*256
代表定义了256个字节的缓冲区 有些参数需要定义缓冲区 所以根据情况要定义
如果益出了 则取256个字节部分 说明256个字节还不够 512 1024 都是可以的
后面的那个
gps = Win32API.new('kernel32', 'GetPrivateProfileString',%w(p p p p l p), 'l')
前面已经说到过了 生成了一个gps的Win32API对象
指定了kernel32这个dll文件,函数名为GetPrivateProfileString
定义了压入堆栈的6个参数的参数类型为p p p p l p
即 指针 指针 指针 指针 长型 指针
怎么知道是这些类型呢 查API手册 每个参数都有类型的说明
最后一个参数是函数返回一个l型的值
到这里 已经建立好一个win32API的对象 gps
看下面一句
gps.call(section, key, "", val, 256, GAME_INI_FILE)
对象调用参数功能 前面已经说过了 后面的参数 需要参考API手册来设置相应的功能
来实现不同的效果
虽然能查到但是这里我还是再说一下吧 GetPrivateProfileString 这个函数的功能
获取初始化文件中(.ini格式的)指定 小节 中的 项目 信息
什么是小节? 什么是项目?
这里我们先说明下ini文件格式 就一目了然了
打开Game.ini文件
可以看到格式是这样的
[小节名称]
键1名称 = xxx
键2名称 = xxx
....
..
键n名称 = xxx
当然Game.ini文件中只有Game这一个小节 加上 N个项目
一般ini文件都是一些初始化 配置信息什么的 有些window应用程序 的初始化信息
都写在ini文件中 根据客户不同需要修改ini文件中相关键信息 可达到不同效果
了解了 小节 和 键 这两个概念就可以了 这个函数最终会返回一个键的键值
由于第一和第二个参数是由Win32Api扩这得这个类方法的参数传入的
还记得这个定义么 需要传入2个参数
def Win32API.GetPrivateProfileString(section, key)
看后面的调用这个函数
title = Win32API.GetPrivateProfileString("Game", "Title")
把 "Game" 和 "Title" 传过去
传到方法内部 这个函数
gps.call(section, key, "", val, 256, GAME_INI_FILE)
就变成了
gps.call("Game", "Title", "", val, 256, GAME_INI_FILE)
由于之前定义的
val = "/0"*256
GAME_INI_FILE = ".\\Game.ini"
所以函数的参数变量什么全部带入其中之后为
gps.call("Game", "Title", "", "/0"*256, 256,".\\Game.ini")
这样的话 参数全部明朗化了
解释每个函数的话 依次解释
"Game" 代表 ini 文件中的小节
"Title" 代表此小节中的项目值
"" 代表如果找不到键 直接返回 "" (空字符串)
"/0"*256 代表开辟256字节的缓冲区
256代表 不能超过256个字节 也是为了不益处
".\\Game.ini" 代表当前目录下的Game.ini文件
最后返回的是Title的值
解释好了就很容易理解这个API函数的功能了
首先在当前目录下找到Game.ini文件
搜索Game小节中的Title键
开辟缓冲区空间
最后把键中的这个键值返回到缓冲区去 并且返回这个值
所以
title = Win32API.GetPrivateProfileString("Game", "Title")
把Title键的值 赋给了title 这个局部变量
如新建一个RM项目的话 Title的值为 Project1
也就是RM窗口做上角的窗口名
接着看
hWnd = Win32API.FindWindow("RGSS Player", title)
"RGSS Player" 表示窗口的类名 就是这个 看截图
title就是刚才那个API返回的值,就是一个窗口标题名称
这个函数功能就是 根据 窗口的类名 和 窗口标题名称
获取了这个窗口的句柄 并且返回它
什么是句柄?
怎么理解呢
对我们来说其实句柄什么都不是
只有系统知道是什么 其实可以理解成只有系统认识的标识
比如刚才返回的一个窗口句柄
系统知道了这个值 根据这个值找到这个窗口 并对这个窗口进行操作
这个例子可以理解为 返回了一个类名为RGSS Player的窗口
标题名为 Project1 的窗口唯一标识
最后看
HWND_TOP = 0
HWND_TOPMOST = -1
SWP_NOMOVE = 2
def Win32API.SetWindowPos(hWnd, w, h)
swp = Win32API.new('user32', 'SetWindowPos', %(l, l, i, i, i, i, i), 'i')
ok = swp.call(hWnd, HWND_TOP, 200, 200, w, h, SWP_NOMOVE)
return ok
end
开始设置的常量就不用看了 一会儿会解释
def Win32API.SetWindowPos(hWnd, w, h)
定义了 SetWindowPos 带3个参数
swp = Win32API.new('user32', 'SetWindowPos', %(l, l, i, i, i, i, i), 'i')
表示 初始化API函数SetWindowPos 并建立对象swp (参数说明前面都讲过了)
ok = swp.call(hWnd, HWND_TOP, 200, 200, w, h, SWP_NOMOVE)
call这个函数
第一个参数是hwnd 还记得前面那个句柄吗?
hWnd = Win32API.FindWindow("RGSS Player", title)
返回一个句柄给hWnd
所以第一个参数就是刚才那个函数的句柄
HWND_TOP 这个值为0 表示这个窗口置于顶层
后面4个参数表示 窗口的 x坐标 y坐标 窗口的宽度 窗口的高度
窗口的宽度 和 窗口的高度是 是变量w和h
是方法参数传入过来的
SWP_NOMOVE 表示窗口类型 这里设置为2 表示忽略x y坐标的定义 保持当前的窗口位置
具体这些参数还有许多设置方法 要查API手册了 就不详述了
最后 这个函数返回一个值
非零表示设置成功 零表示设置失败
所以返回结果带入ok这个局部变量 并且函数最终返回这个结果
接近尾声了 看最后一个
ok = Win32API.SetWindowPos(hWnd,320,480)
运行Win32API扩展函数SetWindowPos
主要功能就是把三个参数 传入其中 def Win32API.SetWindowPos(hWnd, w, h)
这样 swp.call(hWnd, HWND_TOP, 200, 200, w, h, SWP_NOMOVE)
call函数的参数就全部传入进来
swp.call(hWnd,0,200,200,320,480,2)
在提醒一下hWnd为窗口句柄
这样就设置了窗口的坐标 长 宽 已经窗口类型
窗口就改变了
看程序最后
if(ok == 0)
p "変更失敗"
end
还记得ok是保存一个值么?0代表窗口设置失败 非零代表成功
赫赫 好了 本次API教程一(基础篇)结束了 希望大家看了我这个教程能
清楚认识Win32API函数 并且有所收获
下一篇 为进阶篇 会着重讲述一些利用Win32API函数实现一些高级功能的范例
还会教大家如何用Win32API函数来扩展一些RM核心库
有什么不明白的地方 可以回帖问~
补充chinamonkey的疑问
不通过Game.ini文件 如何知道当前窗口的 标题 和 类名
由于这个范例是主站以前搬过来的 这些细节我没注意
可能大家这里会有点疑问
其实利用3个API函数 能够快速的获取当前活动窗口的类名
1.GetActiveWindow # 获取当前活动窗口句柄
2.GetWindowText # 获取窗口标题
3.GetClassName # 获取窗口类名
使用方法:
# 获取当前活动窗口句柄
hWnd = Win32API.new("user32","GetActiveWindow","v","i")
# 获取窗口的标题
str = "\0"*256
get_text = Win32API.new("user32","GetWindowText","ipl","l")
get_text.call(hWnd.call,str,str.length)
p str.delete("\0")
# 获取窗口的类名
str = "\0"*256
get_text = Win32API.new("user32","GetClassName","ipl","l")
get_text.call(hWnd.call,str,str.length)
p str.delete("\0") |
|