Click here to Skip to main content
15,887,862 members
Articles / Programming Languages / C#

Processing Global Mouse and Keyboard Hooks in C#

Rate me:
Please Sign up or sign in to vote.
4.97/5 (614 votes)
31 Aug 2011CPOL6 min read 17M   218.5K   1K   1.4K
This class allows you to tap keyboard and mouse and/or to detect their activity even when an application runs in the background or does not have any user interface at all.

NEWS

This article was posted in 2004 and updated in 2006 and 2008. During all this time until now I receive a lot of positive feedback and recommendations. There where also many useful contributions which where usually posted as code snippets in forum. Now instead of publishing yet another version on my own I decided to ask you all to actively participate. So please be enthusiastic, feel free to join the project at globalmousekeyhook.codeplex.com

You can help by:
  • Contributing code.
  • Creating issue items requesting additional features or reporting defects.
  • Voting for features and fixes you are interested in.
  • Testing the component in different environments.
  • Writing developer documentation.

This will us also allow to keep this original article up to date.

Thank you all for all your great comments on CodeProject forum and looking forward for your brilliant contributions at globalmousekeyhook.codeplex.com

Introduction

This class allows you to tap keyboard and mouse and/or to detect their activity even when an application runs in the background or does not have any user interface at all. This class raises common .NET events with KeyEventArgs and MouseEventArgs, so you can easily retrieve any information you need.

Background

There are a number of applications that run in the background and detect user inactivity to change their mode. For example, MSN Messenger (or any other messenger). I was going to write such an application, so I searched MSDN and found "exactly" what I needed: 318804 - HOW TO: Set a Windows Hook in Visual C# .NET. This article describes how to tap the mouse movement, but it works only when an application is active. At the end of this article, I found this explanation: "Global hook is not supported in .NET Framework. You cannot implement global hooks in Microsoft .NET Framework...". Anyway, I continued my research and found out that there are exceptions. There are WH_KEYBOARD_LL and WH_MOUSE_LL hooks that can be installed globally. So, I have basically replaced WH_MOUSE with WH_MOUSE_LL in the MSDN example, and it works.

The second step was to extract the information received into a .NET EventArgs and raise the appropriate events.

I found a similar article in CodeProject, under Global System Hooks in .NET by Michael Kennedy, but what I dislike is, there is an unmanaged DLL in C++ that is a main part of this solution. This unmanaged DLL is in C++, and a number of classes make it complicated to integrate it in my own tiny application.

Revisions

This article was posted in 2004 and updated in 2006. During all this time until now I receive a lot of positive feedback and recommendations. There were also a number of technology improvements like .NET Framework 3.5 or Visual Studio 2008. So I have decided to update it once more.

I have refactored and improved the solution, made it more flexible, stable and efficient. But this refactoring also had some drawbacks:

  1. Number of code lines and files has grown.
  2. Backward compatibility to older .NETs is lost.

That's why I attend to leave the old version also to be available for download.

Using the Code [Version 2]

The Simple Way

If you are developing a Windows Forms application and prefer drag & drop programming, there is a component named GlobalEventProvider inside the assembly Gma.UserActivityMonitor.dll. Just drag and drop it to your form and create events using the property editor events tab.

The Alternative Way

Use events provided by the static class HookManager. Note that the sender object in events is always null.

For more usage hints, see the source code of the attached demo application.

Using the Code [Version 1]

To use this class in your application, you need to just create an instance of it and hang on events you would like to process. Hooks are automatically installed when the object is created, but you can stop and start listening using appropriate public methods.

C#
UserActivityHook actHook;
void MainFormLoad(object sender, System.EventArgs e)
{
    actHook= new UserActivityHook(); // crate an instance

    // hang on events

    actHook.OnMouseActivity+=new MouseEventHandler(MouseMoved);
    actHook.KeyDown+=new KeyEventHandler(MyKeyDown);
    actHook.KeyPress+=new KeyPressEventHandler(MyKeyPress);
    actHook.KeyUp+=new KeyEventHandler(MyKeyUp);
}

Now, an example of how to process an event:

C#
public void MouseMoved(object sender, MouseEventArgs e)
{
    labelMousePosition.Text=String.Format("x={0}  y={1}", e.X, e.Y);
    if (e.Clicks>0) LogWrite("MouseButton     - " + e.Button.ToString());
}

Changes and Updates from [Version 0] to [Version 1]

I'd like to thank you all for all the useful comments in the discussion forum. There were a lot of bugs and proposals posted after this article was published on 4th June, 2004. Over and over again came the same topics, and I had to refer to previous posts in the discussion, that is why I have decided to revise the code and publish a FAQ. Here is the list of the most important changes:

  • The project was converted into Visual Studio 2005
  • The problem with upper case characters is solved
  • Mouse wheel information is now included in event arguments
  • Better exception handling
  • Cancellation of keyboard events using the Handled property of event arguments
  • XML documentation of functions

FAQ [Version 1]

Question

The project cannot be run in Visual Studio .NET 2005 in debug mode because of an exception error caused by calling the SetWindowsHookEx. Why? Is it a problem of .NET 2.0?

Answer

The compiled release version works well so that cannot be a .NET 2.0 problem. To workaround, you just need to uncheck the check box in the project properties that says: "Enable Visual Studio hosting process". In the menu: Project -> Project Properties... -> Debug -> Enable the Visual Studio hosting process.

Question

I need to suppress some keystrokes after I have processed them.

Answer

Just set the e.Handled property to true in the key events you have processed. It prevents the keystrokes being processed by other applications.

Question:

Is it possible to convert your global hooks to application hooks which capture keystrokes and mouse movements only within the application?

Answer

Yes. Just use...

C#
private const int WH_MOUSE = 7;
private const int WH_KEYBOARD = 2;

... everywhere, instead of:

C#
private const int WH_MOUSE_LL = 14;
private const int WH_KEYBOARD_LL = 13;

Question

Does it work on Win98 (Windows ME, Windows 95)?

Answer

Yes and No. The global hooks WH_MOUSE_LL and WH_KEYBOARD_LL can be monitored only under Windows NT/2000/XP. In other cases, you can only use application hooks (WH_MOUSE and WH_KEYBOARD) which capture keystrokes and mouse movement only within the application.

Question

I have a long delay when closing applications using hooks by clicking the x button in the titlebar. If I close the application via another event (button click) for example, that works fine.

Answer

It's a known bug of Microsoft. It has to do with the Windows themes. If you disable the Windows themes, the problem goes away. Another choice is to have the hook code run in a secondary thread.

Question

How do I catch key combinations like Ctrl+Shift+A?

Answer

You'll have to track which keys have gone down but not up. Only the most recently pressed key keeps sending KeyDown messages, but the others will still send a KeyUp when released. So if you make three flags IsCtrlDown, IsShiftDown, and IsADown, and set them to true at KeyDown and false at KeyUp, the expression (IsCtrlDown && IsShiftDown && IsADown) will give you the required result.

Question

Does it works with .NET Framework 1.1 and Visual Studio 2003?

Answer

Yes. The file UserActivityHook.cs can be used without any changes, in a Visual Studio 2003 .NET 1.1 project.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Germany Germany
Tweeter: @gmamaladze
Google+: gmamaladze
Blog: gmamaladze.wordpress.com

Comments and Discussions

 
Questionit is not working for me Pin
Member 1206694920-Mar-17 19:22
Member 1206694920-Mar-17 19:22 
AnswerRe: it is not working for me Pin
Member 1419396028-Mar-19 20:37
Member 1419396028-Mar-19 20:37 
GeneralMy vote of 1 Pin
Christopher Aicher9-Mar-17 7:51
Christopher Aicher9-Mar-17 7:51 
QuestionService and Processing Global House Pin
Member 1071964123-Dec-16 3:40
Member 1071964123-Dec-16 3:40 
QuestionWorking Great But.. I'm looking for XButtons as well Pin
NotNiceCream22-Dec-16 19:58
NotNiceCream22-Dec-16 19:58 
QuestionMouse freezes (location) when closing/opening program.. Pin
DeadSix1718-Nov-16 7:14
DeadSix1718-Nov-16 7:14 
QuestionReceiving Error Pin
K. Mirzavaziri6-Sep-16 18:27
professionalK. Mirzavaziri6-Sep-16 18:27 
AnswerRe: Receiving Error Pin
Daniel Liedke28-Oct-16 6:52
professionalDaniel Liedke28-Oct-16 6:52 
Hello, the following article helped me to fix the issue:

http://stackoverflow.com/questions/17897646/gma-useractivitymonitor-setwindowshookex-error-126

So this is the updated
C#
GlobalHook\HookManager.Callbacks.cs
file that works for me:

C#
using System;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Gma.UserActivityMonitor
{
    public static partial class HookManager
    {
        [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
        static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);

        /// <summary>
        /// The CallWndProc hook procedure is an application-defined or library-defined callback 
        /// function used with the SetWindowsHookEx function. The HOOKPROC type defines a pointer 
        /// to this callback function. CallWndProc is a placeholder for the application-defined 
        /// or library-defined function name.
        /// </summary>
        /// <param name="nCode">
        /// [in] Specifies whether the hook procedure must process the message. 
        /// If nCode is HC_ACTION, the hook procedure must process the message. 
        /// If nCode is less than zero, the hook procedure must pass the message to the 
        /// CallNextHookEx function without further processing and must return the 
        /// value returned by CallNextHookEx.
        /// </param>
        /// <param name="wParam">
        /// [in] Specifies whether the message was sent by the current thread. 
        /// If the message was sent by the current thread, it is nonzero; otherwise, it is zero. 
        /// </param>
        /// <param name="lParam">
        /// [in] Pointer to a CWPSTRUCT structure that contains details about the message. 
        /// </param>
        /// <returns>
        /// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. 
        /// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx 
        /// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC 
        /// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook 
        /// procedure does not call CallNextHookEx, the return value should be zero. 
        /// </returns>
        /// <remarks>
        /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/callwndproc.asp
        /// </remarks>
        private delegate int HookProc(int nCode, int wParam, IntPtr lParam);

        //##############################################################################
        #region Mouse hook processing

        /// <summary>
        /// This field is not objectively needed but we need to keep a reference on a delegate which will be 
        /// passed to unmanaged code. To avoid GC to clean it up.
        /// When passing delegates to unmanaged code, they must be kept alive by the managed application 
        /// until it is guaranteed that they will never be called.
        /// </summary>
        private static HookProc s_MouseDelegate;

        /// <summary>
        /// Stores the handle to the mouse hook procedure.
        /// </summary>
        private static int s_MouseHookHandle;

        private static int m_OldX;
        private static int m_OldY;

        /// <summary>
        /// A callback function which will be called every Time a mouse activity detected.
        /// </summary>
        /// <param name="nCode">
        /// [in] Specifies whether the hook procedure must process the message. 
        /// If nCode is HC_ACTION, the hook procedure must process the message. 
        /// If nCode is less than zero, the hook procedure must pass the message to the 
        /// CallNextHookEx function without further processing and must return the 
        /// value returned by CallNextHookEx.
        /// </param>
        /// <param name="wParam">
        /// [in] Specifies whether the message was sent by the current thread. 
        /// If the message was sent by the current thread, it is nonzero; otherwise, it is zero. 
        /// </param>
        /// <param name="lParam">
        /// [in] Pointer to a CWPSTRUCT structure that contains details about the message. 
        /// </param>
        /// <returns>
        /// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. 
        /// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx 
        /// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC 
        /// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook 
        /// procedure does not call CallNextHookEx, the return value should be zero. 
        /// </returns>
        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));

                //detect button clicked
                MouseButtons button = MouseButtons.None;
                short mouseDelta = 0;
                int clickCount = 0;
                bool mouseDown = false;
                bool mouseUp = false;

                switch (wParam)
                {
                    case WM_LBUTTONDOWN:
                        mouseDown = true;
                        button = MouseButtons.Left;
                        clickCount = 1;
                        break;
                    case WM_LBUTTONUP:
                        mouseUp = true;
                        button = MouseButtons.Left;
                        clickCount = 1;
                        break;
                    case WM_LBUTTONDBLCLK: 
                        button = MouseButtons.Left;
                        clickCount = 2;
                        break;
                    case WM_RBUTTONDOWN:
                        mouseDown = true;
                        button = MouseButtons.Right;
                        clickCount = 1;
                        break;
                    case WM_RBUTTONUP:
                        mouseUp = true;
                        button = MouseButtons.Right;
                        clickCount = 1;
                        break;
                    case WM_RBUTTONDBLCLK: 
                        button = MouseButtons.Right;
                        clickCount = 2;
                        break;
                    case WM_MOUSEWHEEL:
                        //If the message is WM_MOUSEWHEEL, the high-order word of MouseData member is the wheel delta. 
                        //One wheel click is defined as WHEEL_DELTA, which is 120. 
                        //(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value
                        mouseDelta = (short)((mouseHookStruct.MouseData >> 16) & 0xffff);
                       
                    //TODO: X BUTTONS (I havent them so was unable to test)
                        //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, 
                        //or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released, 
                        //and the low-order word is reserved. This value can be one or more of the following values. 
                        //Otherwise, MouseData is not used. 
                        break;
                }

                //generate event 
                MouseEventExtArgs e = new MouseEventExtArgs(
                                                   button,
                                                   clickCount,
                                                   mouseHookStruct.Point.X,
                                                   mouseHookStruct.Point.Y,
                                                   mouseDelta);

                //Mouse up
                if (s_MouseUp!=null && mouseUp)
                {
                    s_MouseUp.Invoke(null, e);
                }

                //Mouse down
                if (s_MouseDown != null && mouseDown)
                {
                    s_MouseDown.Invoke(null, e);
                }

                //If someone listens to click and a click is heppened
                if (s_MouseClick != null && clickCount>0)
                {
                    s_MouseClick.Invoke(null, e);
                }

                //If someone listens to click and a click is heppened
                if (s_MouseClickExt != null && clickCount > 0)
                {
                    s_MouseClickExt.Invoke(null, e);
                }

                //If someone listens to double click and a click is heppened
                if (s_MouseDoubleClick != null && clickCount == 2)
                {
                    s_MouseDoubleClick.Invoke(null, e);
                }

                //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 ((s_MouseMove!=null || s_MouseMoveExt!=null) && (m_OldX != mouseHookStruct.Point.X || m_OldY != mouseHookStruct.Point.Y))
                {
                    m_OldX = mouseHookStruct.Point.X;
                    m_OldY = mouseHookStruct.Point.Y;
                    if (s_MouseMove != null)
                    {
                        s_MouseMove.Invoke(null, e);
                    }

                    if (s_MouseMoveExt != null)
                    {
                        s_MouseMoveExt.Invoke(null, e);
                    }
                }

                if (e.Handled)
                {
                    return -1;
                }
            }

            //call next hook
            return CallNextHookEx(s_MouseHookHandle, nCode, wParam, lParam);
        }

        private static void EnsureSubscribedToGlobalMouseEvents()
        {
            // install Mouse hook only if it is not installed and must be installed
            if (s_MouseHookHandle == 0)
            {
                //See comment of this field. To avoid GC to clean it up.
                s_MouseDelegate = MouseHookProc;
                //install hook
                var mar = LoadLibrary("user32.dll");
                s_MouseHookHandle = SetWindowsHookEx(
                    WH_MOUSE_LL,
                    s_MouseDelegate,
                   mar,
                    0);
                //If SetWindowsHookEx fails.
                if (s_MouseHookHandle == 0)
                {
                    //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
                    int errorCode = Marshal.GetLastWin32Error();
                    //do cleanup

                    //Initializes and throws a new instance of the Win32Exception class with the specified error. 
                    throw new Win32Exception(errorCode);
                }
            }
        }

        private static void TryUnsubscribeFromGlobalMouseEvents()
        {
            //if no subsribers are registered unsubsribe from hook
            if (s_MouseClick == null &&
                s_MouseDown == null &&
                s_MouseMove == null &&
                s_MouseUp == null &&
                s_MouseClickExt == null &&
                s_MouseMoveExt == null &&
                s_MouseWheel == null)
            {
                ForceUnsunscribeFromGlobalMouseEvents();
            }
        }

        private static void ForceUnsunscribeFromGlobalMouseEvents()
        {
            if (s_MouseHookHandle != 0)
            {
                //uninstall hook
                int result = UnhookWindowsHookEx(s_MouseHookHandle);
                //reset invalid handle
                s_MouseHookHandle = 0;
                //Free up for GC
                s_MouseDelegate = null;
                //if failed and exception must be thrown
                if (result == 0)
                {
                    //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
                    int errorCode = Marshal.GetLastWin32Error();
                    //Initializes and throws a new instance of the Win32Exception class with the specified error. 
                    throw new Win32Exception(errorCode);
                }
            }
        }
        
        #endregion

        //##############################################################################
        #region Keyboard hook processing

        /// <summary>
        /// This field is not objectively needed but we need to keep a reference on a delegate which will be 
        /// passed to unmanaged code. To avoid GC to clean it up.
        /// When passing delegates to unmanaged code, they must be kept alive by the managed application 
        /// until it is guaranteed that they will never be called.
        /// </summary>
        private static HookProc s_KeyboardDelegate;

        /// <summary>
        /// Stores the handle to the Keyboard hook procedure.
        /// </summary>
        private static int s_KeyboardHookHandle;

        /// <summary>
        /// A callback function which will be called every Time a keyboard activity detected.
        /// </summary>
        /// <param name="nCode">
        /// [in] Specifies whether the hook procedure must process the message. 
        /// If nCode is HC_ACTION, the hook procedure must process the message. 
        /// If nCode is less than zero, the hook procedure must pass the message to the 
        /// CallNextHookEx function without further processing and must return the 
        /// value returned by CallNextHookEx.
        /// </param>
        /// <param name="wParam">
        /// [in] Specifies whether the message was sent by the current thread. 
        /// If the message was sent by the current thread, it is nonzero; otherwise, it is zero. 
        /// </param>
        /// <param name="lParam">
        /// [in] Pointer to a CWPSTRUCT structure that contains details about the message. 
        /// </param>
        /// <returns>
        /// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. 
        /// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx 
        /// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC 
        /// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook 
        /// procedure does not call CallNextHookEx, the return value should be zero. 
        /// </returns>
        private static int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            //indicates if any of underlaing events set e.Handled flag
            bool handled = false;

            if (nCode >= 0)
            {
                //read structure KeyboardHookStruct at lParam
                KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
                //raise KeyDown
                if (s_KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
                {
                    Keys keyData = (Keys)MyKeyboardHookStruct.VirtualKeyCode;
                    KeyEventArgs e = new KeyEventArgs(keyData);
                    s_KeyDown.Invoke(null, e);
                    handled = e.Handled;
                }

                // raise KeyPress
                if (s_KeyPress != null && wParam == WM_KEYDOWN)
                {
                    bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);
                    bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);

                    byte[] keyState = new byte[256];
                    GetKeyboardState(keyState);
                    byte[] inBuffer = new byte[2];
                    if (ToAscii(MyKeyboardHookStruct.VirtualKeyCode,
                              MyKeyboardHookStruct.ScanCode,
                              keyState,
                              inBuffer,
                              MyKeyboardHookStruct.Flags) == 1)
                    {
                        char key = (char)inBuffer[0];
                        if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
                        KeyPressEventArgs e = new KeyPressEventArgs(key);
                        s_KeyPress.Invoke(null, e);
                        handled = handled || e.Handled;
                    }
                }

                // raise KeyUp
                if (s_KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
                {
                    Keys keyData = (Keys)MyKeyboardHookStruct.VirtualKeyCode;
                    KeyEventArgs e = new KeyEventArgs(keyData);
                    s_KeyUp.Invoke(null, e);
                    handled = handled || e.Handled;
                }

            }

            //if event handled in application do not handoff to other listeners
            if (handled)
                return -1;

            //forward to other application
            return CallNextHookEx(s_KeyboardHookHandle, nCode, wParam, lParam);
        }

        private static void EnsureSubscribedToGlobalKeyboardEvents()
        {
            // install Keyboard hook only if it is not installed and must be installed
            if (s_KeyboardHookHandle == 0)
            {
                //See comment of this field. To avoid GC to clean it up.
                s_KeyboardDelegate = KeyboardHookProc;
                //install hook
                var mar = LoadLibrary("user32.dll");
                s_KeyboardHookHandle = SetWindowsHookEx(
                    WH_KEYBOARD_LL,
                    s_KeyboardDelegate,
                    mar,
                    0);
                //If SetWindowsHookEx fails.
                if (s_KeyboardHookHandle == 0)
                {
                    //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
                    int errorCode = Marshal.GetLastWin32Error();
                    //do cleanup

                    //Initializes and throws a new instance of the Win32Exception class with the specified error. 
                    throw new Win32Exception(errorCode);
                }
            }
        }

        private static void TryUnsubscribeFromGlobalKeyboardEvents()
        {
            //if no subsribers are registered unsubsribe from hook
            if (s_KeyDown == null &&
                s_KeyUp == null &&
                s_KeyPress == null)
            {
                ForceUnsunscribeFromGlobalKeyboardEvents();
            }
        }

        private static void ForceUnsunscribeFromGlobalKeyboardEvents()
        {
            if (s_KeyboardHookHandle != 0)
            {
                //uninstall hook
                int result = UnhookWindowsHookEx(s_KeyboardHookHandle);
                //reset invalid handle
                s_KeyboardHookHandle = 0;
                //Free up for GC
                s_KeyboardDelegate = null;
                //if failed and exception must be thrown
                if (result == 0)
                {
                    //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
                    int errorCode = Marshal.GetLastWin32Error();
                    //Initializes and throws a new instance of the Win32Exception class with the specified error. 
                    throw new Win32Exception(errorCode);
                }
            }
        }

        #endregion

    }
}

GeneralRe: Receiving Error Pin
giova27-Jan-17 19:07
giova27-Jan-17 19:07 
GeneralRe: Receiving Error Pin
Jeff Bowman30-Mar-17 14:41
professionalJeff Bowman30-Mar-17 14:41 
GeneralRe: Receiving Error Pin
Member 1331948420-Jul-17 0:32
Member 1331948420-Jul-17 0:32 
QuestionSet cursor position through hook Pin
Hunter Hsieh5-Sep-16 23:01
Hunter Hsieh5-Sep-16 23:01 
QuestionWon'twork if called from 4.0 Pin
corlleonedonss30-Aug-16 6:30
corlleonedonss30-Aug-16 6:30 
AnswerRe: Won'twork if called from 4.0 Pin
corlleonedonss30-Aug-16 6:31
corlleonedonss30-Aug-16 6:31 
GeneralRe: Won'twork if called from 4.0 Pin
Daniel Liedke28-Oct-16 7:05
professionalDaniel Liedke28-Oct-16 7:05 
GeneralRe: Won'twork if called from 4.0 Pin
fvl28-May-18 7:09
fvl28-May-18 7:09 
GeneralRe: Won'twork if called from 4.0 Pin
Roink29-May-18 4:06
professionalRoink29-May-18 4:06 
QuestionVery helpful Pin
Member 1228191617-Aug-16 0:44
Member 1228191617-Aug-16 0:44 
PraiseSweet!! It actually builds!! Pin
MainFrameMan_ALIVE_AND_WELL$$16-Aug-16 11:34
MainFrameMan_ALIVE_AND_WELL$$16-Aug-16 11:34 
QuestionDon't we require a .exe and .dll, two projects? Pin
IndianGuru4-Jul-16 20:06
IndianGuru4-Jul-16 20:06 
QuestionCount the key and mouse events globally Pin
Saurabh Solanki28-Jun-16 3:35
Saurabh Solanki28-Jun-16 3:35 
QuestionMouse click released? Pin
Member 1258896016-Jun-16 23:15
Member 1258896016-Jun-16 23:15 
QuestionGlobal Keyboard Hook - Enable selection of keys Pin
Member 31357079-Jun-16 22:54
Member 31357079-Jun-16 22:54 
QuestionGetting notifications on separate thread Pin
Member 443327426-May-16 11:18
Member 443327426-May-16 11:18 
AnswerRe: Getting notifications on separate thread Pin
Member 443327426-May-16 12:17
Member 443327426-May-16 12:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.