I'm using the first code block to execute a low-level mouse hook on a separate thread. It actually works like this (believe it or not) because the act of subscribing initializes the hook. And with a hook I need to be able to block the method calling an event so that I can set a value to alter its course of execution. This is the reason why I can't simply off-load the event handler to another thread.
My problems is, even though this works, is there another way that can avoid DoEvents
?
Is it possible that DoEvents
only applies to events on its own thread or does this call affect my GUI thread? It does not appear to affect my GUI at all as far as I can tell.
Note: Without the call to Sleep
the CPU will increase significantly.
Note: Without DoEvents
the hook messages build up and force the OS to disconnect the hook.
EDIT: I created a sample project so you guys can test this. The app will start a mouse hook on a separate thread and capture a mouse right-click and let you know it did so via a message box. You can get that project using the below link.
The sample shows that you can block the GUI thread and still handle the hook without issues which confirms that the hook is on its own thread.
https://github.com/mzomparelli/Threaded-Low-Level-Mouse-Hook-Example
I am now starting to think that this is a valid use of DoEvents
despite the many claims that DoEvents
is always bad.
private static bool blnStopMouseHook = false;
public static void StartMouseHook()
{
if (MouseHook == null)
{
blnStopMouseHook = false;
MouseHook = new Thread(new ThreadStart(() => { MouseHookThread(); }));
MouseHook.SetApartmentState(ApartmentState.STA);
MouseHook.Start();
}
}
public static void StopMouseHook()
{
blnStopMouseHook = true;
MouseHook.Join();
MouseHook = null;
}
private static void MouseHookThread()
{
HookManager.MouseWheel += HookHandlers.HookManagerOnMouseWheel;
HookManager.MouseClickExt += HookHandlers.HookManagerOnMouseClickExt;
do
{
System.Threading.Thread.Sleep(1);
Application.DoEvents();
} while (blnStopMouseHook == false);
HookManager.MouseWheel -= HookHandlers.HookManagerOnMouseWheel;
HookManager.MouseClickExt -= HookHandlers.HookManagerOnMouseClickExt;
}
Below is a snippet of my HookProc which creates the event HookManagerOnMouseWheel
private static int MouseHookProc(int nCode, int wParam, IntPtr lParam)
{
if (nCode >= 0)
{
//Marshall the data from callback.
MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));
switch (wParam)
{
case WM_MOUSEWHEEL:
mouseDelta = (short)((mouseHookStruct.MouseData >> 16) & 0xffff);
break;
}
//generate event
MouseEventExtArgs e = new MouseEventExtArgs(
button,
clickCount,
mouseHookStruct.Point.X,
mouseHookStruct.Point.Y,
mouseDelta);
//Wheel was moved
if (s_MouseWheel!=null && mouseDelta!=0)
{
s_MouseWheel.Invoke(null, e);
}
//If someone listens to move and there was a change in coordinates raise move event
if (e.Handled)
{
return -1;
}
}
//call next hook
return CallNextHookEx(s_MouseHookHandle, nCode, wParam, lParam);
}
This is my event handler.
public static void HookManagerOnMouseWheel(object sender, MouseEventExtArgs mouseEventArgs)
{
int iHotkey;
int iHotkey2;
string keyCombination = CurrentModifiers();
string keyCombination2 = CurrentModifiers();
if (Window.Taskbar().IsMouseOver() || Window.Taskbar2().IsMouseOver())
{
//Create combination string
if (mouseEventArgs.Delta < 0)
{
keyCombination = keyCombination + "+MOUSE-TASKBAR-SCROLL-DOWN";
keyCombination2 = keyCombination2 + "+MOUSE-ANYWHERE-SCROLL-DOWN";
}
else
{
keyCombination = keyCombination + "+MOUSE-TASKBAR-SCROLL-UP";
keyCombination2 = keyCombination2 + "+MOUSE-ANYWHERE-SCROLL-UP";
}
iHotkey = GLOBALS.hotkeys.FindIndex(l => l.HotkeyString() == keyCombination);
iHotkey2 = GLOBALS.hotkeys.FindIndex(l => l.HotkeyString() == keyCombination2);
if (iHotkey >= 0)
{
ExecuteAction(iHotkey);
mouseEventArgs.Handled = true;
return;
}
else if (iHotkey2 >= 0)
{
ExecuteAction(iHotkey2);
mouseEventArgs.Handled = true;
return;
}
}
if (mouseEventArgs.Delta < 0)
{
keyCombination = keyCombination + "+MOUSE-ANYWHERE-SCROLL-DOWN";
}
else
{
keyCombination = keyCombination + "+MOUSE-ANYWHERE-SCROLL-UP";
}
iHotkey = GLOBALS.hotkeys.FindIndex(l => l.HotkeyString() == keyCombination);
if (iHotkey >= 0)
{
ExecuteAction(iHotkey);
mouseEventArgs.Handled = true;
return;
}
}