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

Project1

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

[RMVX发布] 发呆一天的产物--获取窗口句柄完美版

[复制链接]

Lv2.观梦者

神隐的主犯

梦石
0
星屑
258
在线时间
271 小时
注册时间
2008-2-22
帖子
7691

贵宾

跳转到指定楼层
1
发表于 2010-11-11 11:02:56 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

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

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

x
本帖最后由 铃仙·优昙华院·因幡 于 2010-11-11 20:19 编辑

一大清早起床发呆, 发呆了一天, 于是就有了一下的结果.

dll 版本.

HWND.rar (131.49 KB, 下载次数: 392)

脚本:

  1. module Kernel
  2.   GetWIndowHwnd = Win32API.new("HWND.dll", "GetWIndowHwnd", "v", "l")
  3.   def get_hWnd
  4.      GetWIndowHwnd.call()
  5.   end
  6. end
复制代码
嘛,提升了效率. 不过有 dll 是有点碍眼. Game.exe 和 HWND.dll 要一起使用.


更新一个不需要 dll 的版本:
Game.rar (89.71 KB, 下载次数: 257)
用法很简单, $HWND 就是窗口句柄.



这个是紫苏大的脚本:
http://rpg.blue/forum.php?mod=vi ... 3%E5%8F%A5%E6%9F%84

评分

参与人数 1+4 收起 理由
夕阳武士 + 4 技术活

查看全部评分


《天空之城 —— 破碎的命运》

Lv1.梦旅人

梦石
0
星屑
110
在线时间
953 小时
注册时间
2007-4-25
帖子
805
2
发表于 2010-11-11 11:13:16 | 只看该作者
不公开源码么 =(
既然必须用到 DLL,猜测是改用了 EnumWindows,继而需要回调函数?
其实自写 RGSS Player (夏娜写过)是最好的解法,也可以劫持 CreateWindowEx (紫苏似乎弄过一个劫持 user32.dll 的工程)。
[email protected]:~> repeat 1 fortune
Matz is nice, so we are nice.
回复 支持 反对

使用道具 举报

Lv2.观梦者

神隐的主犯

梦石
0
星屑
258
在线时间
271 小时
注册时间
2008-2-22
帖子
7691

贵宾

3
 楼主| 发表于 2010-11-11 11:15:48 | 只看该作者
本帖最后由 铃仙·优昙华院·因幡 于 2010-11-11 11:17 编辑

源码:

  1. HWND hwnd=0;
  2. DWORD pid=0;
  3. BOOL __stdcall EnumProc(HWND hwnds, LPARAM lParam)
  4. {
  5.         DWORD pidwin;
  6.         if(hwnds != NULL)
  7.         {
  8.                 ::GetWindowThreadProcessId(hwnds, &pidwin);
  9.                 if(pidwin == pid)
  10.                 {
  11.                         hwnd = hwnds;
  12.                         return 0;
  13.                 }
  14.                 return 1;
  15.         }
  16.         return 1;
  17. }

  18. HWND_API HWND GetWIndowHwnd(DWORD pids)
  19. {
  20.         pid = pids;
  21.         ::EnumWindows(EnumProc, 0);
  22.         return hwnd;
  23. }
复制代码
写的比较差劲.

重写其实也不错. 不过有空有能力的话, 倒是可以去试试修改下 exe 或者是 dll 什么的.

不过 Ruby 能处理 函数指针 么??

《天空之城 —— 破碎的命运》
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
110
在线时间
953 小时
注册时间
2007-4-25
帖子
805
4
发表于 2010-11-11 11:47:07 | 只看该作者
本帖最后由 苏小脉 于 2010-11-11 11:50 编辑

其实比较线程标识就可以了,另外 if 内部的 return 1 有点多余。 ^_^

目前这样比较会在某些场合下出现问题,比如:用户通过脚本创建了另一个顶层窗口(自然其创建进程和创建线程都和主窗口一致),这时可能拿到的并不是原来的主窗口句柄。紫苏那贴里的脚本实际上也没有完美地考虑到所有场合——窗口类,顾名思义,就是一类窗口的抽象描述,自然可以有多个窗口实例属于同一个窗口类,而这时如果恰好存在两个同属于 RGSS Player 类,由相同的进程/线程创建的顶层窗口,那获取到的句柄也有可能不是原来的主窗口句柄。
像夏娜那样自行编写一个容器应用程序就很简单地解决了这个问题,毕竟 CreateWindowEx 是在自己的有源码的程序中调用的,其返回值就是窗口句柄。

Ruby 想要通过函数地址来调用本地函数的话,至少需要支持调用函数相关的一些指令(包括转移寄存器值和偏移 PC 等),而为了提供这样的接口,本地 DLL 通常是难免的。
[email protected]:~> repeat 1 fortune
Matz is nice, so we are nice.
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
55
在线时间
14 小时
注册时间
2008-5-7
帖子
74
5
发表于 2010-11-11 11:50:28 | 只看该作者
本帖最后由 独孤残云 于 2010-11-11 11:51 编辑

顶铃仙大人~
话说获取不到窗口句柄确实很纠结的说~
Win32App直接在WinMain中获取句柄,高度封装的Xna则对外暴露了游戏窗口的各项属性(包含句柄),可是貌似RM没有提供相关机制…~

点评

全部遍历一次就可以找得到, 只是要看怎么使用句柄了.  发表于 2010-11-11 12:00
回复 支持 反对

使用道具 举报

Lv2.观梦者

神隐的主犯

梦石
0
星屑
258
在线时间
271 小时
注册时间
2008-2-22
帖子
7691

贵宾

6
 楼主| 发表于 2010-11-11 11:58:51 | 只看该作者
回复 苏小脉 的帖子

遍历没有直接从 CreateWindowEx 这个拿来的舒服点.

不过有一个想直接修改 RGSS20XX.dll 的想法.  只是输出表重建很麻烦(对于我这样的新手来说)

刚才查阅了一下, Ruby 貌似有调用 CallBack 的方法. 只是在 RGSS2 里使用起来很困难.

《天空之城 —— 破碎的命运》
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
110
在线时间
953 小时
注册时间
2007-4-25
帖子
805
7
发表于 2010-11-11 12:07:34 | 只看该作者
本帖最后由 苏小脉 于 2010-11-11 12:07 编辑

回复 铃仙·优昙华院·因幡 的帖子

CreateWindowEx 是在 Game.exe 这个外壳里被调用的,这个可以通过观察其导入表发现;RGSS***.DLL 主要负责引擎的核心逻辑,这使得 DLL 不受具体窗口的羁绊,也可以算是一种简陋的设计模式吧。
另:你说的调用回调函数(本地?)的方法能否共享一下?
[email protected]:~> repeat 1 fortune
Matz is nice, so we are nice.
回复 支持 反对

使用道具 举报

Lv2.观梦者

神隐的主犯

梦石
0
星屑
258
在线时间
271 小时
注册时间
2008-2-22
帖子
7691

贵宾

8
 楼主| 发表于 2010-11-11 12:12:57 | 只看该作者
回复 苏小脉 的帖子

好吧, 弄错了.  是 Game.exe

CallBack 的话, 搜索了下, 大部分都是使用 dl 库, 第一句都是 require 'dl' .
然后就果断关网页了.
  1. require 'dl'
  2. user32=DL.dlopen("user32")

  3. enum_windows_callback= DL.callback('ILL') do |hwnd,lparam|
  4.   puts "hwnd is #{hwnd}"
  5.   0 # return 0 to break the enumeration early
  6. end
  7. begin
  8.   puts "calling enumwindows ..."
  9.   ret, args=user32['EnumWindows', 'IPL'].call(enum_windows_callback, 0)
  10.   puts "called enumwindows."
  11. ensure
  12.   puts "removing callback ..."
  13.   DL.remove_callback(enum_windows_callback)
  14.   puts "removed callback"
  15. end
复制代码
一个也不知道能不能运行的例子

《天空之城 —— 破碎的命运》
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
110
在线时间
953 小时
注册时间
2007-4-25
帖子
805
9
发表于 2010-11-11 12:23:42 | 只看该作者
哦,是用了标准库的 DL。不过 1.9.2 官方的 DL 并没有 callback 这个单例方法,作者应该是进行了扩展的,在 C 层直接调用 callback 的块。
[email protected]:~> repeat 1 fortune
Matz is nice, so we are nice.
回复 支持 反对

使用道具 举报

Lv2.观梦者

神隐的主犯

梦石
0
星屑
258
在线时间
271 小时
注册时间
2008-2-22
帖子
7691

贵宾

10
 楼主| 发表于 2010-11-11 12:26:26 | 只看该作者
  1. require 'win32/api'
  2. include Win32

  3. # Callback example - Enumerate windows
  4. EnumWindows     = API.new('EnumWindows', 'KP', 'L', 'user32')
  5. GetWindowText   = API.new('GetWindowText', 'LPI', 'I', 'user32')
  6. EnumWindowsProc = API::Callback.new('LP', 'I'){ |handle, param|
  7.   buf = "\0" * 200
  8.   GetWindowText.call(handle, buf, 200);

  9.   if (!buf.index(param).nil?)
  10.     puts "window was found: handle #{handle}"
  11.     0 # stop looking after we find it
  12.   else
  13.     1
  14.   end
  15. }
复制代码
这个也差不多, 使用了win32/api . 依旧是不能用

《天空之城 —— 破碎的命运》
回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2024-4-20 17:20

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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