查看: 96|回复: 0

[转载发布] 启动时获取句柄 | 修改分辨率 | 窗口外观 | 加载字体

[复制链接]
  • TA的每日心情
    开心
    7 天前
  • 签到天数: 37 天

    连续签到: 3 天

    [LV.5]常住居民I

    2028

    主题

    32

    回帖

    7260

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    VIP
    0
    卡币
    5184
    OK点
    16
    积分
    7260
    发表于 同元一千年八月四日(秋) | 显示全部楼层 |阅读模式
    灵感来自最近偶然看到的夏娜的 RGSS102J.dll 补丁:
    http://rpg.blue/forum.php?mod=viewthread&tid=127979
    http://rpg.blue/thread-118633-1-1.html
    这个工程实现了在启动时准确获取句柄、修改游戏窗口分辨率、窗口外观以及加载字体的功能,通过代理 DLL 劫持了 kernel32 和 user32 这两个系统 DLL,而其中最重要的是在 kernel32 里的 LoadLibrary 或 GetProcAddress上安装钩子,因为 RM 通过这两个函数获得的地址调用了大量函数,而这些函数并不在对象文件的导入表中

    1、获取句柄
    hook user32 的 CreateWindowEx,返回的时候保存一个全局的句柄变量,然后再提供给 Ruby 一个接口获取这个变量。于是这个脚本可以退休了:
    http://rpg.blue/forum.php?mod=viewthread&tid=133018
    实际上这个脚本也确实有潜在的问题,GetWindow 在极端场合下会引起无限循环,和这个直接劫持 API 的质量没法比

    2、修改分辨率
    这个和目前的分辨率脚本相比之下,优势在于启动时就修改,而不是等到 RGSS 开始执行脚本时才修改。RM 的 Game.exe 创建窗口的过程是:
    设计窗口类 WNDCLASS;
    RegisterWindow 注册窗口类;
    CreateWindowEx 创建窗口;
    通过 SetRect 把一个 RECT 矩形结构体初始化为 (0, 0, 640, 480);
    通过以上矩形,AdjustWindowRect 计算出 640*480 的客户区需要多大的窗口尺寸;
    GetSystemMetric 获取系统屏幕等信息,计算窗口居中的坐标;
    SetWindowPos 移动窗口,并调整尺寸

    到这里 Game.exe 就完事儿了,但如果你只 hook 了这些函数中的一个来改分辨率,结果是一会儿又被改回了 640*480。这是因为 rgss10*j.dll 里还有龌龊的勾当,它会第二次调用 SetWindowPos 移动窗口并修改尺寸,但这一点从它的导入表里看不出来,因为它是通过 GetProcAddress 获取的函数地址来调用 API 的。于是首先要 hook Kernel 的 GetProcAddress,劫持 SetWindowPos,然后把调用转移到 user32 的代理 DLL 中。两边都劫持后,启动时修改分辨率就实现了

    3、修改窗口外观
    仍然是 Hook CreateWindowEx,把传递进来的 dwStyle 参数和 dwExStyle 胡改一气即可。范例工程里改了几个,但并没有全部囊括,有心人可以自行添加

    4、加载字体
    Kernel32 必然是首先映射到进程地址空间的 DLL,所以在 kernel32 的代理 DLL 的入口函数里调用 AddFontResourceEx 即可

    以上功能中需要配置参数都可以在 Game.ini 中调整,内含详细注释。kernel32 的 代理 DLL 是 kernel33,user32 自然就是 user33。源代码在工程的 src 目录下,比较长。就不发到帖子里了,可以自行 build

    范例使用的是 RGSS103J.DLL,如果你希望使用 1.02 的 DLL,那可以用十六进制编辑器把 rgss102j.dll 里的 kernel32.dll 改为 kernel33.dll(Game.exe 也是相同的改法,同时还可以改 user32 为 user33)。否则可以直接拷贝 Game.exe、Game.ini、user33.dll、kernel33.dll 到你的工程,覆盖原文件。如果你不需要范例中的字体,那可以修改 Game.ini 中的字体设置为空

    这四个功能都是以前有过脚本,但多少都有点问题的,所以先行实现,但通过 DLL 劫持,可能性还有很多。proc.txt 里包含了 RMXP 通过 GetProcAddress 调用的函数(仅含“第一层”,不包含 LoadLibrary 获取真实 user32 的 GetProcAddress 地址然后又通过它调用的“第二层”函数)

    欢迎提出建议,以及可能、希望实现的功能

                 本帖来自P1论坛作者紫苏,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg.blue/forum.php?mod=viewthread&tid=157287  若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x
    天天去同能,天天有童年!
    回复 论坛版权

    使用道具 举报

    ahome_bigavatar:guest
    ahome_bigavatar:welcomelogin
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|同能RPG制作大师 ( 沪ICP备12027754号-3 )

    GMT+8, 2024-5-17 16:38 , Processed in 0.047588 second(s), 44 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

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