我使用以下代码在当前进程上获取鼠标消息。
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
出于某种原因,当此代码运行时,鼠标会慢慢运行几秒钟然后恢复正常。
任何想法?
感谢
编辑 - 挂钩方法
private static IntPtr mouseEvent(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
LastLeftClick = new ClickInfo { Time = DateTime.Now, X = hookStruct.pt.x, Y = hookStruct.pt.y };
}
return CallNextHookEx(hookID, nCode, wParam, lParam);
}
public class ClickInfo
{
public int X { get; set; }
public int Y { get; set; }
public DateTime Time { get; set; }
}
答案 0 :(得分:2)
你的钩子程序是什么样的?
如果您的进程只有一个UI线程,请使用消息过滤器: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.addmessagefilter.aspx
答案 1 :(得分:2)
我有同样的问题(只有它的c ++项目,而不是c#)并通过将WH_MOUSE_LL的挂钩更改为WH_MOUSE(从低级别到正常级别)来解决它。对于WM_LBUTTONUP和WM_RBUTTONUP消息,它可以正常工作。
让我感到高兴的是WH_MOUSE_LL的代码在我写它的时候表现不错(没有鼠标冻结等)似乎Windows的一些安全更新改变了鼠标钩子的行为,以前的精细代码变成了问题
答案 2 :(得分:2)
通过设置低级钩子响应性,鼠标现在变得依赖于主线程的响应,并且常见的错误是在启动过程中尽早设置钩子。
SetHook
LongRunningStartupProcess
鼠标直到此处才响应
在启动期间,最好将挂钩调度到线程上,以便在启动过程结束时发生。 Dispatcher.CurrentDispatcher.BeginInvoke(new Action(SetHook));
DispatchSetHook
LongRunningStartupProcess
SetHook(回调)
鼠标变得响应
在您的应用程序中仍然存在持续的管理问题,以确保主线程不执行任何长时间运行的进程,因为这也会锁定鼠标。这可以通过设置挂钩然后在主线程上执行Thread.Sleep
来轻松验证。
答案 3 :(得分:1)
你的钩子过程很贵;你只需要弄清楚为什么以及如何解决它。
尽管代码看起来非常小,但我怀疑有一些初始的C#互操作费用会触发延迟,可能是由于JIT或分页。
如果您更改代码以尽可能多地处理此线程,则问题应该消失。作为一名C ++开发人员,我甚至担心Marshal.PtrToStructure,因为低级别的钩子非常敏感,我不能说这个操作保证是如此便宜以至于不会损害鼠标移动。
我过去曾经使用过低级别的鼠标钩子(在C ++中),并且除非钩子程序本身很昂贵,否则从未出现过问题。在C ++中,我尝试避免对执行剩余处理的HWND执行除PostMessage之外的任何操作。
答案 4 :(得分:1)
当你收到钩子事件时,关掉书,然后做你的工作,如果真的还需要,把钩子重新打开。
这将阻止鼠标滞后。
只有在你真正需要的时候才会保持迷茫。
答案 5 :(得分:0)
很抱歉,经过了这么长的时间,我仍在跟进,但是我通过产生一个单独的线程处理钩子解决了这个问题(我没有将所有内容添加到代码中,因为它还可以翻译消息,但是主要思想应该很清楚):
public Form1()
{
InitializeComponent();
Thread thread = new Thread(HookThread);
thread.IsBackground = true;
thread.Start();
}
private void HookThread()
{
_hookControl = new Control();
IntPtr handle = _hookControl.Handle;
_hookProc = new HookProc(HookFunction);
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
_hook = SetWindowsHookEx(HookType.WH_MOUSE_LL, _hookProc, GetModuleHandle(curModule.ModuleName), 0);// (uint)AppDomain.GetCurrentThreadId());
}
Application.Run();
UnhookWindowsHookEx(_hook);
_hook = IntPtr.Zero;
}
private IntPtr HookFunction(int code, IntPtr wParam, IntPtr lParam)
{
if (code < 0)
{
//you need to call CallNextHookEx without further processing
//and return the value returned by CallNextHookEx
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
int msg = wParam.ToInt32();
string messages = string.Join(", ", _messageMapping.Where(t => t.Item1 == msg).Select(t => t.Item2));
if (string.IsNullOrWhiteSpace(messages))
messages = msg.ToString();
Trace.WriteLine($"Messages: { messages }");
//return the value returned by CallNextHookEx
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
您可以通过在创建的_hookControl上调用BeginInvoke来终止其他线程的线程:
_hookControl.BeginInvoke(((Action)(() => Application.ExitThread())));