Pano etkinliği C #


90

C # aracılığıyla erişebileceğim bir pano değişikliği veya güncellenmiş olay var mı?


Peki ya Control sınıfı? Nerede?

WinForms'un bir parçasıdır.
Contango

Yanıtlar:


73

Sanırım bazı p / invoke kullanmanız gerekecek:

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

C # 'da bir pano monitörünün nasıl kurulacağına ilişkin bu makaleye bakın

Temel olarak uygulamanızı bir pano görüntüleyicisi olarak kaydedersiniz.

_ClipboardViewerNext = SetClipboardViewer(this.Handle);

ve ardından WM_DRAWCLIPBOARDmesajı alacaksınız, bunu geçersiz kılarak halledebilirsiniz WndProc:

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

(Yapılacak daha çok şey var; pano zinciri boyunca işleri aktarmak ve görünümünüzün kaydını silmek, ancak bunu makaleden alabilirsiniz )


Yalnızca ilk açılmış formda çalışır ... mesela MyForm1 ve myForm2'ye sahipsem, bu yüzden myForm1'i, ardından MyForm2'yi açarsam, ClipboardChanged olayı yalnızca MyForm1'de yükseltilecektir. Demek istediğim, bir MDI başvurusunda ...
serhio

Bağlantı kesildi. Farkında olduğunuz herhangi bir yedek var mı? Yine de +1.
Patrick Hofman

1
Tembel insanlar için: 1 ms'de çalışan bir zamanlayıcı ayarlayın. Ardından, her işaretlemede pano içeriğinizin değişip değişmediğini kontrol edin. Bu kancalar bilgisayarımda virüs ve truva atı uyarıları oluşturuyor.
C4d

1
Bu forma her pencereleri MSG geçer ve o kadar sert kod hata ayıklama yapmak

Benzer şekilde, bir kütüphane olarak SharpClipboard , aynı özellikleri tek bir ince bileşen kitaplığında kapsüllediğinden daha yararlı olabilir. Daha sonra ClipboardChangedolayına erişebilir ve kesildiklerinde / kopyalandıklarında çeşitli veri formatlarını tespit edebilirsiniz .
Willy Kimura

78

Tamlık için, işte üretim kodunda kullandığım denetim. Tasarımcıdan sürükleyin ve olay işleyicisini oluşturmak için çift tıklayın.

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
İyi iş! Yine de olay çağıran kodunuz iş parçacığı açısından güvenli değildir. Ya yerel bir kopya oluşturmalı ya da olayı boş bir temsilciyle başlatmalısınız. Ayrıca :) ClipboardChanged tanımındaki 'olay' anahtar kelimesini unuttum
Ohad Schneider

1
@ohadsc Düzeltmeler için teşekkürler. Bildiğim kadarıyla, WndProc UI iş parçacığında çağrılıyor. Sınıf Control'den türetildiğinden, istemciler onu UI iş parçacığında da çağırmalıdır.
dbkk

Yalnızca ilk açılan formda çalışır ... mesela MyForm1 ve myForm2'ye sahipsem, bu yüzden myForm1'i, ardından MyForm2'yi açarsam, ClipboardChanged olayı yalnızca MyForm1'de yükseltilecek ... Yani, bir MDI uygulamasında ...
serhio

Her nasılsa SetClipboardViewer çağrınız Win32 Hata Kodu 1400'ü ayarlıyor: "Geçersiz pencere tanıtıcısı." Ama yine de çalışıyor. Bu bana biraz garip geliyor.
metacircle

1
Bir kitaplık olarak SharpClipboard , aynı özellikleri tek bir ince bileşen kitaplığında kapsüllediğinden daha yararlı olabilir. Daha sonra ClipboardChangedolayına erişebilir ve kesildiklerinde / kopyalandıklarında çeşitli veri formatlarını tespit edebilirsiniz .
Willy Kimura

26

WPF'de bu zorluğu yaşadım ve aşağıda açıklanan yaklaşımı kullanarak sona erdi. Windows formları için, bu yanıtın başka bir yerinde ClipboardHelper denetimi gibi mükemmel örnekler vardır.

WPF için WndProc'u geçersiz kılamayız, bu yüzden onu bir pencereden Kaynak'ı kullanarak bir HwndSource AddHook çağrısıyla açıkça bağlamamız gerekir. Pano dinleyicisi hala AddClipboardFormatListener yerel birlikte çalışma çağrısını kullanır.

Yerel yöntemler:

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

Clipboard Manager sınıfı:

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

Bu, olayı OnSourceInitialized'a veya daha sonra Window.Loaded olayı gibi ekleyerek veya işlem sırasında WPF penceresinde kullanılır. (yerel kancaları kullanmak için yeterli bilgiye sahip olduğumuzda):

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

Bu yaklaşımı, Ctrl-C tuşlarına bastığınızda oyun pano aracılığıyla öğe bilgilerini ifşa ettiğinden, Path of Exile öğe analizörü projesinde kullanıyorum.

https://github.com/ColinDabritz/PoeItemAnalyzer

Umarım bu, WPF pano değişikliği işlemine sahip birine yardımcı olur!


1
Birisi C # 6'da Yeni Sıfır Koşullu İşleci KullanmayıClipboardChanged?.Invoke görmenin ne anlama geldiğini bilmiyorsa , Diğer Senaryolar bölümü
marbel82

11

Tamam, bu eski bir gönderi ancak mevcut cevap setine kıyasla çok basit görünen bir çözüm bulduk. WPF kullanıyoruz ve Pano metin içeriyorsa kendi özel Komutlarımızın (bir Bağlam Menüsünde) etkinleştirilmesini ve devre dışı bırakılmasını istedik. Zaten bir ApplicationCommands.Cut, Copy and Paste var ve bu komutlar pano değişimine doğru şekilde yanıt veriyor. Bu yüzden aşağıdaki EventHandler'ı ekledik.

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

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

Aslında CanExecute'u bu şekilde kendi Komutumuzla kontrol ediyoruz. İhtiyacımız olan şey için çalışıyor ve belki oradaki diğerlerine yardımcı olabilir.


Harika çözüm, çünkü çok basit ... Teşekkürler!
okieh

1
Bu, yapıştırma komutunu etkinleştirme veya devre dışı bırakma sorununa harika bir çözümdür. Ne yazık ki, belirli "değiştirilen metin" senaryosunu kapsamaz ve örneğin, birden çok farklı satır metni kopyalarken çalışmaz.
Colin Däbritz

11

Bunu yapmanın birçok yolu var ama bu benim favorim ve benim için çalışıyor. Başkalarının projeyi ekleyebilmesi ve DLL'yi dahil edebilmesi için bir sınıf kitaplığı oluşturdum, ardından sadece onu çağırıp uygulamalarında istedikleri yerde kullanabilirler.

Bu cevap yardımıyla yapıldığı bu bir .

  1. Sınıf Kitaplığı projesi oluşturun ve bunu ClipboardHelper olarak adlandırın.
  2. Class1 adını ClipboardMonitor ile değiştirin.
  3. Aşağıdaki kodu içine ekleyin.
  4. System.Windows.Forms başvurusu ekleyin.

Kod altında daha fazla adım.

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. Diğer projelerinizde çözüme sağ tıklayın ve Ekle -> Projeden Çıkılıyor -> ClipboardHelper.csproj
  2. Projenizde Referanslar -> Referans Ekle -> Çözüm -> ClipboardHelper'ı seçin ve sağ tıklayın.
  3. ClipboardHelper kullanarak proje türündeki sınıf dosyanızda.
  4. Şimdi ClipboardMonitor.Start veya .Stop veya .OnClipboardChanged yazabilirsiniz.

    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

Bir kitaplık olarak SharpClipboard , aynı özellikleri tek bir ince bileşen kitaplığında kapsüllediğinden daha yararlı olabilir. Daha sonra ClipboardChangedolayına erişebilir ve kesildiklerinde / kopyalandıklarında çeşitli veri formatlarını tespit edebilirsiniz .

İzlemek istediğiniz çeşitli veri formatlarını seçebilirsiniz:

var clipboard = new SharpClipboard();

clipboard.ObservableFormats.Texts = true;
clipboard.ObservableFormats.Files = true;
clipboard.ObservableFormats.Images = true;
clipboard.ObservableFormats.Others = true;

İşte ClipboardChangedolayını kullanan bir örnek :

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

Kes / kopyala olayının meydana geldiği uygulamayı detayları ile birlikte öğrenebilirsiniz:

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

MonitorChangedPano izleme devre dışı bırakıldığında dinleyen olay gibi başka olaylar da vardır; bu , çalışma zamanında panoyu izlemeyi etkinleştirebileceğiniz veya devre dışı bırakabileceğiniz anlamına gelir.

Tüm bunlara ek olarak, bir bileşen olduğu için, bunu Tasarımcı Görünümünde bir Windows Formuna sürükleyip bırakarak kullanabilirsiniz, bu da herkesin seçeneklerini özelleştirmesini ve dahili olaylarıyla çalışmasını çok kolaylaştırır.

SharpClipboard, .NET'teki pano izleme senaryoları için en iyi seçenek gibi görünüyor.


6

Önceki çözümlerden birinin dispose yönteminde bir boşluğu kontrol etmediğine inanıyorum:

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

Asla boş değildir çünkü kurucu onu ayarlar. Farklı yapacağım tek şey base.Dispose(), dispose yönteminde çağrı yapmaktır .
jedmao

Her neyse. Listelediğiniz gibi doğrulama amaçları için, IntPtr.Zero for NULL kullanmalısınız (bunun C # null ile eşdeğer olmadığını unutmayın) stackoverflow.com/questions/1456861/…
walter

1
ChangeClipboardChain tüm msdn örneklerinde her zaman çıkışta çalıştırılır
walter

Amaç, kendisini pano görüntüleyici zincirinden çıkarmak
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;
            }
        }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.