Project1
标题:
发呆一天的产物--获取窗口句柄完美版
[打印本页]
作者:
八云紫
时间:
2010-11-11 11:02
标题:
发呆一天的产物--获取窗口句柄完美版
本帖最后由 铃仙·优昙华院·因幡 于 2010-11-11 20:19 编辑
一大清早起床发呆, 发呆了一天, 于是就有了一下的结果.
dll 版本.
HWND.rar
(131.49 KB, 下载次数: 392)
2010-11-11 17:03 上传
点击文件名下载附件
dll 下载
脚本:
module Kernel
GetWIndowHwnd = Win32API.new("HWND.dll", "GetWIndowHwnd", "v", "l")
def get_hWnd
GetWIndowHwnd.call()
end
end
复制代码
嘛,提升了效率. 不过有 dll 是有点碍眼. Game.exe 和 HWND.dll 要一起使用.
更新一个不需要 dll 的版本:
Game.rar
(89.71 KB, 下载次数: 257)
2010-11-11 20:13 上传
点击文件名下载附件
用法很简单, $HWND 就是窗口句柄.
这个是紫苏大的脚本:
http://rpg.blue/forum.php?mod=vi ... 3%E5%8F%A5%E6%9F%84
作者:
苏小脉
时间:
2010-11-11 11:13
不公开源码么 =(
既然必须用到 DLL,猜测是改用了 EnumWindows,继而需要回调函数?
其实自写 RGSS Player (夏娜写过)是最好的解法,也可以劫持 CreateWindowEx (紫苏似乎弄过一个劫持 user32.dll 的工程)。
作者:
八云紫
时间:
2010-11-11 11:15
本帖最后由 铃仙·优昙华院·因幡 于 2010-11-11 11:17 编辑
源码:
HWND hwnd=0;
DWORD pid=0;
BOOL __stdcall EnumProc(HWND hwnds, LPARAM lParam)
{
DWORD pidwin;
if(hwnds != NULL)
{
::GetWindowThreadProcessId(hwnds, &pidwin);
if(pidwin == pid)
{
hwnd = hwnds;
return 0;
}
return 1;
}
return 1;
}
HWND_API HWND GetWIndowHwnd(DWORD pids)
{
pid = pids;
::EnumWindows(EnumProc, 0);
return hwnd;
}
复制代码
写的比较差劲.
重写其实也不错. 不过有空有能力的话, 倒是可以去试试修改下 exe 或者是 dll 什么的.
不过 Ruby 能处理 函数指针 么??
作者:
苏小脉
时间:
2010-11-11 11:47
本帖最后由 苏小脉 于 2010-11-11 11:50 编辑
其实比较线程标识就可以了,另外 if 内部的 return 1 有点多余。 ^_^
目前这样比较会在某些场合下出现问题,比如:用户通过脚本创建了另一个顶层窗口(自然其创建进程和创建线程都和主窗口一致),这时可能拿到的并不是原来的主窗口句柄。紫苏那贴里的脚本实际上也没有完美地考虑到所有场合——窗口类,顾名思义,就是一类窗口的抽象描述,自然可以有多个窗口实例属于同一个窗口类,而这时如果恰好存在两个同属于 RGSS Player 类,由相同的进程/线程创建的顶层窗口,那获取到的句柄也有可能不是原来的主窗口句柄。
像夏娜那样自行编写一个容器应用程序就很简单地解决了这个问题,毕竟 CreateWindowEx 是在自己的有源码的程序中调用的,其返回值就是窗口句柄。
Ruby 想要通过函数地址来调用本地函数的话,至少需要支持调用函数相关的一些指令(包括转移寄存器值和偏移 PC 等),而为了提供这样的接口,本地 DLL 通常是难免的。
作者:
独孤残云
时间:
2010-11-11 11:50
本帖最后由 独孤残云 于 2010-11-11 11:51 编辑
顶铃仙大人~
话说获取不到窗口句柄确实很纠结的说~
Win32App直接在WinMain中获取句柄,高度封装的Xna则对外暴露了游戏窗口的各项属性(包含句柄),可是貌似RM没有提供相关机制…
~
作者:
八云紫
时间:
2010-11-11 11:58
回复
苏小脉
的帖子
遍历没有直接从 CreateWindowEx 这个拿来的舒服点.
不过有一个想直接修改 RGSS20XX.dll 的想法. 只是输出表重建很麻烦(对于我这样的新手来说)
刚才查阅了一下, Ruby 貌似有调用 CallBack 的方法. 只是在 RGSS2 里使用起来很困难.
作者:
苏小脉
时间:
2010-11-11 12:07
本帖最后由 苏小脉 于 2010-11-11 12:07 编辑
回复
铃仙·优昙华院·因幡
的帖子
CreateWindowEx 是在 Game.exe 这个外壳里被调用的,这个可以通过观察其导入表发现;RGSS***.DLL 主要负责引擎的核心逻辑,这使得 DLL 不受具体窗口的羁绊,也可以算是一种简陋的设计模式吧。
另:你说的调用回调函数(本地?)的方法能否共享一下?
作者:
八云紫
时间:
2010-11-11 12:12
回复
苏小脉
的帖子
好吧, 弄错了. 是 Game.exe
CallBack 的话, 搜索了下, 大部分都是使用 dl 库, 第一句都是 require 'dl' .
然后就果断关网页了.
require 'dl'
user32=DL.dlopen("user32")
enum_windows_callback= DL.callback('ILL') do |hwnd,lparam|
puts "hwnd is #{hwnd}"
0 # return 0 to break the enumeration early
end
begin
puts "calling enumwindows ..."
ret, args=user32['EnumWindows', 'IPL'].call(enum_windows_callback, 0)
puts "called enumwindows."
ensure
puts "removing callback ..."
DL.remove_callback(enum_windows_callback)
puts "removed callback"
end
复制代码
一个也不知道能不能运行的例子
作者:
苏小脉
时间:
2010-11-11 12:23
哦,是用了标准库的 DL。不过 1.9.2 官方的 DL 并没有 callback 这个单例方法,作者应该是进行了扩展的,在 C 层直接调用 callback 的块。
作者:
八云紫
时间:
2010-11-11 12:26
require 'win32/api'
include Win32
# Callback example - Enumerate windows
EnumWindows = API.new('EnumWindows', 'KP', 'L', 'user32')
GetWindowText = API.new('GetWindowText', 'LPI', 'I', 'user32')
EnumWindowsProc = API::Callback.new('LP', 'I'){ |handle, param|
buf = "\0" * 200
GetWindowText.call(handle, buf, 200);
if (!buf.index(param).nil?)
puts "window was found: handle #{handle}"
0 # stop looking after we find it
else
1
end
}
复制代码
这个也差不多, 使用了win32/api . 依旧是不能用
作者:
summer92
时间:
2010-11-11 15:11
介个应该能在生成窗口之前,直接将分辨率改成640x480~~
作者:
八云紫
时间:
2010-11-11 15:20
修改分辨率的那个 dll 和 exe 咱上传过的说. 不过也可以使用脚本来修改~~~
作者:
八云紫
时间:
2010-11-11 17:04
本帖最后由 铃仙·优昙华院·因幡 于 2010-11-11 17:06 编辑
回复
苏小脉
的帖子
现在 窗口类 这个问题也解决了. 句柄是直接从 CreateWindowEx 那里拿到的.
于是乎, 更新了下.
目前 dll 的源码:
HWND hwnd = 0;
HWND_API void SetWindowHwnd(HWND hwnds)
{
hwnd = hwnds;
}
HWND_API HWND GetWIndowHwnd()
{
return hwnd;
}
复制代码
越来越简单了~~~
作者:
八云紫
时间:
2010-11-11 20:12
好吧, 这次就真的是完美版本了. 更新主楼.
作者:
精灵使者
时间:
2010-11-12 08:46
这个可能要用到特殊的exe程序……感觉如果能尽量少修改的话就尽量少修改程序……
作者:
八云紫
时间:
2010-11-12 10:01
所以说是无聊的产物
作者:
苏小脉
时间:
2010-11-14 09:58
本帖最后由 苏小脉 于 2010-11-14 09:59 编辑
赞一个,直接反汇编果然高明!
另:经过调查发现 DB.callback 出现在了 Rails 的官方文档中,但 CRuby 中默认确实没有,可能和具体的 Ruby 实现有关。win32/api 那个是第三方库。
作者:
八云紫
时间:
2010-11-14 09:59
回复
苏小脉
的帖子
限制功能的 RGSS2 很多库都不能用. 很悲剧~~~
作者:
xingmot
时间:
2014-3-3 19:11
直接易语言的获取窗口句柄不就完了...(虽然没怎么看懂...)
欢迎光临 Project1 (https://rpg.blue/)
Powered by Discuz! X3.1