2

I am using the code from this article :

private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;

public static void Main()
{
    _hookID = SetHook(_proc);
    //Application.Run();
    //UnhookWindowsHookEx(_hookID);
}

private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
    using (Process curProcess = Process.GetCurrentProcess())
    using (ProcessModule curModule = curProcess.MainModule)
    {
        return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
            GetModuleHandle(curModule.ModuleName), 0);
    }
}

private delegate IntPtr LowLevelKeyboardProc(
    int nCode, IntPtr wParam, IntPtr lParam);

private static IntPtr HookCallback(
    int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
    {
        int vkCode = Marshal.ReadInt32(lParam);
        ***custom code***
    }
    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);

with a little modification but sometimes when i press a couple of keystrokes too fast then the computer "slows" down a bit and gets a little "laggy".

So when it hits asyncronosly the event HookCallback it sometimes get a little laggy, but i guess its the code in this method "HookCallback" that makes it laggy or is it the hooking it self? I had an idea about creating a new thread everytime i enter "HookCallback" , that maybe will help but do i want to start a new thread everytime i press a key? I am getting an asyncronosly call already so i dont know if i should start another thread besides that.

So my question is simple, where and why does it slow down the computer, is it the hooking it self or is it the custom code ? Or should i put the custom code in a different thread?

And i have another question, sometimes after a few keypresses "HookCallback" doesnt get called, as if i have "unhooked" the event, and it wont capture any keystrokes at all. How can i make sure that it never unhooks the event unless i do it in manually?

Thank you.

Chris Eberle
  • 47,994
  • 12
  • 82
  • 119
brutton
  • 31
  • 1
  • 4
  • Have you tried using a Profiler to see which methods are taking the most time. A lot of Profilers have a free trail period. I can't seem to see why it would slow your pc down. – Jethro Jul 31 '11 at 18:58
  • It might help showing us what code you actually have in HookCallback. Do you do anything expensive ? The hook itself, obviously, has some performance implications, but I would not expect it to be noticable on modern machines. Starting a thread might be just as expensive as your actual work (use the threadpool if you must). – driis Jul 31 '11 at 18:58
  • @driis, he has showing us the code for HookCallback. – Jethro Jul 31 '11 at 19:01
  • No repro and nothing in the code that would explain a slowdown. Be sure to compile as a console mode app. It must be environmental. – Hans Passant Jul 31 '11 at 19:03
  • I made an error, it is a winforms application, just edited my post. – brutton Jul 31 '11 at 19:04

4 Answers4

2

I've spent a fair amount of time doing keyboard hooks, so the following is just my own experience. Hooks need to be efficient. I wrote a small POS app a few years ago that had to capture keystrokes. It was written in C#, and slowed the input to the point of becoming noticeable. After a lot of headaches I finally realized that the big lag was coming from the translation from native code to managed code. I re-wrote small pieces of the hook code in C++ (native) and saw improvements that I would deem "good enough".

Just remember that speed is fully determined by how long your code takes to process it. Try your very best to make it efficient.

Chris Eberle
  • 47,994
  • 12
  • 82
  • 119
  • Ok but i cant rewrite the hook in c++ , just need to know if someone had a similar problem and solved it without having to re-write the hook functionality. I guess u dont have that hooking dll public? :) – brutton Jul 31 '11 at 19:03
  • 1
    Also, keeping it in C# was not mentioned as a requirement. You're complaining about lag, and I'm saying that in my own experience the problem is C# (or more specifically, the CLR). – Chris Eberle Jul 31 '11 at 19:08
  • You have any idea for my second question? About it sometimes "unhooks" the event? – brutton Jul 31 '11 at 19:09
  • Yeah, some apps can insert themselves in the chain *before* you, and capture whatever they please. – Chris Eberle Jul 31 '11 at 19:09
0

There is another factor about "unhook" problem. If your low level global hook codes can not finish in certain amount of time, the OS will remove your hook automatically without notifying you. So make your codes run as fast as possible

Cheers

APZ28
  • 997
  • 5
  • 4
-1

I had the same symptoms, but it turned out my issue was due to Thread.Sleep(); I had recently changed my application from a Console to Windows Application. My code had been:

static void Main( string[] args )
{
    hook_keys();
    AppDomain.CurrentDomain.ProcessExit += CurrentDomainOnProcessExit;
    while (true) { System.Threading.Thread.Sleep( new TimeSpan(0,10,0) ); }
}
private static void CurrentDomainOnProcessExit(object sender, EventArgs eventArgs )
{
    unhook_keys();
}

This made windows slow down incredibly, even though all my hook does is increment a global variable whenever the keyboard is used. When I changed it to the following, my lag issue was resolved:

static void Main( string[] args )
{
    hook_keys();
    var application = new Application();
    application.Run();
    unhook_keys();
}
mdiehl13
  • 472
  • 6
  • 19
-1

If you want to capture keystrokes within your application only, things can be faster then; use WH_KEYBOARD instead of WH_KEYBOARD_LL, this will make much more noticeable performance increase.

private const int WH_KEYBOARD = 2;
Jalal Said
  • 15,906
  • 7
  • 45
  • 68
  • Its global keyboard hook so i cant use it in my application only. – brutton Jul 31 '11 at 19:14
  • Did you try [this](http://www.codeproject.com/KB/cs/globalhook.aspx) before? [Here](http://stackoverflow.com/questions/6871023/how-to-make-an-application-that-can-capture-all-click-when-you-press-the-enter-ke/6871142#6871142) how to use it. it also use in internally those APIs but how knows maybe it is faster.. – Jalal Said Jul 31 '11 at 19:20