WPF剪切板問題-OpenClipboard HRESULT:0x800401D0 (CLIPBRD_E_CANT_OPEN))
最近碰到一個問題,需要弄個小工具來解決。剛好接觸到WPF,於是就想通過WPF來實現。
在這個過程中想通過程序將一些東西復制到剪切板中,代碼很簡單:Clipboard.SetText(lineTexts[lineIndex]);就這一句,想把lineTexts這個字符串List中的第lineIndex項復制到剪切板中,但是運行的時候就會拋出異常,大致的異常信息是“OpenClipboard HRESULT:0x800401D0 (CLIPBRD_E_CANT_OPEN))”(挺長的一段,注意沒寫全)。而winform那邊之前也用過,沒有問題。
上網搜索了一下,看了挺多資料,發現是WPF本身對Clipboard處理的問題,在.Net4.0及之前的版本中都有問題,最近Micorsoft已經在.Net4.5中修復了。問題主要是由於:在程序訪問剪切板的時候,有其他程序正在占用剪切板,導致自己的程序無法訪問,從而拋出異常。
在.Net4.0上,解決這個問題,我大概總結了一下,有下面幾種方法:
這種方法處理過程中UI會有一小段時間的假死。。。可以考慮多線程?
2. 換一種方式設置剪切板
Clipboard.SetDataObject(lineTexts[lineIndex]);
就這一句。。。這種方法不會拋異常,UI也沒有假死,非常正常!估計SetDataObject方法跟SetText方法的實現不一樣,沒有細究。。。
3. 跟方法1類似,不過有點高級
在這個過程中想通過程序將一些東西復制到剪切板中,代碼很簡單:Clipboard.SetText(lineTexts[lineIndex]);就這一句,想把lineTexts這個字符串List中的第lineIndex項復制到剪切板中,但是運行的時候就會拋出異常,大致的異常信息是“OpenClipboard HRESULT:0x800401D0 (CLIPBRD_E_CANT_OPEN))”(挺長的一段,注意沒寫全)。而winform那邊之前也用過,沒有問題。
上網搜索了一下,看了挺多資料,發現是WPF本身對Clipboard處理的問題,在.Net4.0及之前的版本中都有問題,最近Micorsoft已經在.Net4.5中修復了。問題主要是由於:在程序訪問剪切板的時候,有其他程序正在占用剪切板,導致自己的程序無法訪問,從而拋出異常。
在.Net4.0上,解決這個問題,我大概總結了一下,有下面幾種方法:
- 自行截獲異常,進行處理
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文件中添加下面代碼中紅色的部分在App.xaml.cs文件中添加代碼:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
DispatcherUnhandledException="Application_DispatcherUnhandledException">
void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
var comException = e.Exception as System.Runtime.InteropServices.COMException;
if (comException != null && comException.ErrorCode == -2147221040)///OpenClipboard HRESULT:0x800401D0 (CLIPBRD_E_CANT_OPEN))
e.Handled = true;
}
這種方法中剪切板動作會自動多次嘗試,由於拋出的異常被App中的異常處理給截獲了,所以會不斷的嘗試直到成功。方法三也有一定程度的UI假死。對於方法三,具體原理可以到MSDN上搜一下 DispatcherUnhandledException或相關內容,這里一時半會說不清楚。
方法三使用范圍廣,可以類似的處理其他的異常。而方法二只能是自己的代碼才能解決,如果用到WPF控件或者其他第三方控件就不行了。所以推薦方法三,但如果是自己寫的代碼,用方法二就簡單方便的多。