这是一个在实际项目中遇到的问题,在VPN和远程桌面中,WPF程序对系统剪贴板进行操作的时候,发生CLIPBRD_E_CANT_OPEN异常。从异常本身来看,很明显,是COM有问题。

代码很简单 Clipboard.SetText(mSelection); 但是注意,这个是WPF的窗口,所以调用的是 System.Windows.Clipboard,而不是WinForm的System.Windows.Forms.Clipboard。

经过一番搜索,找到了根源:

http://stackoverflow.com/questions/68666/clipbrd-e-cant-open-error-when-setting-the-clipboard-from-net

http://blogs.microsoft.co.il/blogs/tamir/archive/2007/10/24/clipboard-setdata-getdata-troubles-with-vpc-and-ts.aspx

原因是微软的Terminal Service 的Clipboard有一个bug,解决方法就是用try-catch包一下函数调用,然后多调用几次,每次之后呢,Sleep一点时间片,代码看上去就是:

for (int i = 0; i < 10; i++)
{try{Clipboard.SetText(str);return;}catch { }System.Threading.Thread.Sleep(10);
}

而有人也指出,在.Net 2.0 SP1的时候,微软对Winform的剪切板做了修正,内部就做了这个处理,但是WPF没有!好,那就来看看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();}
}

终端服务的剪贴板的缺陷,导致WPF调用Clipboard.SetText() 失败相关推荐

  1. WPF的Clipboard.SetText()有问题

    调用 Clipboard.SetText(),每次都抛出异常:"CLIPBRD_E_CANT_OPEN" 调查后发现,实际上SetText有成功的将文本复制到Clipboard,但 ...

  2. Windows2008/2012多用户同时远程连接终端服务授权

    为什么80%的码农都做不了架构师?>>>    Windows服务器多用户同时登录问题,仅提供要点,其它自行百度: 1,Windows Server 远程桌面默认只能2个连接 2,安 ...

  3. VMware vSphere 服务器虚拟化之二十五 桌面虚拟化之终端服务池

    VMware vSphere 服务器虚拟化之二十五 桌面虚拟化之终端服务池 终端服务池是指由一台或多台微软终端服务器提供服务的桌面源组成的池.终端服务器桌面源可交付多个桌面.它具有以下特征: 1.终端 ...

  4. windows 2003 终端服务超出最大允许连接数(远程桌面,解决办法)

    这是因为Windows 2003中设置了最大允许连接数限制,而你每次连接后可能没有注销而是直接关闭,导致连接数超过了最大连接数.你可以在Windows 2003 服务器上通过组策略中设置一下来解决问题 ...

  5. 终端服务器配置未启用rdp安全层,终端服务配置RDP-Tcp连接属性.PPT

    终端服务配置RDP-Tcp连接属性 11.4.1 什么是TS RemoteApp? TS RemoteApp 使程序可以通过终端服务进行远程访问,就好像运行在最终用户的本地计算机上一样.这些程序称为 ...

  6. 注册表禁用远程桌面服务器,注册表配置远程桌面终端服务修改远程桌面端口号...

    如何通过注册表来配置终端服务,一键修改远程桌面端口号,避免使用组策略配置远程桌面终端服务带来的繁琐操作? Terminal Server mstsc 注册表配置文件,附有注释,一看就懂的. 将以下全部 ...

  7. C++ 打造自己的Windows终端服务客户端(转)

    1. 首先确保你的机器上存在mstscax.dll,如果没有这个文件,可以从http://download.microsoft.com/download/whistler/tools/1.0/wxp/ ...

  8. 安装终端服务和终端服务授权,激活终端服务授权

    1.1 安装和配置终端服务 1.1.1 安装终端服务授权 在DCServer安装终端服务器授权,给域中的终端服务器分发终端服务器许可.没有做指定终端服务授权的终端服务器,只能让用户使用120天. 步骤 ...

  9. 破解 Windows 2003终端服务许可证

    用过windows server 2003做服务器的人都知道  windows2003的性能安全性比以前的windows版本高出很多,但是也带来很多麻烦. 其中服务器最重要的远程管理"终端服 ...

最新文章

  1. python爬虫网络请求超时是什么意思_python爬虫怎么处理异常和超时?
  2. Codeforces Round #704 (Div. 2) D. Genius‘s Gambit 构造 + 细节
  3. php 输出mysql查询结果_php如何输出mysql查询结果
  4. 46个不可不知的生活小常识
  5. halcon 差异模型 异物_基于HALCON的形状匹配算法的研究和心得总结
  6. 解决laravel框架中Eloquent ORM的save方法无法插入数据的问题
  7. 渗透小助手——几个密码收集工具
  8. Spring Boot入门(4)-事务管理
  9. swf文件的反编译入门
  10. WinRunner介绍
  11. python网络爬虫课程设计报告摘要_课程设计 Python 网络爬虫(广度优先方法)
  12. 把rmvb格式转化为avi格式
  13. Visio 2013—安装步骤说明
  14. java请假系统毕业设计_毕业设计学生管理请假系统.doc
  15. 2022年个人如何申请微信H5支付接口?
  16. ping局域网里面全部的ip
  17. forkJoin源码解读
  18. 【控制control】机械臂运动学、动力学模型
  19. URL的作用是什么?它由几部分组成?
  20. matlab-线性代数 矩阵转置(共轭、非共轭)

热门文章

  1. 阿里云、华为云、谷歌云都已入局,盘点13家云计算厂商的RPA
  2. 融云韩迎:中国技术型公司出海才刚开始,未来有很大发展空间
  3. 【Bash百宝箱】shell函数
  4. USB转RS232不稳定
  5. 组态王 6.55 启停plc_6个经典的PLC程序实例,学会不求人
  6. java毕业设计超市管理系统Mybatis+系统+数据库+调试部署
  7. mBlock机器人组装教程_能自我组装的机器人M-block,来自mit人工智能实验室
  8. 什么地图制作软件好用,简单的地图绘制软件
  9. Windows安全模式密码错误、密码不正确、和账户登陆密码不一致解决方案
  10. 在python中读取npz文件