Глобальный хук клавиатуры работает, но глобальный хук оболочки не работает - PullRequest
1 голос
/ 20 октября 2011

У меня есть две части кода, которые очень похожи в том, что они регистрируют глобальные хуки.

Регистрация глобальной клавиатуры:

public class KeyboardHook : IDisposable
{
    #region Events
    private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
    public delegate void HookEventHandler(object sender, KeyboardHookEventArgs e);
    public event HookEventHandler KeyDown;
    public event HookEventHandler KeyUp;
    #endregion

    #region Constants
    private const int WH_KEYBOARD_LL = 13;
    private const int WM_KEYDOWN = 0x0100;
    private const int WM_SYSKEYDOWN = 0x0104;
    private LowLevelKeyboardProc _proc = null;
    private static IntPtr _hookID = IntPtr.Zero;
    #endregion

    #region Imports
    [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);

    #endregion

    #region Constructor
    public KeyboardHook()
    {
        _proc = new LowLevelKeyboardProc(HookCallback); 
        _hookID = SetHook(_proc);
    }

    #endregion


    #region Methods
    private 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 IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        //if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
        if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN))
        {
            int vkCode = Marshal.ReadInt32(lParam);
            WinForms.Keys key = (WinForms.Keys)vkCode;
            if (this.KeyDown != null)
                this.KeyDown(this, new KeyboardHookEventArgs(vkCode));
        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }

    #endregion

    #region Destructor
    public void Dispose()
    {
        UnhookWindowsHookEx(_hookID);
    }
    #endregion
}

Регистрация глобальной оболочки:

    public enum ShellEvents
    {
        HSHELL_WINDOWCREATED = 1,
        HSHELL_WINDOWDESTROYED = 2,
        HSHELL_ACTIVATESHELLWINDOW = 3,
        HSHELL_WINDOWACTIVATED = 4,
        HSHELL_GETMINRECT = 5,
        HSHELL_REDRAW = 6,
        HSHELL_TASKMAN = 7,
        HSHELL_LANGUAGE = 8,
        HSHELL_ACCESSIBILITYSTATE = 11
    }

    public class ShellHook
    {
        #region Events
        private delegate IntPtr ShellProc(int nCode, IntPtr wParam, IntPtr lParam);
        public delegate void HookEventHandler(object sender, ShellHookEventArgs e);
        public event HookEventHandler WindowActivated;
        #endregion

        #region Constants
        private const int WH_SHELL = 10;
        private ShellProc _proc = null;
        private static IntPtr _hookID = IntPtr.Zero;
        #endregion

        #region Imports
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
            ShellProc 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);

        [DllImport("user32.dll")]
        static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
        #endregion

        #region Fields
        #endregion

        #region Constructor
        public ShellHook()
        {
            _proc = new ShellProc(HookCallback); 
            _hookID = SetHook(_proc);
        }
        #endregion

        #region Methods
        private IntPtr SetHook(ShellProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_SHELL, proc,
                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam.Equals(ShellEvents.HSHELL_WINDOWACTIVATED))
            {
                string windowTitle = GetWindowTitle(wParam);
                if (this.WindowActivated != null)
                    this.WindowActivated(this, new ShellHookEventArgs(windowTitle));
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

        private string GetWindowTitle(IntPtr hWnd)
        {
            const int nChars = 256;
            StringBuilder Buff = new StringBuilder(nChars);

            if (GetWindowText(hWnd, Buff, nChars) > 0)
            {
                return Buff.ToString();
            }
            return null;
        }
        #endregion

        #region Destructor
        public void Dispose()
        {
            UnhookWindowsHookEx(_hookID);
        }
        #endregion
    }

По какой-то причине перехват клавиатуры работает, но перехват оболочки не выполняется (SetWindowsHookEx возвращает 0 и обратный вызов не достигается).

Есть идеи, почему?

1 Ответ

2 голосов
/ 20 октября 2011

Думаю, я отвечу на свой вопрос.Эта цитата из pinvoke.net объясняет, почему ...

Однако вы не можете реализовать глобальные перехватчики в Microsoft .NET Framework, кроме перехватчиков низкого уровня.Чтобы установить глобальный хук, у хука должен быть собственный экспорт библиотеки динамических ссылок (DLL), чтобы внедрить себя в другой процесс, для которого требуется допустимая, согласованная функция для вызова.Это требует экспорта DLL, который .NET Framework не поддерживает.Управляемый код не имеет понятия согласованного значения для указателя функции, поскольку эти указатели на функции являются прокси, которые создаются динамически.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...