赞 | 14 |
VIP | 0 |
好人卡 | 1 |
积分 | 18 |
经验 | 2716 |
最后登录 | 2022-6-5 |
在线时间 | 133 小时 |
Lv3.寻梦者
- 梦石
- 0
- 星屑
- 1803
- 在线时间
- 133 小时
- 注册时间
- 2013-10-6
- 帖子
- 193
|
本帖最后由 不死鸟之翼 于 2018-1-13 23:54 编辑
这是一个典型的脚本语言和原生代码的互操作问题,回调参数一定需要是原生代码。
因为Win32 API层是C/C++的天下,所以我们用C/C++处理这类问题显然比手写机器指令舒服得多(我特么也脑仁儿疼啊)。
主要思路是Ruby到C++用Win32API call通信,回来就用RGSSEval。
大概写了一段,编译成DLL并导出Inject函数即可。
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; }
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;
}
Ruby侧提供回调函数
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
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
fwKeys当特定键按下时特定位为1,详情参考MSDN。
效果图
如果需要处理其他消息的话在窗口过程里增加即可。
因为窗口过程是在主消息循环中分发消息时调用的,所以不会有线程同步问题。 |
|