Feedback

MultiClipBoard (oder besser ClipBoardChangedEvent)

Sprache: C#

Wem das Feature des MultiClipboards von beispielsweise Office oder Visual Studio immer begeistert hat, kann es nun mit dieser Kleinen Komponente, in sein eigenes Programm recht einfach nachbauen. EDIT: 18.11.2007 So nochmal ein wenig überarbeitet
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace Tools {
    /// <summary>
    /// Stellt das Event Clipboard Changed für die übergebene Form zur Verfügung.
    /// </summary>
    /// <example>
    /// <code>
    /// //zb innerhalb der MainForm in der Methode InitializeComponent();
    /// Tools.MultiClipboard multiClipboard1;
    /// 
    /// private void InitializeComponent() {
    ///     // entweder so
    ///     this.multiClipboard1 = new Tools.MultiClipboard(this);
    ///     // oder so
    ///     //this.multiClipboard1 = new Tools.MultiClipboard();
    ///     //this.multiClipboard1.MainForm = this;
    ///     // 
    ///     // multiClipboard1
    ///     // 
    ///     this.multiClipboard1.clipBoardBoarding += new Tools.MultiClipboard.ClipBoardChangHandler(this.multiClipboard1_clipBoardBoarding);
    /// }
    /// private void multiClipboard1_clipBoardBoarding(object sender, Tools.ClipBoardChangEventArgs ex) {
    ///     // an dieser Stelle können Sie auf das Event reagieren 
    ///     // der Inhalt der aktuellen Zwischen ablage ist inerhalb ClipBoardChangEventArgs enthalten.
    /// }
    /// </code>
    /// </example>
    class MultiClipboard : Component {
        // Event
        /// <summary>
        /// Stellt die Methode dar, die ein Ereigniss behandelt.
        /// </summary>
        public delegate void ClipBoardChangHandler(Object sender, ClipBoardChangEventArgs ex);
        /// <summary>
        /// Tritt auf sobald sich die Zwischenablage ändert.
        /// </summary>
        public event ClipBoardChangHandler clipBoardChanged;

        // Api Call
        [DllImport("user32")]
        private extern static IntPtr SetClipboardViewer(IntPtr hWnd);
        [DllImport("user32")]
        private extern static int ChangeClipboardChain(IntPtr hWnd, IntPtr hWndNext);

        // Fields
        private Form formForMessageLoop;
        private IntPtr nextViewer = IntPtr.Zero;
        private IntPtr currentViewer = IntPtr.Zero;

        /// <summary>
        /// Legt die Form fest an die, die MessageLoop gebunden werden soll.
        /// </summary>
        public Form MainForm {
            set {
                formForMessageLoop = value;
                // Form Anmelden
                RegisterForm(formForMessageLoop);
            }
        }
        /// <summary>
        /// Initialisiert eine neue Instanz der MultiClipboard Klasse.
        /// </summary>
        public MultiClipboard() {
        }
        /// <summary>
        /// Initialisiert eine neue Instanz der MultiClipboard Klasse
        /// </summary>
        /// <param name="mainForm">Legt die Form fest an die, die MessageLoop gebunden werden soll.</param>
        public MultiClipboard(Form mainForm) {
            formForMessageLoop = mainForm;
            // Form anmelden
            RegisterForm(mainForm);    
        }
        /// <summary>
        /// Messageloop an Form Binden, sowie Event anbinden. 
        /// </summary>
        /// <param name="mainForm">Legt die Form fest an die, die MessageLoop gebunden werden soll.</param>
        private void RegisterForm(Form mainForm) {
            MessageLoopMainForm messageLoopMainForm = new MessageLoopMainForm(mainForm);

            RegisterViewer(mainForm);

            messageLoopMainForm.NextClipBoardViewer = nextViewer;
            //bei aufruf sofort an per Event weiterleiten
            messageLoopMainForm.clipBoardBoardChanged += new MessageLoopMainForm.ClipBoardChangEventHandler
                (delegate(Message m) { if (clipBoardChanged != null) clipBoardChanged(this, new ClipBoardChangEventArgs(Clipboard.GetDataObject())); });
        }
        /// <summary>
        /// Diesen Viewer an der Message Loop anmelden
        /// </summary>
        /// <param name="mainForm"></param>
        private void RegisterViewer(Form mainForm) {
            nextViewer = SetClipboardViewer(mainForm.Handle);
            currentViewer = mainForm.Handle;
        }
        /// <summary>
        /// Diesen Viewer wieder aus dem Message Loop wieder herrausnehmen
        /// </summary>
        private void DeRegisterViwer() {
            if (nextViewer != IntPtr.Zero) {
                ChangeClipboardChain(currentViewer, nextViewer);
                nextViewer = IntPtr.Zero;
                currentViewer = IntPtr.Zero;
            }
        }
        /// <summary>
        /// Destructor dieser Klasse
        /// </summary>
        ~MultiClipboard() {
            DeRegisterViwer();
        }
    }

    internal class MessageLoopMainForm : NativeWindow {
        // delegate
        internal delegate void ClipBoardChangEventHandler(Message m);
        internal ClipBoardChangEventHandler clipBoardBoardChanged;

        // Api Call
        [DllImport("user32")]
        private extern static int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

        // Konstanten
        /// <summary>
        /// Message wenn sich am Clipboard etwas ändert
        /// </summary>
        private const int WM_DRAWCLIPBOARD = 0x308;
        /// <summary>
        /// Message sobald sich an den anderen Viewern etwas ändert
        /// </summary>
        private const int WM_CHANGECBCHAIN = 0x30D;

        private IntPtr nextViewer;
        internal IntPtr NextClipBoardViewer {
            set {
                nextViewer = value;
            }
        }

        internal MessageLoopMainForm(Form mainForm) {
            // an die jeweiligen Form anhängen
            AssignHandle(mainForm.Handle);
        }

        protected override void WndProc(ref Message m) {
            switch (m.Msg) {
                case WM_CHANGECBCHAIN: {
                        // Nächsten Viewer ermitteln
                        nextViewer = m.LParam;
                        if (nextViewer != IntPtr.Zero) {
                            // Message an den nächsten Viewer weiterleiten
                            SendMessage(nextViewer, m.Msg, m.WParam, m.LParam);
                        }
                        break;
                    }
                case WM_DRAWCLIPBOARD: {
                        if (clipBoardBoardChanged != null)
                            clipBoardBoardChanged(m);
                        // Message an den nächsten Viewer weiterleiten
                        if (nextViewer != IntPtr.Zero) {
                            SendMessage(nextViewer, m.Msg, m.WParam, m.LParam);
                        }
                        m.Result = IntPtr.Zero;
                        break;
                    }
                default: {
                        // An die normale WndProc weiterleiten
                        base.WndProc(ref m);
                        break;
                    }
            }
        } 
    }
    /// <summary>
    /// Stellt die daten des Ereignisses zur Verfügung
    /// </summary>
    public class ClipBoardChangEventArgs : EventArgs {
        private IDataObject clipBoardObject;
        /// <summary>
        /// Initialisiert eine neue Instanz der ClipBoardChangEventArgs Klasse.
        /// </summary>
        public ClipBoardChangEventArgs(IDataObject clipBoardObject) { this.clipBoardObject = clipBoardObject; }
        /// <summary>
        /// Die enthaltenen Daten des Clipboards, zum Zeitpunkt an dem das Ereigniss aufgetrten ist.
        /// </summary>
        public IDataObject ClipBoardObject { get { return clipBoardObject; } }
    } 
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace Tools {
    /// <summary>
    /// Stellt das Event Clipboard Changed für die übergebene Form zur Verfügung.
    /// </summary>
    /// <example>
    /// <code>
    /// //zb innerhalb der MainForm in der Methode InitializeComponent();
    /// Tools.MultiClipboard multiClipboard1;
    /// 
    /// private void InitializeComponent() {
    ///     // entweder so
    ///     this.multiClipboard1 = new Tools.MultiClipboard(this);
    ///     // oder so
    ///     //this.multiClipboard1 = new Tools.MultiClipboard();
    ///     //this.multiClipboard1.MainForm = this;
    ///     // 
    ///     // multiClipboard1
    ///     // 
    ///     this.multiClipboard1.clipBoardBoarding += new Tools.MultiClipboard.ClipBoardChangHandler(this.multiClipboard1_clipBoardBoarding);
    /// }
    /// private void multiClipboard1_clipBoardBoarding(object sender, Tools.ClipBoardChangEventArgs ex) {
    ///     // an dieser Stelle können Sie auf das Event reagieren 
    ///     // der Inhalt der aktuellen Zwischen ablage ist inerhalb ClipBoardChangEventArgs enthalten.
    /// }
    /// </code>
    /// </example>
    class MultiClipboard : Component {
        // Event
        /// <summary>
        /// Stellt die Methode dar, die ein Ereigniss behandelt.
        /// </summary>
        public delegate void ClipBoardChangHandler(Object sender, ClipBoardChangEventArgs ex);
        /// <summary>
        /// Tritt auf sobald sich die Zwischenablage ändert.
        /// </summary>
        public event ClipBoardChangHandler clipBoardChanged;

        // Api Call
        [DllImport("user32")]
        private extern static IntPtr SetClipboardViewer(IntPtr hWnd);
        [DllImport("user32")]
        private extern static int ChangeClipboardChain(IntPtr hWnd, IntPtr hWndNext);

        // Fields
        private Form formForMessageLoop;
        private IntPtr nextViewer = IntPtr.Zero;
        private IntPtr currentViewer = IntPtr.Zero;

        /// <summary>
        /// Legt die Form fest an die, die MessageLoop gebunden werden soll.
        /// </summary>
        public Form MainForm {
            set {
                formForMessageLoop = value;
                // Form Anmelden
                RegisterForm(formForMessageLoop);
            }
        }
        /// <summary>
        /// Initialisiert eine neue Instanz der MultiClipboard Klasse.
        /// </summary>
        public MultiClipboard() {
        }
        /// <summary>
        /// Initialisiert eine neue Instanz der MultiClipboard Klasse
        /// </summary>
        /// <param name="mainForm">Legt die Form fest an die, die MessageLoop gebunden werden soll.</param>
        public MultiClipboard(Form mainForm) {
            formForMessageLoop = mainForm;
            // Form anmelden
            RegisterForm(mainForm);    
        }
        /// <summary>
        /// Messageloop an Form Binden, sowie Event anbinden. 
        /// </summary>
        /// <param name="mainForm">Legt die Form fest an die, die MessageLoop gebunden werden soll.</param>
        private void RegisterForm(Form mainForm) {
            MessageLoopMainForm messageLoopMainForm = new MessageLoopMainForm(mainForm);

            RegisterViewer(mainForm);

            messageLoopMainForm.NextClipBoardViewer = nextViewer;
            //bei aufruf sofort an per Event weiterleiten
            messageLoopMainForm.clipBoardBoardChanged += new MessageLoopMainForm.ClipBoardChangEventHandler
                (delegate(Message m) { if (clipBoardChanged != null) clipBoardChanged(this, new ClipBoardChangEventArgs(Clipboard.GetDataObject())); });
        }
        /// <summary>
        /// Diesen Viewer an der Message Loop anmelden
        /// </summary>
        /// <param name="mainForm"></param>
        private void RegisterViewer(Form mainForm) {
            nextViewer = SetClipboardViewer(mainForm.Handle);
            currentViewer = mainForm.Handle;
        }
        /// <summary>
        /// Diesen Viewer wieder aus dem Message Loop wieder herrausnehmen
        /// </summary>
        private void DeRegisterViwer() {
            if (nextViewer != IntPtr.Zero) {
                ChangeClipboardChain(currentViewer, nextViewer);
                nextViewer = IntPtr.Zero;
                currentViewer = IntPtr.Zero;
            }
        }
        /// <summary>
        /// Destructor dieser Klasse
        /// </summary>
        ~MultiClipboard() {
            DeRegisterViwer();
        }
    }

    internal class MessageLoopMainForm : NativeWindow {
        // delegate
        internal delegate void ClipBoardChangEventHandler(Message m);
        internal ClipBoardChangEventHandler clipBoardBoardChanged;

        // Api Call
        [DllImport("user32")]
        private extern static int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

        // Konstanten
        /// <summary>
        /// Message wenn sich am Clipboard etwas ändert
        /// </summary>
        private const int WM_DRAWCLIPBOARD = 0x308;
        /// <summary>
        /// Message sobald sich an den anderen Viewern etwas ändert
        /// </summary>
        private const int WM_CHANGECBCHAIN = 0x30D;

        private IntPtr nextViewer;
        internal IntPtr NextClipBoardViewer {
            set {
                nextViewer = value;
            }
        }

        internal MessageLoopMainForm(Form mainForm) {
            // an die jeweiligen Form anhängen
            AssignHandle(mainForm.Handle);
        }

        protected override void WndProc(ref Message m) {
            switch (m.Msg) {
                case WM_CHANGECBCHAIN: {
                        // Nächsten Viewer ermitteln
                        nextViewer = m.LParam;
                        if (nextViewer != IntPtr.Zero) {
                            // Message an den nächsten Viewer weiterleiten
                            SendMessage(nextViewer, m.Msg, m.WParam, m.LParam);
                        }
                        break;
                    }
                case WM_DRAWCLIPBOARD: {
                        if (clipBoardBoardChanged != null)
                            clipBoardBoardChanged(m);
                        // Message an den nächsten Viewer weiterleiten
                        if (nextViewer != IntPtr.Zero) {
                            SendMessage(nextViewer, m.Msg, m.WParam, m.LParam);
                        }
                        m.Result = IntPtr.Zero;
                        break;
                    }
                default: {
                        // An die normale WndProc weiterleiten
                        base.WndProc(ref m);
                        break;
                    }
            }
        } 
    }
    /// <summary>
    /// Stellt die daten des Ereignisses zur Verfügung
    /// </summary>
    public class ClipBoardChangEventArgs : EventArgs {
        private IDataObject clipBoardObject;
        /// <summary>
        /// Initialisiert eine neue Instanz der ClipBoardChangEventArgs Klasse.
        /// </summary>
        public ClipBoardChangEventArgs(IDataObject clipBoardObject) { this.clipBoardObject = clipBoardObject; }
        /// <summary>
        /// Die enthaltenen Daten des Clipboards, zum Zeitpunkt an dem das Ereigniss aufgetrten ist.
        /// </summary>
        public IDataObject ClipBoardObject { get { return clipBoardObject; } }
    } 
}

1 Kommentar