0

I found a way to capture the Print Screen button in C#. When pressing Alt + Print Screen a simple messagebox pops up saying the keys have been pressed. But it's unresponsive for a couple of seconds right after. I have no idea why this is happening.

Here's the code I use:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        _hookID = SetHook(_proc);
        Application.Run(new Form1());
        UnhookWindowsHookEx(_hookID);  
    }

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

    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)
        {
            Keys number = (Keys)Marshal.ReadInt32(lParam);
            if (number == Keys.PrintScreen)
            {
                if ((wParam == (IntPtr)260 && Keys.Alt == Control.ModifierKeys && number == Keys.PrintScreen))
                {
                    MessageBox.Show("You pressed alt+ print screen");
                }
            }

        }
        return CallNextHookEx(IntPtr.Zero, 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); 
}

Does anyone have a clue why it's hanging after the messagebox?

Devator
  • 3,686
  • 4
  • 33
  • 52
  • keep a break point here `return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);` and see whats happens..does it wait or not? – PresleyDias Jun 05 '12 at 12:08
  • It waits, yes. It waits for a couple of seconds and then jumps to Visual Studio.. – Devator Jun 05 '12 at 12:13
  • Sounds similar to http://stackoverflow.com/questions/2999013/global-low-level-keyboard-hook-freezing-in-c-sharp-net-3-5 – sgmoore Jun 05 '12 at 12:37
  • try this [lobal-keyboard-hook-slowing-down-computer](http://stackoverflow.com/questions/6891570/global-keyboard-hook-slowing-down-computer) – PresleyDias Jun 05 '12 at 12:38

1 Answers1

1

Windows cannot dispatch the next keyboard message until the hook callback finished executing. Clearly you do not want to use MessageBox.Show(), that blocks the callback. Windows puts up with that for several seconds before it declares your code broken and disables the hook.

Use Debug.Print() instead.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • I need to show another form, which also seems to block it. What would be the best way? Start a new thread which will show the form? – Devator Jun 05 '12 at 13:01
  • Calling a form's Show() method should not be a problem. ShowDialog() *is* a problem, that's a blocking call. Use the BeginInvoke() method to run the code later, don't use threads. – Hans Passant Jun 05 '12 at 13:07