none
Low-Level Keyboard Hook in C# --> Timer problem

    General discussion

  • Hello!
    This is some code for a low level keyboard hook...


    The code looks like this:

    using System;
    using System.Diagnostics;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;

    class InterceptKeys
    {
    private const int WH_KEYBOARD_LL = 13;
    private const int WM_KEYDOWN = 0x0100;
    private static LowLevelKeyboardProc _proc = HookCallback;


    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)
    {

    return CallNextHookEx(_hookID, nCode, wParam, lowParam);
    }

    [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);
    }


    I am able to "record" the user inputs into a text file with no problem.
    My question: How can I implement a timer so the file gets emptied between a specific interval  (example: every 10 min. the file is emptied)?

    I don't know where should I declare the timer. I tried to declare it in Main(), something like:

    <code>
    public static void Main()
    {
    _hookID = SetHook(_proc);
    System.Timers.Timer timer = new System.Timers.Timer(30000);
    timer.Elapsed += new ElapsedEventHandler(anotherclass.OnTimedEvent);
    timer.Enabled = true;
    Application.Run();
    UnhookWindowsHookEx(_hookID);
    }
    <code>

    I run the project, type some random letters, I see them in my text file. After 30 second the file is empty. Everything ok. I type some random letters again and wait for a few seconds... The letters are in the file, but the file doesn't get emptied...
    The contents of the file are deleted only once!
    After some waiting, I pause the project and I see highlighted in green the line: Application.Run(); (basically the application is waiting for another user input, but the timer is "forgotten").

    Thank you. I hope someone will help me.

    Nicholas



    • Changed type Drago91 Monday, June 23, 2008 4:39 PM the problem I had was silly, there was no need for a question...
    • Changed type Drago91 Monday, June 23, 2008 4:39 PM the problem I had was silly, there was no need for a question...
    • Changed type Drago91 Monday, June 23, 2008 4:39 PM the problem I had was silly, there was no need for a question...
    • Changed type Drago91 Monday, June 23, 2008 4:39 PM the problem I had was silly, there was no need for a question...
    • Changed type Drago91 Monday, June 23, 2008 4:39 PM the problem I had was silly, there was no need for a question...
    • Changed type Drago91 Monday, June 23, 2008 4:39 PM the problem I had was silly, there was no need for a question...
    • Changed type Drago91 Monday, June 23, 2008 4:39 PM the problem I had was silly, there was no need for a question...
    • Changed type Drago91 Monday, June 23, 2008 4:41 PM the problem I had was silly, there was no need to make this thread a question
    • Edited by Drago91 Monday, June 23, 2008 4:44 PM editing some code...
    Saturday, June 21, 2008 9:30 PM

All replies

  •  
    I run the project, type some random letters, I see them in my text file. After 30 second the file is empty. Everything ok. I type some random letters again and wait for a few seconds... The letters are in the file, but the file doesn't get emptied...

    It is a typical problem with timers. Honestly I do believe there are bugs in the Timer classes (there are two). I think since the timers are not a crucial part of any code MS does not pay any attention to them. I've had similar problems and have given up on them except for displaying elapsed time on a label.

    One thing you may try to do it to put your timer in a separate thread and have it manipulate your file from there with BeginInvoke. It will give you much better chances. On the other hand the timers are considered thread safe, so I don't know how much it will do for you. Maybe they are thread safe for the very same reason that you cannot make them to work.

    AlexB
    Saturday, June 21, 2008 9:41 PM
  • In your code you define timer as a local variable to the Main method, you configure it, then you do not use it any more.

    Since you do not use it any more, garbage collection should be free to clean it up, and thus the timer might disappear before it ever gets fired. I say "might" because I'm unsure if the timer does anything to make sure it stays alive while enabled.

    You can try to just add the following line after Application.Run():

    GC.KeepAlive(timer);

    As for the rest of your post, since you do not post neither the code that writes the text to your file nor the code that attempts to empty the file, nor how this code is invoked, it is impossible to determine why something happens and not the other.

    As for AlexBB, I don't really understand what you mean by a typical problem with timers. Is it a typical problem with timers that files don't get emptied? Since neither of you show the code that connects the timer to the file, it is impossible to say why it happens, or not, as the case might be.

    http://presentationmode.blogspot.com/
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    • Marked as answer by Drago91 Sunday, June 22, 2008 12:25 PM
    Saturday, June 21, 2008 10:11 PM
  • Thank you both for your answers. 
     The timer seems to be working fine (I was already using GC.KeepAlive(timer), but after the UnhookWindowsHookEx(_hookID); line).
    Read this sentence slowly, please....: I am using some other objects in the OnTimedEvent method that are declared in the class in which the OnTimedEvent method is. 
    The objects are used only once in the OnTimedEvent, but the next time the timer is elapsed, the objects "disappear". I think I must use GC.KeepAlive() for those objects too...
    Anyway, I've declared my objects in the OnTimedEvent and everything is OK.

    I'm marking Mr Karlsen's reply as an answer, because I've used his advice and because the problems were somewhere else in the code, as he suggested.

    Nicholas
    Sunday, June 22, 2008 12:24 PM
  •  As for AlexBB, I don't really understand what you mean by a typical problem with timers.

    I mean that frequently it is difficult to make the timers work consistently. I cannot really give any code. For one thing I had to get rid of those implementations that did not work, the ones that left are very convoluted: the timer is in one class, the OnTick or Elapsed event in another, it is a mess. It seems to be working or maybe not, I am in the hiatus on that part. I am busy with other things and eventually will return to the problem later.
    AlexB
    Sunday, June 22, 2008 2:07 PM
  • AlexBB said:

     As for AlexBB, I don't really understand what you mean by a typical problem with timers.

    I mean that frequently it is difficult to make the timers work consistently. I cannot really give any code. For one thing I had to get rid of those implementations that did not work, the ones that left are very convoluted: the timer is in one class, the OnTick or Elapsed event in another, it is a mess. It seems to be working or maybe not, I am in the hiatus on that part. I am busy with other things and eventually will return to the problem later.


    AlexB



    I had the same problem...timer in one class the Elapsed in another... After hours of debugging, googling, reading forums, debugging again I've found the problem... that GC.KeepAlive(); instruction...
    Sunday, June 22, 2008 5:03 PM