Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Current thread must be set to single thread apartment (STA)" error in copy string to clipboard

Tags:

c#

clipboard

I have tried code from How to copy data to clipboard in C#:

Clipboard.SetText("Test!");

And I get this error:

Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it.

How can I fix it?

like image 711
user1823701 Avatar asked Jul 20 '13 11:07

user1823701


3 Answers

If you can't control whether thread runs in STA mode or not (i.e. tests, plugin to some other app or just some code that randomly sends that call to run on no-UI thread and you can't use Control.Invoke to send it back to main UI thread) than you can run clipboard access on thread specifically configured to be in STA state which is required for clipboard access (which internally uses OLE that actually requires STA).

Thread thread = new Thread(() => Clipboard.SetText("Test!"));
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start(); 
thread.Join(); //Wait for the thread to end
like image 85
It'sNotALie. Avatar answered Dec 22 '22 07:12

It'sNotALie.


Make sure thread that runs the code is marked with [STAThread] attribute. For WinForm and console based apps it is generally Main method

Put [STAThread] above your main method:

[STAThread]
static void Main()
{
}

For WinForms it is usually in generated Main.cs file that you can edit if necessary (it will not be re-generated on changes). For console it's were you define the Main.

If you can't control the thread (i.e. you are writing a library or main app is locked by some reason) you can instead run code that accesses clipboard on specially configured thread (.SetApartmentState(ApartmentState.STA)) as shown in another answer.

like image 39
Thousand Avatar answered Dec 22 '22 08:12

Thousand


You can only access the clipboard from an STAThread.

The quickest way to solve this is to put [STAThread] on top of your Main() method, but if for whatever reason you cannot do that you can use a separate class that creates an STAThread set/get the string value for to you.

public static class Clipboard
{
    public static void SetText(string p_Text)
    {
        Thread STAThread = new Thread(
            delegate ()
            {
                // Use a fully qualified name for Clipboard otherwise it
                // will end up calling itself.
                System.Windows.Forms.Clipboard.SetText(p_Text);
            });
        STAThread.SetApartmentState(ApartmentState.STA);
        STAThread.Start();
        STAThread.Join();
    }
    public static string GetText()
    {
        string ReturnValue = string.Empty;
        Thread STAThread = new Thread(
            delegate ()
            {
                // Use a fully qualified name for Clipboard otherwise it
                // will end up calling itself.
                ReturnValue = System.Windows.Forms.Clipboard.GetText();
            });
        STAThread.SetApartmentState(ApartmentState.STA);
        STAThread.Start();
        STAThread.Join();

        return ReturnValue;
    }
}
like image 35
GDavoli Avatar answered Dec 22 '22 07:12

GDavoli