jtackabury

I am hooking MouseLL and I want the callbacks to be processed on a different thread, so that if my interface locks up for a second while it's doing something the mouse doesn't stop responding, or get jittery. I haven't found a good way to do this, so I'm using this:

1. Start a new thread
2. Setup the MouseLL hook in this new thread
3. Run this code inside the thread to keep the thread alive:
while(true)
{ Sleep(1); }

This seems like a horrible hack to me. Is there anyway to keep this thread alive without a loop like this, so it can wait for a callback There must be a better way!

Thanks,
Jon



Re: Visual C# General Hook Callbacks on a new thread

Peter Ritchie

Yes, that's a horrible hack. That basically guarentees to slow everything down.

I would start a background GUI thread. It will remain running without eating the CPU. You can do this without having another Form with the ApplicationContext class. For example:

Code Snippet

///

/// ApplicationContext-based class to be able to create a second message pump

/// Parts lifted from Stephen Toub and http://blogs.msdn.com/toub/archive/2006/05/03/589423.aspx

///

internal class ProgramApplicationContext : ApplicationContext

{

private delegate IntPtr LowLevelKeyboardProc(

int nCode, IntPtr wParam, IntPtr lParam);

private const int WH_KEYBOARD_LL = 13;

private IntPtr hookID;

public ProgramApplicationContext()

{

Form activeForm = System.Windows.Forms.Form.ActiveForm;

// make sure we're informed of the main forms closure

System.Windows.Forms.Form.ActiveForm.FormClosed += new FormClosedEventHandler(ActiveForm_FormClosed);

using (Process curProcess = Process.GetCurrentProcess())

using (ProcessModule curModule = curProcess.MainModule)

{

hookID = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback,

GetModuleHandle(curModule.ModuleName), 0);

}

}

protected override void Dispose(bool disposing)

{

base.Dispose(disposing);

UnhookWindowsHookEx(hookID);

}

~ProgramApplicationContext()

{

Dispose(false);

}

internal static void StartMonitoringKeystrokes()

{

// create another thread to service another message pump

Thread thread = new Thread(new ThreadStart(ThreadEntry));

thread.IsBackground = false;

thread.Start();

}

private static void ThreadEntry()

{

ProgramApplicationContext ap = new ProgramApplicationContext();

Application.Run(ap);

}

private void ActiveForm_FormClosed(object sender, FormClosedEventArgs e)

{

this.ExitThread();

}

private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)

{

Trace.WriteLine(nCode);

return CallNextHookEx(hookID, nCode, wParam, lParam);

}

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]

private static extern IntPtr SetWindowsHookEx(int idHook,

LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]

[return: MarshalAs(UnmanagedType.Bool)]

private static extern bool UnhookWindowsHookEx(IntPtr hhk);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]

private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,

IntPtr wParam, IntPtr lParam);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]

private static extern IntPtr GetModuleHandle(string lpModuleName);

}

Since this class needs to know when the main form is closed, this needs to be run after the main form has been shown. This can be done by handling the Shown event on that form, for example:

Code Snippet

private void Form1_Shown(object sender, EventArgs e)

{

ProgramApplicationContext.StartMonitoringKeystrokes();

}






Re: Visual C# General Hook Callbacks on a new thread

jtackabury

This does look like a MUCH better solution. I'll give it a try as soon as I get a chance and let you know how it works out. I knew my "solution" sounded like a horrible hack, it just had a certain bad smell.





Re: Visual C# General Hook Callbacks on a new thread

Peter Ritchie

Works for me. Be sure not to put a break-point on the access to the ActiveForm property, that is only non-null when the application has focus. When the debugger breaks the application will no longer have focus and you'll get an null exception.




Re: Visual C# General Hook Callbacks on a new thread

jtackabury

This worked like a champ! Thanks a ton for all the help. I integrated it perfectly into my project, worked the first time. You, sir, are truly an MVP.

Jon