如何使用 Clipboard.GetText 使用任务?

How to use Clipboard.GetText using a Task?

我正在编写一个 Windows 表单应用程序来自动化一个旧软件。为了在该软件和我的应用程序之间传输信息,我使用剪贴板。单击旧软件上的按钮会将一些信息放入剪贴板。

为了使用 Clipboard.GetText 我应该从 windows 形式调用它。但我不想 UI 线程上的所有内容。

在另一个任务中调用 Clipboard.GetText 时,我得到它说你应该从 STAThread 调用 Clipboard.GetText。

你将不得不改变你的期望。标准要求只有 UI 线程与剪贴板交互。

从技术上讲,如文档中所述,实际要求是只有 single-threaded apartment (STA) threads 可以访问剪贴板。因为大多数后台线程,如 .NET 中 ThreadPool class 创建的线程,都是多线程单元 (MTA) 线程,它们无法访问剪贴板。您可以通过手动创建自己的 STA 线程和 运行 消息泵来解决此问题,但仅使用 UI 线程要容易得多,所以每个人都这样做。

但是,尝试使用剪贴板在两个进程之间共享信息是一个糟糕的设计。剪贴板是为 用户 存储信息而设计的。您写入剪贴板的任何内容都会破坏用户存储在那里的任何内容。如果你的应用程序这样做,并覆盖了我想保留的东西,我会非常生你的气。

进程之间有更好的通信方式;搜索 "interprocess communication"(缩写为 "IPC")以获取各种想法。

如果您不想使用 Windows.Forms 或 Wpf 剪贴板,您可以调用本机剪贴板 api,如下所示:

How can I copy a string to clipboard within my console app WITHOUT adding a reference to System.Windows.Forms?

从剪贴板获取字符串的示例

        OpenClipboard(IntPtr.Zero);

        var ptr = GetClipboardData(13);
        var s = Marshal.PtrToStringUni(ptr);
        Marshal.FreeHGlobal(ptr);
        CloseClipboard();

我使用 13 作为剪贴板类型 (CF_UNICODETEXT) 您可以在此处看到的完整列表: https://msdn.microsoft.com/de-de/library/windows/desktop/ff729168(v=vs.85).aspx

您的 UI 话题是 STA。但这并不意味着您必须在 UI 线程中执行 all 您的逻辑。您可以在后台执行 UI 行之外的所有行。这可以通过将你的 Clipboard.GetText 回调从你的工作线程编组回 UI 线程来实现(假设你有一个 Form 或任何其他 Control 可用 - 在 ctrl变量):

//Do something
Func<string> getClipboardText = delegate() { return Clipboard.GetText(); };
string clipboardText = (string)ctrl.Invoke(getClipboardText);
//Do something else