คลิปบอร์ดเหตุการณ์ 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.