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