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

Project1

 找回密码
 注册会员
搜索
查看: 7296|回复: 18

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

[复制链接]

TA还没有解放自身的潜力。

Lv1.梦旅人

神隐的主犯

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

贵宾

发表于 2010-11-11 11:02:56 | 显示全部楼层 |阅读模式

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

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

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

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

dll 版本.

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

评分

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

查看全部评分


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

TA还没有解放自身的潜力。

Lv1.梦旅人

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

使用道具 举报

TA还没有解放自身的潜力。

Lv1.梦旅人

神隐的主犯

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

贵宾

 楼主| 发表于 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 能处理 函数指针 么??

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

使用道具 举报

TA还没有解放自身的潜力。

Lv1.梦旅人

梦石
0
星屑
50
在线时间
947 小时
注册时间
2007-4-25
帖子
805
发表于 2010-11-11 11:47:07 | 显示全部楼层
本帖最后由 苏小脉 于 2010-11-11 11:50 编辑

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

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

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

使用道具 举报

TA还没有解放自身的潜力。

Lv1.梦旅人

梦石
0
星屑
55
在线时间
14 小时
注册时间
2008-5-7
帖子
74
发表于 2010-11-11 11:50:28 | 显示全部楼层
本帖最后由 独孤残云 于 2010-11-11 11:51 编辑

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

点评

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

使用道具 举报

TA还没有解放自身的潜力。

Lv1.梦旅人

神隐的主犯

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

贵宾

 楼主| 发表于 2010-11-11 11:58:51 | 显示全部楼层
回复 苏小脉 的帖子

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

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

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

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

使用道具 举报

TA还没有解放自身的潜力。

Lv1.梦旅人

梦石
0
星屑
50
在线时间
947 小时
注册时间
2007-4-25
帖子
805
发表于 2010-11-11 12:07:34 | 显示全部楼层
本帖最后由 苏小脉 于 2010-11-11 12:07 编辑

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

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

使用道具 举报

TA还没有解放自身的潜力。

Lv1.梦旅人

神隐的主犯

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

贵宾

 楼主| 发表于 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
复制代码
一个也不知道能不能运行的例子

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

使用道具 举报

TA还没有解放自身的潜力。

Lv1.梦旅人

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

使用道具 举报

TA还没有解放自身的潜力。

Lv1.梦旅人

神隐的主犯

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

贵宾

 楼主| 发表于 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 . 依旧是不能用

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

使用道具 举报

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

本版积分规则

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

站长信箱:fux2@moe9th.com|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2019-3-20 19:25

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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