前言:最近在写一个桌面程序时需要全局HOOK 窗体的创建,但是在.net中SetWindowsHookEx()只可实现键盘鼠标的全局钩子,其余的全局钩子都需要使用DLL。难道就没有解决办法了么?经过长时间的搜索后在CSDN的一篇帖子中,有大神提到了RegisterShellHookWindow()这个方法。但是又经过一番搜索后,发现基本上是C++或者其他语言的使用分享。所以写下了这篇文章,给后来的人提供快速解决的途径。

在WinForm中使用RegisterShellHook

1.准备工作

        ......
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool RegisterShellHookWindow(IntPtr hWnd);
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern uint RegisterWindowMessage(string Message);
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool DeregisterShellHookWindow(IntPtr hHandle);
        ......
        uint WM_ShellHook;
        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_SYSMENU = 9,
            HSHELL_ENDTASK = 10,
            HSHELL_ACCESSIBILITYSTATE = 11,
            HSHELL_APPCOMMAND = 12,
            HSHELL_WINDOWREPLACED = 13,
            HSHELL_WINDOWREPLACING = 14,
            HSHELL_HIGHBIT = 0x8000,
            HSHELL_FLASH = (HSHELL_REDRAW | HSHELL_HIGHBIT),
            HSHELL_RUDEAPPACTIVATED = (HSHELL_WINDOWACTIVATED | HSHELL_HIGHBIT)
        }

2.注册钩子

  • 注意事项:不要在构造函数中注册钩子,此时窗体的handle未被创建。
        private void Form1_Load(object sender, EventArgs e)
        {
            if (RegisterShellHookWindow(this.Handle)) {
                WM_ShellHook = RegisterWindowMessage("SHELLHOOK");
            }
        }

3.处理消息

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_ShellHook)
            {
                switch ((ShellEvents)m.WParam)
                {
                    case ShellEvents.HSHELL_WINDOWCREATED:
                        Console.WriteLine("窗体创建");
                        break;
                    default:
                        break;
                }
            }
            base.WndProc(ref m);
        }

4.卸载钩子

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            DeregisterShellHookWindow(this.Handle);
        }

在WPF中使用RegisterShellHook

  • WPF较为特殊,handle不能直接取得,WndProc方法不能直接重写。

1.准备工作

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool RegisterShellHookWindow(IntPtr hWnd);
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern uint RegisterWindowMessage(string Message);
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool DeregisterShellHookWindow(IntPtr hHandle);
        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_SYSMENU = 9,
            HSHELL_ENDTASK = 10,
            HSHELL_ACCESSIBILITYSTATE = 11,
            HSHELL_APPCOMMAND = 12,
            HSHELL_WINDOWREPLACED = 13,
            HSHELL_WINDOWREPLACING = 14,
            HSHELL_HIGHBIT = 0x8000,
            HSHELL_FLASH = (HSHELL_REDRAW | HSHELL_HIGHBIT),
            HSHELL_RUDEAPPACTIVATED = (HSHELL_WINDOWACTIVATED | HSHELL_HIGHBIT)
        }
        uint WM_ShellHook;

2.注册钩子

        private IntPtr handle;
        public MainWindow()
        {
            InitializeComponent();
            this.SourceInitialized += new EventHandler(Win_SourceInitialized);
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            handle = new WindowInteropHelper(this).Handle;
            if (RegisterShellHookWindow(handle))
            {
                WM_ShellHook = RegisterWindowMessage("SHELLHOOK");
            }
        }
        private void Win_SourceInitialized(object sender, EventArgs e)
        {
            HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
            if (source != null) source.AddHook(WndProc);
        }

3.处理消息

        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == WM_ShellHook) {
                switch ((ShellEvents)wParam)
                {
                    case ShellEvents.HSHELL_WINDOWCREATED:
                        Console.WriteLine("窗体被创建");
                        break;
                }
            }
            return IntPtr.Zero;
        }

4.卸载钩子

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            DeregisterShellHookWindow(handle);
        }

到这里就结束了