如何在非主线程中获取剪贴板数据?
How to get clipboard data in non main thread?
我正在尝试使用以下代码从剪贴板获取数据。
private void TestBtn_Click(object sender, EventArgs e)
{
Thread sampleThread = new Thread(SampleMethod);
sampleThread.IsBackground = true;
sampleThread.Start();
Thread.Sleep(2000);
var textFromMain = Clipboard.GetText(TextDataFormat.Text);
}
private void SampleMethod()
{
var textFromThread = Clipboard.GetText(TextDataFormat.Text);
Thread.Sleep(1000);
}
我正在使用此行将任何文本复制到剪贴板 -
var textFromMain = Clipboard.GetText(TextDataFormat.Text);
但在第 returns 行下面是空字符串或空白字符串。
var textFromThread = Clipboard.GetText(TextDataFormat.Text);
我不明白这是怎么回事。有人可以帮助我理解。如果是多线程,请指出正确的方向。
Clipboard.GetText(TextDataFormat.Text)
使用 COM 并抛出 exception 如果在未标记 STAThreadAttribute
.
的线程中调用
一种解决方法是使用委托将 Clipboard.GetText
的 return 调用委托给带有 Invoke 的主线程。但在这种情况下,线程将冻结它在 Invoke 上的执行,直到 SampleMethod()
结束它在主窗体线程上的执行,并且主线程将空闲。
其他方法是使用自己调用 COM 来获取剪贴板文本而不是 System.Windows.Forms.Clipboard.GetText()
,请参阅 ClipboardCom.GetText()
,此方法不需要等待主窗体线程。
private string _textFromMain, _textFromThreadByInvoke, _textFromThreadByCom;
private delegate string GetClipboardInvoke(TextDataFormat textformat);
private void SampleInvokeMethod()
{
GetClipboardInvoke invokerClipboard = new GetClipboardInvoke(Clipboard.GetText);
_textFromThreadByInvoke = (string)this.Invoke(invokerClipboard, TextDataFormat.Text); // where this is a Form
Thread.Sleep(1000);
}
private void button1_Click(object sender, EventArgs e)
{
Thread sampleInvokeThread = new Thread(SampleInvokeMethod) { IsBackground = true };
sampleInvokeThread.Start();
Thread sampleComThread = new Thread(SampleComMethod) { IsBackground = true };
sampleComThread.Start();
Thread.Sleep(10000);
_textFromMain = Clipboard.GetText(TextDataFormat.Text);
}
private void SampleComMethod()
{
_textFromThreadByCom = ClipboardCom.GetText();
Thread.Sleep(1000);
}
public static class ClipboardCom
{
[DllImport("user32.dll")]
static extern IntPtr GetClipboardData(uint uFormat);
[DllImport("user32.dll")]
static extern bool IsClipboardFormatAvailable(uint format);
[DllImport("user32.dll", SetLastError = true)]
static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll", SetLastError = true)]
static extern bool CloseClipboard();
[DllImport("kernel32.dll")]
static extern IntPtr GlobalLock(IntPtr hMem);
[DllImport("kernel32.dll")]
static extern bool GlobalUnlock(IntPtr hMem);
const uint CF_UNICODETEXT = 13;
public static string GetText()
{
if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
return null;
if (!OpenClipboard(IntPtr.Zero))
return null;
string data = null;
var hGlobal = GetClipboardData(CF_UNICODETEXT);
if (hGlobal != IntPtr.Zero)
{
var lpwcstr = GlobalLock(hGlobal);
if (lpwcstr != IntPtr.Zero)
{
data = Marshal.PtrToStringUni(lpwcstr);
GlobalUnlock(lpwcstr);
}
}
CloseClipboard();
return data;
}
}
我终于用下面的方法访问剪贴板文本了。
private string GetClipBoradData()
{
try
{
string clipboardData= null;
Exception threadEx = null;
Thread staThread = new Thread(
delegate ()
{
try
{
clipboardData= Clipboard.GetText(TextDataFormat.Text);
}
catch (Exception ex)
{
threadEx = ex;
}
});
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();
return clipboardData;
}
catch (Exception exception)
{
return string.Empty;
}
}
以下代码对我有用。
Thread theThread = new Thread((ThreadStart)delegate
{
var selectedPodcastPlaylist = (PodcastPlaylist)metroGridPodcastPlaylist.SelectedRows[0].DataBoundItem;
Clipboard.SetText(selectedPodcastPlaylist.URI);
});
try
{
//set STA as the Open file dialog needs it to work
theThread.TrySetApartmentState(ApartmentState.STA);
//start the thread
theThread.Start();
// Wait for thread to get started
while (!theThread.IsAlive) { Thread.Sleep(1); }
// Wait a tick more (@see: http://scn.sap.com/thread/45710)
Thread.Sleep(1);
//wait for the dialog thread to finish
theThread.Join();
}
catch (Exception)
{
}
灵感来自此处的文章和来源
Thread Apartment Safe Open/Save File Dialogs for C#
我正在尝试使用以下代码从剪贴板获取数据。
private void TestBtn_Click(object sender, EventArgs e)
{
Thread sampleThread = new Thread(SampleMethod);
sampleThread.IsBackground = true;
sampleThread.Start();
Thread.Sleep(2000);
var textFromMain = Clipboard.GetText(TextDataFormat.Text);
}
private void SampleMethod()
{
var textFromThread = Clipboard.GetText(TextDataFormat.Text);
Thread.Sleep(1000);
}
我正在使用此行将任何文本复制到剪贴板 -
var textFromMain = Clipboard.GetText(TextDataFormat.Text);
但在第 returns 行下面是空字符串或空白字符串。
var textFromThread = Clipboard.GetText(TextDataFormat.Text);
我不明白这是怎么回事。有人可以帮助我理解。如果是多线程,请指出正确的方向。
Clipboard.GetText(TextDataFormat.Text)
使用 COM 并抛出 exception 如果在未标记 STAThreadAttribute
.
一种解决方法是使用委托将 Clipboard.GetText
的 return 调用委托给带有 Invoke 的主线程。但在这种情况下,线程将冻结它在 Invoke 上的执行,直到 SampleMethod()
结束它在主窗体线程上的执行,并且主线程将空闲。
其他方法是使用自己调用 COM 来获取剪贴板文本而不是 System.Windows.Forms.Clipboard.GetText()
,请参阅 ClipboardCom.GetText()
,此方法不需要等待主窗体线程。
private string _textFromMain, _textFromThreadByInvoke, _textFromThreadByCom;
private delegate string GetClipboardInvoke(TextDataFormat textformat);
private void SampleInvokeMethod()
{
GetClipboardInvoke invokerClipboard = new GetClipboardInvoke(Clipboard.GetText);
_textFromThreadByInvoke = (string)this.Invoke(invokerClipboard, TextDataFormat.Text); // where this is a Form
Thread.Sleep(1000);
}
private void button1_Click(object sender, EventArgs e)
{
Thread sampleInvokeThread = new Thread(SampleInvokeMethod) { IsBackground = true };
sampleInvokeThread.Start();
Thread sampleComThread = new Thread(SampleComMethod) { IsBackground = true };
sampleComThread.Start();
Thread.Sleep(10000);
_textFromMain = Clipboard.GetText(TextDataFormat.Text);
}
private void SampleComMethod()
{
_textFromThreadByCom = ClipboardCom.GetText();
Thread.Sleep(1000);
}
public static class ClipboardCom
{
[DllImport("user32.dll")]
static extern IntPtr GetClipboardData(uint uFormat);
[DllImport("user32.dll")]
static extern bool IsClipboardFormatAvailable(uint format);
[DllImport("user32.dll", SetLastError = true)]
static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll", SetLastError = true)]
static extern bool CloseClipboard();
[DllImport("kernel32.dll")]
static extern IntPtr GlobalLock(IntPtr hMem);
[DllImport("kernel32.dll")]
static extern bool GlobalUnlock(IntPtr hMem);
const uint CF_UNICODETEXT = 13;
public static string GetText()
{
if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
return null;
if (!OpenClipboard(IntPtr.Zero))
return null;
string data = null;
var hGlobal = GetClipboardData(CF_UNICODETEXT);
if (hGlobal != IntPtr.Zero)
{
var lpwcstr = GlobalLock(hGlobal);
if (lpwcstr != IntPtr.Zero)
{
data = Marshal.PtrToStringUni(lpwcstr);
GlobalUnlock(lpwcstr);
}
}
CloseClipboard();
return data;
}
}
我终于用下面的方法访问剪贴板文本了。
private string GetClipBoradData()
{
try
{
string clipboardData= null;
Exception threadEx = null;
Thread staThread = new Thread(
delegate ()
{
try
{
clipboardData= Clipboard.GetText(TextDataFormat.Text);
}
catch (Exception ex)
{
threadEx = ex;
}
});
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();
return clipboardData;
}
catch (Exception exception)
{
return string.Empty;
}
}
以下代码对我有用。
Thread theThread = new Thread((ThreadStart)delegate
{
var selectedPodcastPlaylist = (PodcastPlaylist)metroGridPodcastPlaylist.SelectedRows[0].DataBoundItem;
Clipboard.SetText(selectedPodcastPlaylist.URI);
});
try
{
//set STA as the Open file dialog needs it to work
theThread.TrySetApartmentState(ApartmentState.STA);
//start the thread
theThread.Start();
// Wait for thread to get started
while (!theThread.IsAlive) { Thread.Sleep(1); }
// Wait a tick more (@see: http://scn.sap.com/thread/45710)
Thread.Sleep(1);
//wait for the dialog thread to finish
theThread.Join();
}
catch (Exception)
{
}
灵感来自此处的文章和来源 Thread Apartment Safe Open/Save File Dialogs for C#