查看: 2974|回复: 15

[有事请教] RGSS能处理窗口自定义消息吗?

[复制链接]

遠航の猫咪

梦石
3
星屑
26947
在线时间
2423 小时
注册时间
2005-10-15
回帖
987

开拓者

发表于 2018-1-12 15:07:22 | 显示全部楼层 |阅读模式

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

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

×
照着vb处理的方法用rgss写了一段,无法运行……

有对api比较了解的大牛看看什么情况……?

[pre lang="ruby"]module Kernel
  class << self
  
    GetWindowLong = Win32API.new("user32", "GetWindowLong", "ii", "i")
    SetWindowLong = Win32API.new("user32", "SetWindowLong", "iii", "i")
    CallWindowProc = Win32API.new("user32", "CallWindowProc", "iiiii", "i")
   
  
    def hwnd
      Win32API.new("user32", "GetActiveWindow", "", "i").call
    end
   
    def wm_proc(hwnd, msg, wparam, lparam)
      if msg == 522 # WM_MOUSEWHEEL
        p 1
      else
        CallWindowProc.call(@old_proc_addr, hwnd, msg, wparam, lparam)
      end
    end
   
    def handle
      @old_proc_addr = GetWindowLong.call(hwnd, -4)
      @new_proc_addr = method(:wm_proc).object_id * 2
      SetWindowLong.call(hwnd, -4, @new_proc_addr)
    end
   
    def unhandle
      SetWindowLong.call(hwnd, -4, @old_proc_addr)
    end
  end
end

Kernel.handle
[/pre]
SailCat (小猫子·要开心一点) 共上站 24 次,发表过 11 篇文章 上 次 在: [2006年01月28日11:41:18 星期六] 从 [162.105.120.91] 到本站一游。

老黄鸡

梦石
4
星屑
45700
在线时间
7948 小时
注册时间
2009-7-6
回帖
13338

MZ评测员RM创作大赛01组委会开拓者贵宾

发表于 2018-1-12 15:32:43 | 显示全部楼层
啊,其实方法倒是对了,但是ruby的函数肯定不能用来做回调函数的……
https://rpg.blue/thread-370060-1-1.html
具体使用方法参考本文即可。
上面的方法是根据yangff的无DLL鼠标修改而来,过滤了消息类型。

点评

我惊了,忘了撤销售价  发表于 2018-1-12 16:29
竟然回调函数要写成二进制代码才行……没法,一写汇编脑仁儿疼……上次写那个RGBA-BGRA的代码折腾了我快一个星期……  发表于 2018-1-12 16:09
这附件也太贵了……!!!  发表于 2018-1-12 15:43
RGDirect - DirectX驱动的RGSS,点我了解.
(排满,暂停)RM全系列成套系统定制请联系QQ1213237796
不接受对其他插件维护的委托
回复

使用道具 举报

头像被屏蔽
梦石
0
星屑
653
在线时间
3774 小时
注册时间
2011-2-26
回帖
1577

开拓者

发表于 2018-1-12 18:24:54 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

梦石
0
星屑
1803
在线时间
133 小时
注册时间
2013-10-6
回帖
181
发表于 2018-1-13 23:52:53 | 显示全部楼层
本帖最后由 不死鸟之翼 于 2018-1-13 23:54 编辑

这是一个典型的脚本语言和原生代码的互操作问题,回调参数一定需要是原生代码。
因为Win32 API层是C/C++的天下,所以我们用C/C++处理这类问题显然比手写机器指令舒服得多(我特么也脑仁儿疼啊)。
主要思路是Ruby到C++用Win32API call通信,回来就用RGSSEval。

大概写了一段,编译成DLL并导出Inject函数即可。

[pre lang="ruby" line="1"]using RGSSEval_t = int(__cdecl*)(const char*);

RGSSEval_t RGSSEval = nullptr;
WNDPROC OldWindowProc = nullptr;
string rubyCallbackFunc;

LRESULT CALLBACK CustomWindowsProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
        switch (uMsg) {
        case WM_MOUSEWHEEL: {
                int zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
                int xPos = GET_X_LPARAM(lParam);
                int yPos = GET_Y_LPARAM(lParam);
                int fwKeys = GET_KEYSTATE_WPARAM(wParam);
                POINT clientPt = { xPos,yPos };
                ScreenToClient(hWnd, &clientPt);
                stringstream expr;
                expr << rubyCallbackFunc << "(" << zDelta << "," << clientPt.x << "," << clientPt.y << "," << fwKeys << ")";
                RGSSEval(expr.str().c_str());
                return CallWindowProcA(OldWindowProc, hWnd, uMsg, wParam, lParam);
        }
        default:
                return CallWindowProcA(OldWindowProc, hWnd, uMsg, wParam, lParam);
        }
}

INT WINAPI Inject(const char* callbackName)
{
        HMODULE hModule=GetModuleHandleA("RGSS202E.dll"); //Change this if necessary
        if (hModule) {
                RGSSEval = (RGSSEval_t)GetProcAddress(hModule, "RGSSEval");
                if (RGSSEval) {
                        HWND hWnd = GetActiveWindow();
                        if (hWnd) {
                                OldWindowProc = (WNDPROC)SetWindowLongA(hWnd, GWL_WNDPROC, (LONG)CustomWindowsProc);
                                rubyCallbackFunc = callbackName;
                                return TRUE;
                        }
                }
        }
        return FALSE;
}[/pre]

Ruby侧提供回调函数

[pre lang="ruby" line="1"]def on_mouse_wheel(zDelta,xPos,yPos,fwKeys)
  p "delta=#{zDelta} mouse_x=#{xPos} mouse_y=#{yPos} modifiers=#{fwKeys}"
end

fun=Win32API.new('WndProc.dll','Inject','p','i')
if fun.call('on_mouse_wheel')==0
  p 'Failed'
end[/pre]

fwKeys当特定键按下时特定位为1,详情参考MSDN。

效果图

screenshot.jpg

如果需要处理其他消息的话在窗口过程里增加即可。
因为窗口过程是在主消息循环中分发消息时调用的,所以不会有线程同步问题。

WNDPROC.zip

101.49 KB, 下载次数: 2

售价: 5 星屑  [记录]

点评

虽然同一个线程,但是还是有可能会碰到GVML(GIL)  发表于 2018-1-14 20:38
感谢解决,但是“编译成DLL”……这不是我写插件的初衷了……我还是自己研究下无DLL的方案吧  发表于 2018-1-14 00:09
←你看到一只经常潜水的萌新。
回复

使用道具 举报

梦石
0
星屑
1803
在线时间
133 小时
注册时间
2013-10-6
回帖
181
发表于 2018-1-14 00:16:01 | 显示全部楼层
如果不要DLL的话也很好搞 编译完了之后拿一个反汇编器(比如OD)把核心代码copy走,然后Ruby里申请一块内存填进去,给EXECUTE权限就完了。传回数据也是RGSSEval。

另外 我点评我自己的帖子之后,其他点评了的人是否会收到通知?麻烦告知

点评

已收到通知,哈哈  发表于 2018-1-14 09:51
thx&test  发表于 2018-1-14 04:04
应该是会有的吧,就是“XXX和您在同一层点评了……”那个通知,我收到过。  发表于 2018-1-14 00:39
←你看到一只经常潜水的萌新。
回复

使用道具 举报

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

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部