我正在编写一个 Windows 窗体应用程序,该应用程序可以自动化旧软件。为了在该软件和我的应用程序之间传输信息,我使用剪贴板。单击旧软件上的按钮会将一些信息放入剪贴板。
对于使用 Clipboard.GetText 我应该从 Windows 窗体中调用它。但我不希望一切都在 UI 线程上。
在另一个任务中调用 Clipboard.GetText 时,我得到它说你应该从 STAThread 调用 Clipboard.GetText。
你将不得不改变你的期望。标准要求是只有 UI 线程与剪贴板交互。
从技术上讲,正如文档中所述,实际要求是只有单线程单元(STA)线程可以访问剪贴板。由于大多数后台线程(如 .NET 中的 ThreadPool 类创建的线程)都是多线程单元 (MTA) 线程,因此它们无法访问剪贴板。您可以通过手动创建自己的 STA 线程并在其上运行消息泵来解决此问题,但仅使用 UI 线程要容易得多,所以每个人都这样做。
然而,一开始尝试使用剪贴板在两个进程之间共享信息是一个糟糕的设计。剪贴板供“用户”存储信息。您写入剪贴板的任何内容都会破坏用户存储在那里的任何内容。如果你的应用程序这样做,并覆盖了我想保留的东西,我会对你非常愤怒。 进程之间有更好的通信方式;搜索“进程间通信”(缩写为“IPC”)以获取各种想法。
Clipboard.GetText
回调从工作线程编组回 UI 线程来实现(假设您有 Form
或任何其他可用的 Control
- 在
ctrl
变量中)://Do something
Func<string> getClipboardText = delegate() { return Clipboard.GetText(); };
string clipboardText = (string)ctrl.Invoke(getClipboardText);
//Do something else
如果您不想使用 Windows.Forms 或 Wpf 剪贴板,您可以调用原生剪贴板 api,如下所示: 如何在控制台应用程序中将字符串复制到剪贴板而不添加对 System.Windows.Forms 的引用?
从剪贴板获取字符串的示例
OpenClipboard(IntPtr.Zero);
var ptr = GetClipboardData(13);
var s = Marshal.PtrToStringUni(ptr);
Marshal.FreeHGlobal(ptr);
CloseClipboard();
我使用 13 作为剪贴板类型(CF_UNICODETEXT)
您可以在这里看到完整列表:
// Init the Output Variable:
string Output = string.Empty;
// Run inside a Task:
await Task.Run(() =>
{
Thread thread = new Thread(() =>
{
Output = Clipboard.GetText(TextDataFormat.Text);
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
});