1

I am developing a window application c# .net. That application is used to connect other machine(window machine) with remote desktop connection and monitor the what user did on that remote machine.

To monitor the user actions, I installed the custom hook procedures for WH_KEYBOARD_LL and WH_MOUSE_LL hooks as global hook procedure using SetWindowsHookEx() method at the time of connecting to remote machine.

When user log off from the remote machine, I need to release hook procedures using UnhookWindowsHookEx(). Problem occurs here by showing message : "フック ハンドルが無効です" (which means Invalid hook handle).

This error does not happen always. It happened sometimes.

I am beginner to c# .net development. I have no idea with this error.

So, I would like to know why that error occurs when UnhookWindowsHookEx() is called.

Please, anybody help me.

My code are:

try
{
  HookManager.KeyDown -= HookManager_KeyDown;
  HookManager.KeyUp -= HookManager_KeyUp;
  HookManager.MouseUp -= HookManager_MouseUp;
}
catch (Exception ex)
{
  // error is written to log file if uninstalling hook procedure is failed
  LogController.Instance.Fatal(ex.Source + CommonConstants.TAB + ex.Message);
}

.....

The above codes execute following code:

public static partial class HookManager
{
  private static int s_KeyboardHookHandle;

  private static event KeyEventHandler s_KeyDown;

  public static event KeyEventHandler KeyDown
  {
       add
       {
           EnsureSubscribedToGlobalKeyboardEvents();
           s_KeyDown += value;
       }
       remove
       {
           s_KeyDown -= value;
           TryUnsubscribeFromGlobalKeyboardEvents();
       }
   }

   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
            s_KeyboardHookHandle = SetWindowsHookEx(
                WH_KEYBOARD_LL,
                s_KeyboardDelegate,
                Marshal.GetHINSTANCE(
                    Assembly.GetExecutingAssembly().GetModules()[0]),
                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);
            }
        }
    }

 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);
    }
  • We've no idea where you got `s_KeyboardHookHandle` from – David Heffernan Feb 03 '14 at 09:53
  • FWIW, your error handling code can be simply `throw new Win32Exception()` which will call `Marshal.GetLastWin32Error()` for you – David Heffernan Feb 03 '14 at 09:54
  • Thank David, I have modified source in my post to show where KeyboardHookHandle comes from. Please take a look for me. Thank you again. – Kyaw Zin Htoo Naing Feb 03 '14 at 10:57
  • This code was written for an old version of .NET, it will no longer work reliably on .NET 4.0 and higher. Marshal.GetHINSTANCE() doesn't do what you hope it does. Which gives you a simple workaround, just target .NET 3.5. Or use GetModuleHandle("user32.dll") as a fix. – Hans Passant Feb 03 '14 at 11:44
  • possible duplicate of [Global mouse event handler](http://stackoverflow.com/questions/11607133/global-mouse-event-handler) – Hans Passant Feb 03 '14 at 11:46
  • @KyawZinHtooNaing Do you get some solution to your problem if yes then please share. – Khan Engineer Feb 24 '16 at 07:51
  • @HansPassant I got some time Invalid handle at the time of UnhookWindowsHookEx(myHandle) but it thows exception and when ever setting again SetWindowsHookEx there my application crashes due to not successful unhook so I need to have a successful unhook even exception occurs, How Could I do that ? Please Help thanks in Advance – Khan Engineer Feb 24 '16 at 07:53
  • @HansPassant I am using GetModule("kernel32.dll") but getting same problem. – Khan Engineer Feb 24 '16 at 07:54

0 Answers0