Click here to Skip to main content
12,251,293 members (43,193 online)
Click here to Skip to main content

Stats

226.5K views
7.6K downloads
219 bookmarked
Posted

Global Windows Hooks

, 24 Sep 2010 CPOL
A single component that contains various Windows hooks
Library Files
WindowsHookLib.dll
Source Code and Demo
WindowsHookDemo
WindowsHookDemo.suo
WindowsHookDemo
bin
Debug
WindowsHookDemo.exe
WindowsHookDemo.vshost.exe
WindowsHookLib.dll
Release
My Project
Application.myapp
WindowsHookDemo.vbproj.user
WindowsHookLib
WindowsHookLib.suo
WindowsHookLib
bin
Release
x86
Release
WindowsHookLib.dll
WindowsHookLib.dll.lastcodeanalysissucceeded
WindowsHookLib.pdb
Properties
Resources
clipboard.ico
keyboard.ico
mouse.ico
Thumbs.db
WindowsHookLib Component
WindowsHookLib.dll
// Author: Arman Ghazanchyan
// Created: 01/11/2008
// Modified: 09/14/2010

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Forms;
using System.Reflection;
using System.Drawing;

[assembly: CLSCompliant(true)]

namespace WindowsHookLib
{
    /// <summary>
    /// Provides functionality to hook a window to the clipboard chain.
    /// </summary>
    [DebuggerNonUserCode]
    [DefaultEvent("ClipboardChanged"), ToolboxBitmap(typeof(ClipboardHook), "Resources.clipboard"),
    Description("Component that hooks a window to the clipboard chain and raises some useful events.")]
    public partial class ClipboardHook : Component
    {
        #region ' Event Handlers and Delegates '

        /// <summary>
        /// Occurs when the ClipboardHook state changed.
        /// </summary>
        [System.ComponentModel.Description("Occurs when the ClipboardHook state changed.")]
        public event System.EventHandler<StateChangedEventArgs> StateChanged;
        /// <summary>
        /// Occurs when the clipboard contents is changed.
        /// </summary>
        [System.ComponentModel.Description("Occurs when the clipboard contents is changed.")]
        public event System.EventHandler<ClipboardEventArgs> ClipboardChanged;

        #endregion

        #region ' Members '

        //Clipboard NativeWindow
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private ClipboardHook.ClipboardPorc _clipboardProc;

        #endregion

        #region ' Properties '

        /// <summary>
        /// Gets the component's assembly information.
        /// </summary>
        public static Assembly AssemblyInfo
        {
            get
            {
                return Assembly.GetExecutingAssembly();
            }
        }

        /// <summary>
        /// Gets the state of the hook.
        /// </summary>
        public HookState State
        {
            get
            {
                if (this._clipboardProc != null && this._clipboardProc.Handle != IntPtr.Zero)
                    return HookState.Installed;
                else
                    return HookState.Uninstalled;
            }
        }

        /// <summary>
        /// Gets the hooked window handle.
        /// </summary>
        public IntPtr HookedWindow
        {
            get
            {
                return this._clipboardProc.Handle;
            }
        }

        #endregion

        #region ' Methods '

        /// <summary>
        /// Default constructor.
        /// </summary>
        public ClipboardHook()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Installs the clipboard hook for a window.
        /// </summary>
        /// <param name="window">
        /// A valid window (Form) within the solution associated with the ClipboardHook.
        /// </param>
        public void InstallHook(Form window)
        {
            if (this.State == HookState.Uninstalled)
            {
                if (window != null)
                {
                    UnsafeNativeMethods.SetLastError(0);
                    IntPtr nextWind = UnsafeNativeMethods.SetClipboardViewer(window.Handle);
                    if (nextWind == IntPtr.Zero)
                    {
                        UInt32 eCode = UnsafeNativeMethods.GetLastError();
                        if (eCode != 0)
                        {
                            // Failed to hook. Throw a HookException
                            throw new WindowsHookException(new Win32Exception((int)eCode).Message);
                        }
                        else
                        {
                            this._clipboardProc = new ClipboardPorc(nextWind);
                            this._clipboardProc.WindowClosing += new EventHandler(_clipboardProc_WindowClosing);
                            this._clipboardProc.HandleChanged += new EventHandler(_clipboardProc_HandleChanged);
                            this._clipboardProc.ClipboardChanged += new EventHandler<ClipboardEventArgs>(_clipboardProc_ClipboardChanged);
                            this._clipboardProc.AssignHandle(window.Handle);
                        }
                    }
                    else
                    {
                        this._clipboardProc = new ClipboardPorc(nextWind);
                        this._clipboardProc.WindowClosing += new EventHandler(_clipboardProc_WindowClosing);
                        this._clipboardProc.HandleChanged += new EventHandler(_clipboardProc_HandleChanged);
                        this._clipboardProc.ClipboardChanged += new EventHandler<ClipboardEventArgs>(_clipboardProc_ClipboardChanged);
                        this._clipboardProc.AssignHandle(window.Handle);
                    }
                }
                else
                    throw new WindowsHookException("The argument cannot be Null (Nothing in VB).", "window");
            }
        }

        /// <summary>
        /// Removes the clipboard hook for this window.
        /// </summary>
        public void RemoveHook()
        {
            if (this.State == HookState.Installed)
            {
                UnsafeNativeMethods.SetLastError(0);
                UnsafeNativeMethods.ChangeClipboardChain(this._clipboardProc.Handle, this._clipboardProc.NextWindow);
                UInt32 eCode = UnsafeNativeMethods.GetLastError();
                if (eCode != 0)
                {
                    // Failed to hook. Throw a HookException
                    throw new WindowsHookException(new Win32Exception((int)eCode).Message);
                }
                else
                {
                    this._clipboardProc.ReleaseHandle();
                    this._clipboardProc.WindowClosing -= new EventHandler(_clipboardProc_WindowClosing);
                    this._clipboardProc.HandleChanged -= new EventHandler(_clipboardProc_HandleChanged);
                    this._clipboardProc.ClipboardChanged -= new EventHandler<ClipboardEventArgs>(_clipboardProc_ClipboardChanged);
                    this._clipboardProc = null;
                }
            }
        }

        /// <summary>
        /// Safely removes the hook without throwing exception.
        /// </summary>
        private void SafeRemove()
        {
            if (this.State == HookState.Installed)
            {
                UnsafeNativeMethods.ChangeClipboardChain(this._clipboardProc.Handle, this._clipboardProc.NextWindow);
                this._clipboardProc.ReleaseHandle();
                this._clipboardProc.WindowClosing -= new EventHandler(_clipboardProc_WindowClosing);
                this._clipboardProc.HandleChanged -= new EventHandler(_clipboardProc_HandleChanged);
                this._clipboardProc.ClipboardChanged -= new EventHandler<ClipboardEventArgs>(_clipboardProc_ClipboardChanged);
                this._clipboardProc = null;
            }
        }

        #endregion

        #region ' Events '

        private void _clipboardProc_HandleChanged(object sender, EventArgs e)
        {
            this.OnStateChanged(new StateChangedEventArgs(this.State));
        }

        private void _clipboardProc_ClipboardChanged(object sender, ClipboardEventArgs e)
        {
            this.OnClipboardChanged(e);
        }

        private void _clipboardProc_WindowClosing(object sender, EventArgs e)
        {
            this.SafeRemove();
        }

        #endregion

        #region ' On Event '

        /// <summary>
        /// Raises the WindowsHookLib.ClipboardHook.StateChanged event.
        /// </summary>
        /// <param name="e">A WindowsHookLib.StateChangedEventArgs
        /// that contains the event data.</param>
        protected virtual void OnStateChanged(WindowsHookLib.StateChangedEventArgs e)
        {
            if (StateChanged != null)
                StateChanged(this, e);
        }

        /// <summary>
        /// Raises the WindowsHookLib.ClipboardHook.ClipboardChanged event.
        /// </summary>
        /// <param name="e">A WindowsHookLib.ClipboardEventArgs
        /// that contains the event data.</param>
        protected virtual void OnClipboardChanged(WindowsHookLib.ClipboardEventArgs e)
        {
            if (ClipboardChanged != null)
                ClipboardChanged(this, e);
        }

        #endregion

        #region ' ClipboardPrc Class '

        [DebuggerNonUserCode]
        private class ClipboardPorc : System.Windows.Forms.NativeWindow
        {
            #region ' Event Handlers and Delegates '

            public event EventHandler HandleChanged;
            public event EventHandler WindowClosing;
            public event EventHandler<ClipboardEventArgs> ClipboardChanged;

            #endregion

            #region ' Members '

            //Holds the nex window handler in the clipboard chain
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private IntPtr _nextWind;
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            private const int WM_DESTROY = 0x0002;

            #endregion

            #region ' Properties '

            public IntPtr NextWindow
            {
                get
                {
                    return this._nextWind;
                }
                set
                {
                    this._nextWind = value;
                }
            }

            #endregion

            #region ' Methods '

            public ClipboardPorc(IntPtr nextWind)
            {
                this._nextWind = nextWind;
            }

            protected override void OnHandleChange()
            {
                base.OnHandleChange();
                if (this.Handle == IntPtr.Zero)
                    this._nextWind = IntPtr.Zero;
                if (HandleChanged != null)
                    HandleChanged(this, new System.EventArgs());
            }

            protected override void WndProc(ref Message m)
            {
                switch (m.Msg)
                {
                    case UnsafeNativeMethods.WM_DRAWCLIPBOARD:
                        if (ClipboardChanged != null)
                            ClipboardChanged(this, new ClipboardEventArgs(m.WParam));

                        UnsafeNativeMethods.SendMessage(this._nextWind, (UInt32)m.Msg, m.WParam, m.LParam);
                        break;
                    case UnsafeNativeMethods.WM_CHANGECBCHAIN:
                        if (m.WParam == this._nextWind)
                        {
                            // The window is being removed is the next window on the clipboard chain.
                            // Change the ClipboardHook._nextWind handle with LParam.
                            // There is no need to pass this massage any farther.
                            this._nextWind = m.LParam;
                        }
                        else
                        {
                            UnsafeNativeMethods.SendMessage(this._nextWind, (UInt32)m.Msg, m.WParam, m.LParam);
                        }
                        break;
                    default:
                        if (m.Msg == WM_DESTROY && WindowClosing != null)
                            WindowClosing(this, new System.EventArgs());

                        base.WndProc(ref m);
                        break;
                }
            }

            #endregion
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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

Share

About the Author

Arman Ghazanchyan
Software Developer (Senior) ZipEdTech
United States United States
No Biography provided

You may also be interested in...

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160426.1 | Last Updated 24 Sep 2010
Article Copyright 2007 by Arman Ghazanchyan
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid