Вопрос

Есть ли в буфере обмена измененное или обновленное событие, к которому я могу получить доступ через C #?

Это было полезно?

Решение

Я думаю, вам придется использовать p / invoke:

[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);

См. эту статью на как настроить монитор буфера обмена в c #

Обычно вы регистрируете свое приложение как средство просмотра буфера обмена, используя

_ClipboardViewerNext = SetClipboardViewer(this.Handle);

и затем вы получите сообщение WM_DRAWCLIPBOARD , которое вы можете обработать, переопределив WndProc :

protected override void WndProc(ref Message m)
{
    switch ((Win32.Msgs)m.Msg)
    {
        case Win32.Msgs.WM_DRAWCLIPBOARD:
        // Handle clipboard changed
        break;
        // ... 
   }
}

(Еще многое нужно сделать; передать вещи по цепочке буфера обмена и отменить регистрацию вашего представления, но вы можете получить это по адресу статья )

Другие советы

Для полноты, вот элемент управления, который я использую в производственном коде. Просто перетащите из конструктора и дважды щелкните, чтобы создать обработчик событий.

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;

namespace ClipboardAssist {

// Must inherit Control, not Component, in order to have Handle
[DefaultEvent("ClipboardChanged")]
public partial class ClipboardMonitor : Control 
{
    IntPtr nextClipboardViewer;

    public ClipboardMonitor()
    {
        this.BackColor = Color.Red;
        this.Visible = false;

        nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
    }

    /// <summary>
    /// Clipboard contents changed.
    /// </summary>
    public event EventHandler<ClipboardChangedEventArgs> ClipboardChanged;

    protected override void Dispose(bool disposing)
    {
        ChangeClipboardChain(this.Handle, nextClipboardViewer);
    }

    [DllImport("User32.dll")]
    protected static extern int SetClipboardViewer(int hWndNewViewer);

    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        // defined in winuser.h
        const int WM_DRAWCLIPBOARD = 0x308;
        const int WM_CHANGECBCHAIN = 0x030D;

        switch (m.Msg)
        {
            case WM_DRAWCLIPBOARD:
                OnClipboardChanged();
                SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                break;

            case WM_CHANGECBCHAIN:
                if (m.WParam == nextClipboardViewer)
                    nextClipboardViewer = m.LParam;
                else
                    SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                break;

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

    void OnClipboardChanged()
    {
        try
        {
            IDataObject iData = Clipboard.GetDataObject();
            if (ClipboardChanged != null)
            {
                ClipboardChanged(this, new ClipboardChangedEventArgs(iData));
            }

        }
        catch (Exception e)
        {
            // Swallow or pop-up, not sure
            // Trace.Write(e.ToString());
            MessageBox.Show(e.ToString());
        }
    }
}

public class ClipboardChangedEventArgs : EventArgs
{
    public readonly IDataObject DataObject;

    public ClipboardChangedEventArgs(IDataObject dataObject)
    {
        DataObject = dataObject;
    }
}
}

Я столкнулся с этой проблемой в WPF и в итоге использовал подход, описанный ниже. Для форм Windows есть отличные примеры в этом ответе, такие как элемент управления ClipboardHelper.

Для WPF мы не можем переопределить WndProc, поэтому мы должны явно подключить его с помощью вызова HwndSource AddHook, используя Source из окна. Слушатель буфера обмена все еще использует собственный вызов взаимодействия AddClipboardFormatListener.

Собственные методы:

internal static class NativeMethods
{
    // See http://msdn.microsoft.com/en-us/library/ms649021%28v=vs.85%29.aspx
    public const int WM_CLIPBOARDUPDATE = 0x031D;
    public static IntPtr HWND_MESSAGE = new IntPtr(-3);

    // See http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only
    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool AddClipboardFormatListener(IntPtr hwnd);
}

Класс менеджера буфера обмена:

using System.Windows;
using System.Windows.Interop;

public class ClipboardManager
{
    public event EventHandler ClipboardChanged;

    public ClipboardManager(Window windowSource)
    {
        HwndSource source = PresentationSource.FromVisual(windowSource) as HwndSource;
        if(source == null)
        {
            throw new ArgumentException(
                "Window source MUST be initialized first, such as in the Window's OnSourceInitialized handler."
                , nameof(windowSource));
        }

        source.AddHook(WndProc);

        // get window handle for interop
        IntPtr windowHandle = new WindowInteropHelper(windowSource).Handle;

        // register for clipboard events
        NativeMethods.AddClipboardFormatListener(windowHandle);
    }

    private void OnClipboardChanged()
    {
        ClipboardChanged?.Invoke(this, EventArgs.Empty);
    }

    private static readonly IntPtr WndProcSuccess = IntPtr.Zero;

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == NativeMethods.WM_CLIPBOARDUPDATE)
        {
            OnClipboardChanged();
            handled = true;
        }

        return WndProcSuccess;
    }
}

Это используется в окне WPF путем добавления события в OnSourceInitialized или позже, такого как событие Window.Loaded или во время работы. (когда у нас достаточно информации для использования нативных хуков):

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);

        // Initialize the clipboard now that we have a window soruce to use
        var windowClipboardManager = new ClipboardManager(this);
        windowClipboardManager.ClipboardChanged += ClipboardChanged;
    }

    private void ClipboardChanged(object sender, EventArgs e)
    {
        // Handle your clipboard update here, debug logging example:
        if (Clipboard.ContainsText())
        {
            Debug.WriteLine(Clipboard.GetText());
        }
    }
}

Я использую этот подход в проекте анализатора элементов Path of Exile, поскольку игра предоставляет информацию об элементах через буфер обмена при нажатии Ctrl-C.

https://github.com/ColinDabritz/PoeItemAnalyzer

Надеюсь, это поможет кому-то с обработкой изменений буфера обмена WPF!

Хорошо, это старый пост, но мы нашли решение, которое кажется очень простым по сравнению с текущим набором ответов. Мы используем WPF, и мы хотели, чтобы наши собственные команды (в ContextMenu) включали и отключали, если в буфере обмена есть текст. Уже есть ApplicationCommands.Cut, Copy и Paste, и эти команды корректно реагируют на изменение буфера обмена. Поэтому мы просто добавили следующий EventHandler.

ApplicationCommands.Paste.CanExecuteChanged += new EventHandler(Paste_CanExecuteChanged);

private void Paste_CanExecuteChanged(object sender, EventArgs e) {
  ourVariable= Clipboard.ContainsText();
}

Таким образом, мы фактически контролируем CanExecute для нашей собственной команды. Работает на то, что нам было нужно, и, возможно, это поможет другим.

Есть несколько способов сделать это, но это мой любимый и работает для меня. Я создал библиотеку классов, чтобы другие могли добавить проект и включить библиотеку DLL, а затем просто вызывать ее и использовать в любом месте в своих приложениях.

Этот ответ был получен с помощью этого .

<Ол>
  • Создайте проект библиотеки классов и назовите его ClipboardHelper.
  • Замените имя Class1 на ClipboardMonitor.
  • Добавьте приведенный ниже код.
  • Добавьте ссылку на System.Windows.Forms.
  • Дополнительные шаги в коде.

    using System;
    using System.Windows.Forms;
    using System.Threading;
    using System.Runtime.InteropServices;
    
    namespace ClipboardHelper
    {
        public static class ClipboardMonitor
        {
            public delegate void OnClipboardChangeEventHandler(ClipboardFormat format, object data);
            public static event OnClipboardChangeEventHandler OnClipboardChange;
    
            public static void Start()
            {
                ClipboardWatcher.Start();
                ClipboardWatcher.OnClipboardChange += (ClipboardFormat format, object data) =>
                {
                    if (OnClipboardChange != null)
                        OnClipboardChange(format, data);
                };
            }
    
            public static void Stop()
            {
                OnClipboardChange = null;
                ClipboardWatcher.Stop();
            }
    
            class ClipboardWatcher : Form
            {
                // static instance of this form
                private static ClipboardWatcher mInstance;
    
                // needed to dispose this form
                static IntPtr nextClipboardViewer;
    
                public delegate void OnClipboardChangeEventHandler(ClipboardFormat format, object data);
                public static event OnClipboardChangeEventHandler OnClipboardChange;
    
                // start listening
                public static void Start()
                {
                    // we can only have one instance if this class
                    if (mInstance != null)
                        return;
    
                    var t = new Thread(new ParameterizedThreadStart(x => Application.Run(new ClipboardWatcher())));
                    t.SetApartmentState(ApartmentState.STA); // give the [STAThread] attribute
                    t.Start();
                }
    
                // stop listening (dispose form)
                public static void Stop()
                {
                    mInstance.Invoke(new MethodInvoker(() =>
                    {
                        ChangeClipboardChain(mInstance.Handle, nextClipboardViewer);
                    }));
                    mInstance.Invoke(new MethodInvoker(mInstance.Close));
    
                    mInstance.Dispose();
    
                    mInstance = null;
                }
    
                // on load: (hide this window)
                protected override void SetVisibleCore(bool value)
                {
                    CreateHandle();
    
                    mInstance = this;
    
                    nextClipboardViewer = SetClipboardViewer(mInstance.Handle);
    
                    base.SetVisibleCore(false);
                }
    
                [DllImport("User32.dll", CharSet = CharSet.Auto)]
                private static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
    
                [DllImport("User32.dll", CharSet = CharSet.Auto)]
                private static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
    
                [DllImport("user32.dll", CharSet = CharSet.Auto)]
                private static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
    
                // defined in winuser.h
                const int WM_DRAWCLIPBOARD = 0x308;
                const int WM_CHANGECBCHAIN = 0x030D;
    
                protected override void WndProc(ref Message m)
                {
                    switch (m.Msg)
                    {
                        case WM_DRAWCLIPBOARD:
                            ClipChanged();
                            SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                            break;
    
                        case WM_CHANGECBCHAIN:
                            if (m.WParam == nextClipboardViewer)
                                nextClipboardViewer = m.LParam;
                            else
                                SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                            break;
    
                        default:
                            base.WndProc(ref m);
                            break;
                    }
                }
    
                static readonly string[] formats = Enum.GetNames(typeof(ClipboardFormat));
    
                private void ClipChanged()
                {
                    IDataObject iData = Clipboard.GetDataObject();
    
                    ClipboardFormat? format = null;
    
                    foreach (var f in formats)
                    {
                        if (iData.GetDataPresent(f))
                        {
                            format = (ClipboardFormat)Enum.Parse(typeof(ClipboardFormat), f);
                            break;
                        }
                    }
    
                    object data = iData.GetData(format.ToString());
    
                    if (data == null || format == null)
                        return;
    
                    if (OnClipboardChange != null)
                        OnClipboardChange((ClipboardFormat)format, data);
                }
            }
        }
    
        public enum ClipboardFormat : byte
        {
            /// <summary>Specifies the standard ANSI text format. This static field is read-only.
            /// </summary>
            /// <filterpriority>1</filterpriority>
            Text,
            /// <summary>Specifies the standard Windows Unicode text format. This static field
            /// is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            UnicodeText,
            /// <summary>Specifies the Windows device-independent bitmap (DIB) format. This static
            /// field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            Dib,
            /// <summary>Specifies a Windows bitmap format. This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            Bitmap,
            /// <summary>Specifies the Windows enhanced metafile format. This static field is
            /// read-only.</summary>
            /// <filterpriority>1</filterpriority>
            EnhancedMetafile,
            /// <summary>Specifies the Windows metafile format, which Windows Forms does not
            /// directly use. This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            MetafilePict,
            /// <summary>Specifies the Windows symbolic link format, which Windows Forms does
            /// not directly use. This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            SymbolicLink,
            /// <summary>Specifies the Windows Data Interchange Format (DIF), which Windows Forms
            /// does not directly use. This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            Dif,
            /// <summary>Specifies the Tagged Image File Format (TIFF), which Windows Forms does
            /// not directly use. This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            Tiff,
            /// <summary>Specifies the standard Windows original equipment manufacturer (OEM)
            /// text format. This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            OemText,
            /// <summary>Specifies the Windows palette format. This static field is read-only.
            /// </summary>
            /// <filterpriority>1</filterpriority>
            Palette,
            /// <summary>Specifies the Windows pen data format, which consists of pen strokes
            /// for handwriting software, Windows Forms does not use this format. This static
            /// field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            PenData,
            /// <summary>Specifies the Resource Interchange File Format (RIFF) audio format,
            /// which Windows Forms does not directly use. This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            Riff,
            /// <summary>Specifies the wave audio format, which Windows Forms does not directly
            /// use. This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            WaveAudio,
            /// <summary>Specifies the Windows file drop format, which Windows Forms does not
            /// directly use. This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            FileDrop,
            /// <summary>Specifies the Windows culture format, which Windows Forms does not directly
            /// use. This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            Locale,
            /// <summary>Specifies text consisting of HTML data. This static field is read-only.
            /// </summary>
            /// <filterpriority>1</filterpriority>
            Html,
            /// <summary>Specifies text consisting of Rich Text Format (RTF) data. This static
            /// field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            Rtf,
            /// <summary>Specifies a comma-separated value (CSV) format, which is a common interchange
            /// format used by spreadsheets. This format is not used directly by Windows Forms.
            /// This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            CommaSeparatedValue,
            /// <summary>Specifies the Windows Forms string class format, which Windows Forms
            /// uses to store string objects. This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            StringFormat,
            /// <summary>Specifies a format that encapsulates any type of Windows Forms object.
            /// This static field is read-only.</summary>
            /// <filterpriority>1</filterpriority>
            Serializable,
        }
    }
    
    1. В других своих проектах щелкните правой кнопкой мыши на решении и выберите Добавить - > Выход из проекта - > ClipboardHelper.csproj
    2. В своем проекте перейдите и щелкните правой кнопкой мыши на References - > Добавить ссылку - > Решение - > Выберите ClipboardHelper.
    3. В вашем классе файл типа проекта с использованием ClipboardHelper.
    4. Теперь вы можете набирать ClipboardMonitor.Start или .Stop или .OnClipboardChanged

      using ClipboardHelper;
      
      namespace Something.Something.DarkSide
      {
          public class MainWindow
          {
      
              public MainWindow()
              {
                  InitializeComponent();
      
                  Loaded += MainWindow_Loaded;
              }
      
              void MainWindow_Loaded(object sender, RoutedEventArgs e)
              {
                  ClipboardMonitor.OnClipboardChange += ClipboardMonitor_OnClipboardChange;
                  ClipboardMonitor.Start();
              }               
      
              private void ClipboardMonitor_OnClipboardChange(ClipboardFormat format, object data)
              {
                  // Do Something...
              }
      }
      

    Я полагаю, что одно из более ранних решений не проверяет нулевое значение в методе dispose:

    using System;
    using System.ComponentModel;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using System.Drawing;
    
    namespace ClipboardAssist {
    
    // Must inherit Control, not Component, in order to have Handle
    [DefaultEvent("ClipboardChanged")]
    public partial class ClipboardMonitor : Control 
    {
        IntPtr nextClipboardViewer;
    
        public ClipboardMonitor()
        {
            this.BackColor = Color.Red;
            this.Visible = false;
    
            nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
        }
    
        /// <summary>
        /// Clipboard contents changed.
        /// </summary>
        public event EventHandler<ClipboardChangedEventArgs> ClipboardChanged;
    
        protected override void Dispose(bool disposing)
        {
            if(nextClipboardViewer != null)
                ChangeClipboardChain(this.Handle, nextClipboardViewer);
        }
    
        [DllImport("User32.dll")]
        protected static extern int SetClipboardViewer(int hWndNewViewer);
    
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
    
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
    
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            // defined in winuser.h
            const int WM_DRAWCLIPBOARD = 0x308;
            const int WM_CHANGECBCHAIN = 0x030D;
    
            switch (m.Msg)
            {
                case WM_DRAWCLIPBOARD:
                    OnClipboardChanged();
                    SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                    break;
    
                case WM_CHANGECBCHAIN:
                    if (m.WParam == nextClipboardViewer)
                        nextClipboardViewer = m.LParam;
                    else
                        SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                    break;
    
                default:
                    base.WndProc(ref m);
                    break;
            }
        }
    
        void OnClipboardChanged()
        {
            try
            {
                IDataObject iData = Clipboard.GetDataObject();
                if (ClipboardChanged != null)
                {
                    ClipboardChanged(this, new ClipboardChangedEventArgs(iData));
                }
    
            }
            catch (Exception e)
            {
                // Swallow or pop-up, not sure
                // Trace.Write(e.ToString());
                MessageBox.Show(e.ToString());
            }
        }
    }
    
        public class ClipboardChangedEventArgs : EventArgs
        {
            public readonly IDataObject DataObject;
    
            public ClipboardChangedEventArgs(IDataObject dataObject)
            {
                DataObject = dataObject;
            }
        }
    }
    

    здесь является хороший пример использования AddClipboardFormatListener .

    Для того, чтобы сделать это, нам нужно вызвать пин-код AddClipboardFormatListener и RemoveClipboardFormatListener .

    /// <summary>
    /// Places the given window in the system-maintained clipboard format listener list.
    /// </summary>
    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool AddClipboardFormatListener(IntPtr hwnd);
    
    /// <summary>
    /// Removes the given window from the system-maintained clipboard format listener list.
    /// </summary>
    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
    
    /// <summary>
    /// Sent when the contents of the clipboard have changed.
    /// </summary>
    private const int WM_CLIPBOARDUPDATE = 0x031D;
    

    Затем нам нужно добавить наше окно в список слушателей формата буфера обмена, вызвав метод AddClipboardFormatListener с дескриптором нашего окна в качестве параметра. Поместите следующий код в конструктор формы главного окна или любое из его событий загрузки.

    AddClipboardFormatListener(this.Handle);    // Add our window to the clipboard's format listener list.
    

    Переопределите метод WndProc , чтобы мы могли его отследить при отправке WM_CLIPBOARDUPDATE .

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
    
        if (m.Msg == WM_CLIPBOARDUPDATE)
        {
            IDataObject iData = Clipboard.GetDataObject();      // Clipboard's data.
    
            /* Depending on the clipboard's current data format we can process the data differently.
             * Feel free to add more checks if you want to process more formats. */
            if (iData.GetDataPresent(DataFormats.Text))
            {
                string text = (string)iData.GetData(DataFormats.Text);
                // do something with it
            }
            else if (iData.GetDataPresent(DataFormats.Bitmap))
            {
                Bitmap image = (Bitmap)iData.GetData(DataFormats.Bitmap);
                // do something with it
            }
        }
    }
    

    И, наконец, перед закрытием формы обязательно удалите главное окно из списка слушателей формата буфера обмена.

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        RemoveClipboardFormatListener(this.Handle);     // Remove our window from the clipboard's format listener list.
    }
    

    SharpClipboard в виде библиотеки может быть более полезным, поскольку она объединяет те же функции в одну прекрасная библиотека компонентов. Затем вы можете получить доступ к его событию ClipboardChanged и обнаружить различные форматы данных, когда они вырезаны / скопированы.

    Вы можете выбрать различные форматы данных, которые вы хотите отслеживать:

    var clipboard = new SharpClipboard();
    
    clipboard.ObservableFormats.Texts = true;
    clipboard.ObservableFormats.Files = true;
    clipboard.ObservableFormats.Images = true;
    clipboard.ObservableFormats.Others = true;
    

    Вот пример использования события ClipboardChanged :

    private void ClipboardChanged(Object sender, ClipboardChangedEventArgs e)
    {
        // Is the content copied of text type?
        if (e.ContentType == SharpClipboard.ContentTypes.Text)
        {
            // Get the cut/copied text.
            Debug.WriteLine(clipboard.ClipboardText);
        }
    
        // Is the content copied of image type?
        else if (e.ContentType == SharpClipboard.ContentTypes.Image)
        {
            // Get the cut/copied image.
            Image img = clipboard.ClipboardImage;
        }
    
        // Is the content copied of file type?
        else if (e.ContentType == SharpClipboard.ContentTypes.Files)
        {
            // Get the cut/copied file/files.
            Debug.WriteLine(clipboard.ClipboardFiles.ToArray());
    
            // ...or use 'ClipboardFile' to get a single copied file.
            Debug.WriteLine(clipboard.ClipboardFile);
        }
    
        // If the cut/copied content is complex, use 'Other'.
        else if (e.ContentType == SharpClipboard.ContentTypes.Other)
        {
            // Do something with 'e.Content' here...
        }
    }
    

    Вы также можете найти приложение, в котором произошло событие вырезания / копирования, и его подробности:

    private void ClipboardChanged(Object sender, SharpClipboard.ClipboardChangedEventArgs e)
    {
        // Gets the application's executable name.
        Debug.WriteLine(e.SourceApplication.Name);
        // Gets the application's window title.
        Debug.WriteLine(e.SourceApplication.Title);
        // Gets the application's process ID.
        Debug.WriteLine(e.SourceApplication.ID.ToString());
        // Gets the application's executable path.
        Debug.WriteLine(e.SourceApplication.Path);
    }
    

    Существуют также другие события, такие как событие MonitorChanged , которое прослушивается всякий раз, когда отключен мониторинг буфера обмена. Это означает, что вы можете включить или отключить мониторинг буфера обмена во время выполнения.

    В дополнение ко всему этому, поскольку это компонент, вы можете использовать его в режиме конструктора , перетаскивая его в форму Windows, что упрощает настройку его параметров для любого пользователя. и работать с его встроенными событиями.

    SharpClipboard , по-видимому, является наилучшим вариантом для сценариев мониторинга буфера обмена в .NET.

            [DllImport("User32.dll", CharSet = CharSet.Auto)]
            public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
            private IntPtr _ClipboardViewerNext;
    
            private void Form1_Load(object sender, EventArgs e)
            {
                _ClipboardViewerNext = SetClipboardViewer(this.Handle);
            }
    
            protected override void WndProc(ref System.Windows.Forms.Message m)
            {
                const int WM_DRAWCLIPBOARD = 0x308;
    
                switch (m.Msg)
                {
                    case WM_DRAWCLIPBOARD:
                        //Clipboard is Change 
                        //your code..............
                        break; 
                    default:
                        base.WndProc(ref m);
                        break;
                }
            }
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top