25

我已经尝试过如何在 C# 中将数据复制到剪贴板中的代码:

Clipboard.SetText("Test!");

我得到这个错误:

在进行 OLE 调用之前,必须将当前线程设置为单线程单元 (STA) 模式。确保您的Main功能已STAThreadAttribute在其上标记。

我该如何解决?

4

4 回答 4

51

如果您无法控制线程是否在 STA 模式下运行(即测试、插件到某个其他应用程序,或者只是一些随机发送该调用以在无 UI 线程上运行的代码,并且您无法将Control.Invoke其发送回主 UI 线程)比您可以在专门配置为处于STA剪贴板访问所需状态的线程上运行剪贴板访问(内部使用实际上需要 STA 的 OLE)。

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
于 2013-07-20T12:01:23.937 回答
19

确保运行代码的线程标有 [STAThread] 属性。对于 WinForm 和基于控制台的应用程序,它通常是Main方法

放在[STAThread]你的主要方法之上:

[STAThread]
static void Main()
{
}

对于 WinForms,它通常位于生成的 Main.cs 文件中,您可以在必要时对其进行编辑(更改时不会重新生成)。对于控制台,它是您定义的Main.

如果您无法控制线程(即您正在编写库或主应用程序由于某种原因被锁定),您可以运行代码来访问专门配置的线程(.SetApartmentState(ApartmentState.STA))上的剪贴板,如另一个答案所示。

于 2013-07-20T12:01:16.733 回答
12

您只能从 STAThread 访问剪贴板。

解决这个问题的最快方法是放在[STAThread]你的Main()方法之上,但如果由于某种原因你不能这样做,你可以使用一个单独的类来创建一个 STAThread 为你设置/获取字符串值。

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;
    }
}
于 2018-07-05T08:18:16.943 回答
0

这个问题已有 8 年历史了,但许多人仍然需要解决方案。

正如其他人所提到的,必须从主线程或 [STAThread] 调用剪贴板。

好吧,我每次都使用这种解决方法。也许它可以是一个替代方案。

public static void SetTheClipboard()
{
    Thread t = new Thread(() => {
        Clipboard.SetText("value in clipboard");
    });

    t.SetApartmentState(ApartmentState.STA);
    t.Start();
    t.Join();

    await Task.Run(() => {
        // use the clipboard here in another thread. Also can be used in another thread in another method.
    });
}

剪贴板值是在 t 线程中创建的。

关键是:线程t单元设置为STA状态。

稍后您可以根据需要在其他线程中使用剪贴板值。

希望你能明白这一点。

于 2021-05-03T09:56:46.660 回答