Project1

标题: [RMVX] 真·后台运行(2009/11/25 重要更新) [打印本页]

作者: 紫苏    时间: 2009-7-14 15:46
标题: [RMVX] 真·后台运行(2009/11/25 重要更新)
本帖最后由 紫苏 于 2009-11-25 11:30 编辑

RMVXBR.rar (258.57 KB, 下载次数: 2817)

2009/07/14:


2009/09/01:


2009/11/25:


前不久刚发布了 RMXP 真·后台运行,当时感觉应该可以直接应用到 RMVX,结果 zh 测试后发现会发生错误。

通过调试发现,在 DLL 中不能直接调用老的窗口过程函数,而必须把地址传递给 CallWindowProc 函数让它来调用,否则在 VX 中就会出错,原因按照 MSDN 的说法,是因为 SetWindowLong 的返回值可能是函数地址,也可能是一个只对 CallWindowProc 有意义的特殊值~

修改为调用 CallWindowProc 之后,倒是不会出错了,但却又衍生出新的问题——在程序响应移动窗口、最大化、最小化等窗口消息时十分缓慢,原因不明……

于是今天尝试把拦截 WM_ACTIVATEAPP 的过程直接写到 DLL 中,测试就冇问题了 = =||
推测之前的问题可能是由于 RGSS2***.dll 中的 RGSSEval 函数效率不及 RGSS1***.dll 的,导致在 dll 中解释 Ruby 窗口过程缓慢……

用法见范例工程,绑定失去焦点时不响应键盘功能,否则可能被杀软认为是 keylogger~
请务必保留 Lib 文件夹 以及其中的 BackgroundRunning.dll

调用源代码:
  1. unless $_Start


  2. $_Start = Win32API.new("Lib/BackgroundRunning","Start",'V','L')
  3. $_Stop = Win32API.new("Lib/BackgroundRunning","Stop",'V','L')
  4. $_OnFocus = Win32API.new("Lib/BackgroundRunning","OnFocus",'V','L')

  5. $_Start.call

  6. module Input
  7.   InputUpdate = method :update
  8.   InputTrigger = method :trigger?
  9.   InputPress = method :press?
  10.   InputRepeat = method :repeat?
  11.   InputDir4 = method :dir4
  12.   InputDir8 = method :dir8
  13.   def self.update
  14.     InputUpdate.call if $_OnFocus.call != 0
  15.   end
  16.   def self.trigger?(num)
  17.     return $_OnFocus.call != 0 ? InputTrigger.call(num) : false
  18.   end
  19.   def self.press?(num)
  20.     return $_OnFocus.call != 0 ? InputPress.call(num) : false
  21.   end
  22.   def self.repeat?(num)
  23.     return $_OnFocus.call != 0 ? InputRepeat.call(num) : false
  24.   end
  25.   def self.dir4
  26.     return $_OnFocus.call != 0 ? InputDir4.call : 0   
  27.   end
  28.   def self.dir8
  29.     return $_OnFocus.call != 0 ? InputDir8.call : 0   
  30.   end
  31. end


  32. end
复制代码
DLL 源代码:

  1. #include <windows.h>
  2. #include <stdio.h>

  3. HWND g_hWnd = NULL;
  4. LONG g_pOldWndProc = NULL;
  5. BOOL g_onFocus = TRUE;
  6. bool g_started = FALSE;

  7. LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  8. {
  9.     switch(uMsg)
  10.     {
  11.     case WM_ACTIVATEAPP:
  12.         g_onFocus = wParam;
  13.         return TRUE;
  14.     default:
  15.         return CallWindowProc((WNDPROC)g_pOldWndProc, hWnd, uMsg, wParam, lParam);
  16.     }
  17. }

  18. int Start()
  19. {
  20.     if(!g_started)
  21.     {
  22.         // Retrieve the current thread identifier.
  23.         DWORD threadID = GetCurrentThreadId();
  24.         // Retrieve the handle to the front-most window.
  25.         g_hWnd = GetWindow(GetForegroundWindow(), GW_HWNDFIRST);
  26.         // Enumerate all the windows.
  27.         while(g_hWnd)
  28.         {
  29.             // If the current thread identifier matches the one being enumerated, then
  30.             if(threadID == GetWindowThreadProcessId(g_hWnd, NULL))
  31.             {
  32.                 // Allocate a buffer of length 12.
  33.                 char className[12];
  34.                 // Get the class name of the window.
  35.                 GetClassName(g_hWnd, className, 12);
  36.                 // break the loop if the class name matches.
  37.                 if(strcmp(className, "RGSS Player") == 0)
  38.                     break;
  39.             }
  40.             // Retrieve the handle to the next window.
  41.             g_hWnd = GetWindow(g_hWnd, GW_HWNDNEXT);
  42.         }

  43.         // Failed when retrieving the handle to the window.
  44.         if(!g_hWnd)
  45.             return 1;

  46.         g_pOldWndProc = SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG)WindowProc);
  47.         // Failed when replacing window proc.
  48.         if(!g_pOldWndProc)
  49.             return 2;

  50.         g_started = true;
  51.     }
  52.     return 0;
  53. }

  54. int Stop()
  55. {
  56.     if(g_started)
  57.     {
  58.         // Failed when retrieving the handle to the window.
  59.         if(!g_hWnd)
  60.             return 1;

  61.         // Failed when reverting the window proc.
  62.         if(!SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG)g_pOldWndProc))
  63.             return 2;

  64.         g_started = false;
  65.     }
  66.     return 0;
  67. }

  68. int OnFocus()
  69. {
  70.     return g_onFocus;
  71. }
复制代码

作者: zh99998    时间: 2009-7-14 16:46
终于出现了~~~先坐沙发
嗯……范例工程出错了
---------------------------
真·后台运行
---------------------------
脚本 '真·后台运行' 的第 4 行发生了 RuntimeError .

LoadLibrary: Lib/VXBkRun

---------------------------
确定   
---------------------------

作者: IamI    时间: 2009-7-14 17:03
本帖最后由 IamI 于 2009-7-14 17:07 编辑

故障同LS
作者: 猫哥哥    时间: 2009-7-14 17:51
打开工程运行正常。
作者: 紫苏    时间: 2009-7-14 17:56
1、2楼的问题已经修复,感谢提出 ^^
作者: 外星星人    时间: 2009-7-14 19:48
提示: 作者被禁止或删除 内容自动屏蔽
作者: 风雪优游    时间: 2009-7-14 20:02
昨天看到问题,今天就看到脚本。LZ真有效率,支持一个。
作者: zh99998    时间: 2009-7-14 20:17
外星星人
现在再下载一次试试呢
作者: 第二疯子    时间: 2009-7-18 14:03
  1. 脚本 '真·后台运行' 的第 4 行发生了 RuntimeError .
复制代码
故障依然…………
作者: zh99998    时间: 2009-8-4 15:24
话说……那个键盘好像没重定义trigger……如果刚按下一个键的时候切到后台了
然后不更新,就一直trigger了
(好吧我是来挑刺的)
作者: 沉影不器    时间: 2009-8-7 22:35
提示: 作者被禁止或删除 内容自动屏蔽
作者: 紫苏    时间: 2009-9-1 06:12
主楼更新,厚颜自顶 =w=

话说……那个键盘好像没重定义trigger……如果刚按下一个键的时候切到后台了
然后不更新,就一直trigger了
(好吧我是来挑刺的)
zh99998 发表于 2009-8-4 15:24

trigger? 不是只判断按下的瞬间么 o.o
……算了,加上判断好了~
这个强大的东西,7月份就发表了?...之前怎么没发现= =//
rm没办法直接用回调函数...
沉影不器 发表于 2009-8-7 22:35

确实,要用也只能把函数放在 DLL 里……




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1