303

If I have some text in a String, how can I copy that to the clipboard so that the user can paste it into another window (for example, from my application to Notepad)?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Elie
  • 13,693
  • 23
  • 74
  • 128
  • 5
    without winforms or wpf: http://stackoverflow.com/a/13571530/359135 –  Oct 12 '13 at 13:06

8 Answers8

392

You can use System.Windows.Forms.Clipboard.SetText(...).

bluish
  • 26,356
  • 27
  • 122
  • 180
ravuya
  • 8,586
  • 4
  • 30
  • 33
177

System.Windows.Forms.Clipboard.SetText (Windows Forms) or System.Windows.Clipboard.SetText (WPF)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jeff Moser
  • 19,727
  • 6
  • 65
  • 85
70

I wish calling SetText were that easy but there are quite a few gotchas that you have to deal with. You have to make sure that the thread you are calling it on is running in the STA. It can sometimes fail with an access denied error then work seconds later without problem - something to do with the COM timing issues in the clipboard. And if your application is accessed over Remote Desktop access to the clipboard is sketchy. We use a centralized method to handle all theses scenarios instead of calling SetText directly.

@Stecy: Here's our centralized code:

The StaHelper class simply executes some arbitrary code on a thread in the Single Thread Apartment (STA) - required by the clipboard.

abstract class StaHelper
{
    readonly ManualResetEvent _complete = new ManualResetEvent( false );    

    public void Go()
    {
        var thread = new Thread( new ThreadStart( DoWork ) )
        {
            IsBackground = true,
        }
        thread.SetApartmentState( ApartmentState.STA );
        thread.Start();
    }

    // Thread entry method
    private void DoWork()
    {
        try
        {
            _complete.Reset();
            Work();
        }
        catch( Exception ex )
        {
            if( DontRetryWorkOnFailed )
                throw;
            else
            {
                try
                {
                    Thread.Sleep( 1000 );
                    Work();
                }
                catch
                {
                    // ex from first exception
                    LogAndShowMessage( ex );
                }
            }
        }
        finally
        {
            _complete.Set();
        }
    }

    public bool DontRetryWorkOnFailed{ get; set; }

    // Implemented in base class to do actual work.
    protected abstract void Work();
}

Then we have a specific class for setting text on the clipboard. Creating a DataObject manually is required in some edge cases on some versions of Windows/.NET. I don't recall the exact scenarios now and it may not be required in .NET 3.5.

class SetClipboardHelper : StaHelper
{
    readonly string _format;
    readonly object _data;

    public SetClipboardHelper( string format, object data )
    {
        _format = format;
        _data = data;
    }

    protected override void Work()
    {
        var obj = new System.Windows.Forms.DataObject(
            _format,
            _data
        );

        Clipboard.SetDataObject( obj, true );
    }
}

Usage looks like this:

new SetClipboardHelper( DataFormats.Text, "See, I'm on the clipboard" ).Go();
Noctis
  • 11,507
  • 3
  • 43
  • 82
Paul Alexander
  • 31,970
  • 14
  • 96
  • 151
  • 4
    +1, I've experienced at least some of these gotchas. It's worked OK for me if I wrap the clipboard access in try { ...} catch (System.Runtime.InteropServices.ExternalException) { }. – Joe May 22 '09 at 19:35
  • 1
    @Paul, would you be so kind to explain your centralized method? – Stécy Jan 27 '10 at 15:57
  • 3
    This answer deserves far more upvotes than it has. Additionally, you should make a self answered question, something like "How to run STA code in a non-STA context" – Sidney Feb 19 '16 at 22:02
  • 2
    Here I am, a year and a half later with almost no memory of this issue from 2/19/16, once again copying this class. – Sidney Oct 16 '17 at 20:30
  • What is DataFormats ? – Kiquenet Apr 08 '19 at 11:36
  • I've closed this one as duplicate of https://stackoverflow.com/questions/3546016/how-to-copy-data-to-clipboard-in-c-sharp/34077334#34077334. Consider moving your answer there (and see if at the same time you can modernize it for `Task`/`async`/`await` if interested). – Alexei Levenkov Dec 03 '19 at 03:32
28

WPF: System.Windows.Clipboard (PresentationCore.dll)

Winforms: System.Windows.Forms.Clipboard

Both have a static SetText method.

bluish
  • 26,356
  • 27
  • 122
  • 180
bsneeze
  • 4,369
  • 25
  • 20
  • Thank you for the inclusion of PresentationCore.dll reference. Not included by default in console application – xtreampb Nov 01 '16 at 18:31
18

This works for me:

You want to do:

System.Windows.Forms.Clipboard.SetText("String to be copied to Clipboard");

But it causes an error saying it must be in a single thread of ApartmentState.STA.

So let's make it run in such a thread. The code for it:

public void somethingToRunInThread()
{
    System.Windows.Forms.Clipboard.SetText("String to be copied to Clipboard");
}

protected void copy_to_clipboard()
{
    Thread clipboardThread = new Thread(somethingToRunInThread);
    clipboardThread.SetApartmentState(ApartmentState.STA);
    clipboardThread.IsBackground = false;
    clipboardThread.Start();
}

After calling copy_to_clipboard(), the string is copied into the clipboard, so you can Paste or Ctrl + V and get back the string as String to be copied to the clipboard.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
benli1212
  • 181
  • 1
  • 2
15

Using the solution showed in this question, System.Windows.Forms.Clipboard.SetText(...), results in the exception:

Current thread must be set to single thread apartment (STA) mode before OLE calls can be made

To prevent this, you can add the attribute:

[STAThread]

to

static void Main(string[] args)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Leroy
  • 318
  • 2
  • 7
8

In Windows Forms, if your string is in a textbox, you can easily use this:

textBoxcsharp.SelectAll();
textBoxcsharp.Copy();
textBoxcsharp.DeselectAll();
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Magnetic_dud
  • 1,506
  • 2
  • 22
  • 36
  • 2
    you don't need to put in all the select and deslect junk. Just simply put this in: `textBox1.Copy();` – Dozer789 Feb 15 '14 at 20:15
  • 4
    Actually, you do need the SelectAll() and DeselectAll() junk. According to https://msdn.microsoft.com/en-us/library/system.windows.forms.textboxbase.copy(v=vs.120).aspx what gets copied to the clipboard is the **currently selected** text. – G. Stewart Apr 12 '16 at 12:40
  • 3
    you need to put SelectAll(), otherwise it doesn't work, I just [tried in this useless app](https://github.com/Magneticdud/Paginatore/commit/5b58a89bf947c1be345861e2adbadf3270ad88f7). There's no need to use DeselectAll() in WPF apps though. – Magnetic_dud Apr 13 '16 at 17:45
  • I like this because it keeps you from having to add STA attributes to your class. I just wanted this during some debugging, and I didn't to alter other parts of my code just to get something to the keyboard buffer. – MattSlay Apr 14 '19 at 23:07
-2

Use try-catch, even if it has an error it will still copy.

Try
   Clipboard.SetText("copy me to clipboard")
Catch ex As Exception

End Try

If you use a message box to capture the exception, it will show you error, but the value is still copied to clipboard.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • Are you sure about that? Have you tried it a number of times, e.g. 10 times? Perhaps you were just lucky? Wouldn't a retry be required in general (as a workaround)? – Peter Mortensen Mar 17 '19 at 18:35