Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version
Go to top

Global Windows Hooks

, 24 Sep 2010
A single component that contains various Windows hooks
Library_Files.zip
Library Files
WindowsHookLib.dll
Source_Code_and_Demo.zip
Source Code and Demo
WindowsHookDemo
WindowsHookDemo.suo
WindowsHookDemo
bin
Debug
WindowsHookDemo.exe
WindowsHookDemo.vshost.exe
WindowsHookLib.dll
Release
My Project
Application.myapp
Settings.settings
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.zip
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

VBDT
Software Developer (Senior) ZipEdTech
United States United States
No Biography provided

| Advertise | Privacy | Mobile
Web01 | 2.8.140926.1 | Last Updated 24 Sep 2010
Article Copyright 2007 by VBDT
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid