คลิปบอร์ดเหตุการณ์ C #


90

มีการเปลี่ยนแปลงคลิปบอร์ดหรืออัปเดตเหตุการณ์ที่ฉันสามารถเข้าถึงผ่าน C # ได้หรือไม่


แล้วชั้นควบคุมล่ะ? มันอยู่ที่ไหน?

เป็นส่วนหนึ่งของ WinForms
— Contango

คำตอบ:


73

ฉันคิดว่าคุณจะต้องใช้ 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;
        // ... 
   }
}

(ยังมีอีกมากที่ต้องทำส่งผ่านสิ่งต่างๆไปตามห่วงโซ่คลิปบอร์ดและยกเลิกการลงทะเบียนมุมมองของคุณ แต่คุณสามารถรับได้จากบทความ )


มันใช้งานได้เฉพาะในรูปแบบที่เปิดครั้งแรก ... บอกว่าฉันมี MyForm1 และ myForm2 ฉันจึงเปิด myForm1 จากนั้น MyForm2 เหตุการณ์ ClipboardChanged จะขึ้นเฉพาะใน MyForm1 เท่านั้น ฉันหมายถึงในแอปพลิเคชัน MDI ...
— serhio

ลิงค์ตายแล้ว การสำรองข้อมูลใด ๆ ที่คุณทราบหรือไม่? +1 อย่างไรก็ตาม
— Patrick Hofman

1
สำหรับคนขี้เกียจ: ตั้งเวลาจับเวลาที่ 1ms จากนั้นตรวจสอบทุกครั้งว่ามีการเปลี่ยนแปลงเนื้อหาคลิปบอร์ดของคุณหรือไม่ ตะขอเหล่านี้เพิ่มการแจ้งเตือนไวรัสและโทรจันบนคอมพิวเตอร์ของฉัน
— C4d

1
มันส่งผ่านผงชูรสทุกหน้าต่างไปยังแบบฟอร์มและทำให้ยากต่อการดีบักโค้ด

ในทำนองเดียวกันSharpClipboardเป็นไลบรารีอาจมีประโยชน์มากกว่าเนื่องจากรวมคุณสมบัติเดียวกันไว้ในไลบรารีคอมโพเนนต์ที่ดี จากนั้นคุณสามารถเข้าถึงClipboardChangedเหตุการณ์และตรวจจับรูปแบบข้อมูลต่างๆเมื่อถูกตัด / คัดลอก
— Willy Kimura

78

เพื่อความสมบูรณ์นี่คือการควบคุมที่ฉันใช้ในรหัสการผลิต เพียงลากจากตัวออกแบบและดับเบิลคลิกเพื่อสร้างตัวจัดการเหตุการณ์

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;
    }
}
}

2
เยี่ยมมาก! อย่างไรก็ตามรหัสการโทรเหตุการณ์ของคุณไม่ปลอดภัยสำหรับเธรด คุณควรสร้างสำเนาในเครื่องหรือเริ่มต้นเหตุการณ์ด้วยผู้รับมอบสิทธิ์ที่ว่างเปล่า คุณลืมคีย์เวิร์ด 'event' ในคำจำกัดความของ ClipboardChanged :)
— Ohad Schneider

1
@ohadsc ขอบคุณสำหรับการแก้ไข เท่าที่ฉันรู้ WndProc ถูกเรียกบนเธรด UI เนื่องจากคลาสมาจาก Control ไคลเอนต์ควรเรียกใช้บนเธรด UI ด้วย
— dbkk

มันใช้งานได้เฉพาะในรูปแบบที่เปิดครั้งแรก ... พูดว่าฉันมี MyForm1 และ myForm2 ฉันจึงเปิด myForm1 จากนั้น MyForm2 เหตุการณ์ ClipboardChanged จะขึ้นเฉพาะใน MyForm1 ... ฉันหมายถึงในแอปพลิเคชัน MDI ...
— serhio

อย่างไรก็ตามการเรียก SetClipboardViewer ของคุณตั้งค่ารหัสข้อผิดพลาด Win32 1400: "หมายเลขอ้างอิงหน้าต่างไม่ถูกต้อง" แต่ก็ยังใช้งานได้ นี่ดูแปลก ๆ สำหรับฉัน
— metacircle

1
SharpClipboardเป็นไลบรารีอาจมีประโยชน์มากกว่าเนื่องจากรวมคุณสมบัติเดียวกันไว้ในไลบรารีส่วนประกอบที่ดี จากนั้นคุณสามารถเข้าถึงClipboardChangedเหตุการณ์และตรวจจับรูปแบบข้อมูลต่างๆเมื่อถูกตัด / คัดลอก
— Willy Kimura

26

ฉันมีความท้าทายนี้ใน WPF และลงเอยด้วยวิธีการที่อธิบายไว้ด้านล่าง สำหรับรูปแบบ windows มีตัวอย่างที่ยอดเยี่ยมที่อื่นในคำตอบนี้เช่นการควบคุม ClipboardHelper

สำหรับ WPF เราไม่สามารถแทนที่ WndProc ได้ดังนั้นเราจึงต้องเชื่อมต่ออย่างชัดเจนด้วยการเรียก HwndSource AddHook โดยใช้ Source จากหน้าต่าง ผู้ฟังคลิปบอร์ดยังคงใช้การโทร interop แบบเนทีฟของ 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!


1
ถ้ามีคนไม่ทราบว่าสิ่งที่มันหมายถึงการClipboardChanged?.Invokeดูการใช้ใหม่ Null เงื่อนไขประกอบการใน C # 6ส่วนสถานการณ์อื่น ๆ
— marbel82

11

โอเคนี่เป็นโพสต์เก่า แต่เราพบวิธีแก้ปัญหาที่ดูเหมือนง่ายมากเมื่อเทียบกับชุดคำตอบปัจจุบัน เรากำลังใช้ WPF และเราต้องการให้คำสั่งที่กำหนดเอง (ใน ContextMenu) เปิดใช้งานและปิดใช้งานหากคลิปบอร์ดมีข้อความ มี ApplicationCommands อยู่แล้วตัดคัดลอกและวางและคำสั่งเหล่านี้ตอบสนองอย่างถูกต้องต่อการเปลี่ยนแปลงคลิปบอร์ด ดังนั้นเราจึงเพิ่ม EventHandler ต่อไปนี้

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

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

จริงๆแล้วเรากำลังควบคุม CanExecute ด้วยคำสั่งของเราเองด้วยวิธีนี้ ใช้ได้ผลกับสิ่งที่เราต้องการและบางทีมันอาจจะช่วยคนอื่นได้


ทางออกที่ดีเพราะมันง่ายมาก ... ขอบคุณ!
— okieh

1
นี่เป็นวิธีแก้ปัญหาที่ยอดเยี่ยมสำหรับการเปิดใช้งานหรือปิดใช้งานคำสั่งวาง น่าเสียดายที่ไม่ครอบคลุมสถานการณ์เฉพาะ "ข้อความที่เปลี่ยนแปลง" และจะไม่เริ่มทำงานเมื่อคัดลอกข้อความบรรทัดต่างๆหลายบรรทัดเช่น
— Colin Dabritz

11

มีหลายวิธีในการทำสิ่งนี้ แต่นี่เป็นสิ่งที่ฉันชอบและเหมาะกับฉัน ฉันได้สร้างไลบรารีคลาสเพื่อให้ผู้อื่นสามารถเพิ่มโปรเจ็กต์และรวม DLL จากนั้นก็โทรหาและใช้งานได้ทุกที่ที่ต้องการภายในแอปพลิเคชันของตน

คำตอบนี้ถูกสร้างขึ้นมาด้วยความช่วยเหลือของคนนี้

  1. สร้างโปรเจ็กต์ไลบรารีคลาสและตั้งชื่อว่า ClipboardHelper
  2. แทนที่ชื่อ Class1 ด้วย ClipboardMonitor
  3. ใส่รหัสด้านล่างลงไป
  4. เพิ่มข้อมูลอ้างอิง 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. ในโครงการของคุณไปที่และคลิกขวาที่การอ้างอิง -> เพิ่มการอ้างอิง -> โซลูชัน -> เลือก 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...
            }
    }
    

7

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


6

ฉันเชื่อว่าหนึ่งในวิธีแก้ปัญหาก่อนหน้านี้ไม่ได้ตรวจสอบค่าว่างในวิธีการกำจัด:

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;
        }
    }
}

มันไม่เคยเป็นโมฆะเพราะตัวสร้างตั้งค่า สิ่งเดียวที่ฉันจะทำแตกต่างออกไปคือการเรียกbase.Dispose()ใช้วิธีการกำจัด
— jedmao

อย่างไรก็ตาม. เพื่อวัตถุประสงค์ในการตรวจสอบเช่นที่คุณระบุไว้คุณควรใช้ IntPtr.Zero สำหรับ NULL (โปรดทราบว่ามันไม่เทียบเท่ากับ C # null) stackoverflow.com/questions/1456861/…
— walter

1
ChangeClipboardChain ถูกเรียกใช้เสมอเมื่อออกในทุกตัวอย่าง
— msdn

จุดประสงค์คือการลบตัวเองออกจากห่วงโซ่ของโปรแกรมดูคลิปบอร์ด
— walter

0
        [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;
            }
        }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.