异常信息“OpenClipboard HRESULT:0x800401D0 (CLIPBRD_E_CANT_OPEN
WPF本身对Clipboard处理的问题,在.Net4.0及之前的版本中都有问题,在.Net4.5中修复了,但XP下安装不了.NET4.5,而我的程序又必须在XP下运行。
问题主要是由于:在程序访问剪切板的时候,有其他程序正在占用剪切板,导致自己的程序无法访问,从而抛出异常。
自行截获异常,进行处理
for (int i = 0; i < 10; i++)
{
try
{
Clipboard.SetText(lineTexts[lineIndex]);
break;
}
catch
{
System.Threading.Thread.Sleep(10);//这句加不加都没关系
}
}
这种方法处理过程中UI会有一小段时间的假死。。。可以考虑多线程?
2. 换一种方式设置剪切板
Clipboard.SetDataObject(lineTexts[lineIndex]);
就这一句。。。这种方法不会抛异常,UI也没有假死,非常正常!估计SetDataObject方法跟SetText方法的实现不一样,没有细究。。。
3. 跟方法1类似,不过有点高级
剪切板处理的那句代码不变,还是使用SetText方法。
在App.xaml文件中添加下面代码中红色的部分
xmlns="/winfx//xaml/presentation"
xmlns:x="/winfx//xaml"
StartupUri="MainWindow.xaml"
DispatcherUnhandledException="Application_DispatcherUnhandledException">
在App.xaml.cs文件中添加代码:
void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
var comException = e.Exception as System.Exception;
if (comException != null && comException.ErrorCode == -2147221040)///OpenClipboard HRESULT:0x800401D0 (CLIPBRD_E_CANT_OPEN))
e.Handled = true;
}
4.使用winform剪贴板
System.Windows.Forms.Clipboard.SetText(txt2.Text);
看一下WinForm和WPF的代码
WinForm的SetText()最终会调用SetDataObject(data, copy, 10, 100),这个是SetDataObject()的签名:
[UIPermission(SecurityAction.Demand, Clipboard=UIPermissionClipboard.OwnClipboard)]
public static void SetDataObject(object data, bool copy, int retryTimes, int retryDelay)
{
if (Application.OleRequired() != ApartmentState.STA)
{
throw new ThreadStateException(SR.GetString("ThreadMustBeSTA"));
}
if (data == null)
{
throw new ArgumentNullException("data");
}
if (retryTimes < 0)
{
object[] args = new object[] { "retryTimes", retryTimes.ToString(CultureInfo.CurrentCulture), 0.ToString(CultureInfo.CurrentCulture) };
throw new ArgumentOutOfRangeException("retryTimes", SR.GetString("InvalidLowBoundArgumentEx", args));
}
if (retryDelay < 0)
{
object[] objArray2 = new object[] { "retryDelay", retryDelay.ToString(CultureInfo.CurrentCulture), 0.ToString(CultureInfo.CurrentCulture) };
throw new ArgumentOutOfRangeException("retryDelay", SR.GetString("InvalidLowBoundArgumentEx", objArray2));
}
DataObject obj2 = null;
if (!(data is IDataObject))
{
obj2 = new DataObject(data);
}
bool flag = false;
try
{
IntSecurity.ClipboardRead.Demand();
}
catch (SecurityException)
{
flag = true;
}
if (flag)
{
if (obj2 == null)
{
obj2 = data as DataObject;
}
if (!IsFormatValid(obj2))
{
throw new SecurityException(SR.GetString("ClipboardSecurityException"));
}
}
if (obj2 != null)
{
obj2.RestrictedFormats = flag;
}
int num2 = retryTimes;
IntSecurity.UnmanagedCode.Assert();
try
{
int num;
do
{
if (data is IDataObject)
{
num = UnsafeNativeMethods.OleSetClipboard((IDataObject) data);
}
else
{
num = UnsafeNativeMethods.OleSetClipboard(obj2);
}
if (num != 0)
{
if (num2 == 0)
{
ThrowIfFailed(num);
}
num2--;
Thread.Sleep(retryDelay);
}
}
while (num != 0);
if (copy)
{
num2 = retryTimes;
do
{
num = UnsafeNativeMethods.OleFlushClipboard();
if (num != 0)
{
if (num2 == 0)
{
ThrowIfFailed(num);
}
num2--;
Thread.Sleep(retryDelay);
}
}
while (num != 0);
}
}
finally
{
CodeAccessPermission.RevertAssert();
}
}
而WPF的SetText(),虽然签名一样,但是具有完全不同的实现:
[SecurityCritical]
public static void SetDataObject(object data, bool copy)
{
SecurityHelper.DemandAllClipboardPermission();
CriticalSetDataObject(data, copy);
}
[FriendAccessAllowed, SecurityCritical]
internal static void CriticalSetDataObject(object data, bool copy)
{
IDataObject obj2;
if (data == null)
{
throw new ArgumentNullException("data");
}
if (data is DataObject)
{
obj2 = (DataObject) data;
}
else if (data is IDataObject)
{
SecurityHelper.DemandUnmanagedCode();
obj2 = (IDataObject) data;
}
else
{
obj2 = new DataObject(data);
}
int num2 = 10;
while (true)
{
int hr = OleServicesContext.CurrentOleServicesContext.OleSetClipboard(obj2);
if (NativeMethods.Succeeded(hr))
{
break;
}
if (--num2 == 0)
{
Marshal.ThrowExceptionForHR(hr);
}
Thread.Sleep(100);
}
if (copy)
{
Thread.Sleep(10);
Flush();
}
}