1. 程式人生 > >終端服務的剪貼簿的缺陷,導致WPF呼叫Clipboard.SetText() 失敗

終端服務的剪貼簿的缺陷,導致WPF呼叫Clipboard.SetText() 失敗

這是一個在實際專案中遇到的問題,在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() 失敗

這是一個在實際專案中遇到的問題,在VPN和遠端桌面中,WPF程式對系統剪貼簿進行操作的時候,發生CLIPBRD_E_CANT_OPEN異常。從異常本身來看,很明顯,是COM有問題。 程式碼很簡單 Clipboard.SetText(mSelection); 但是注意,這

C#如何儲存剪貼簿內容在使用後恢復。

   C# clipboard類封裝了對剪貼簿的操作,一般使用沒有問題。但由於clipboard封裝的資料型別有限,對於一些自定義型別的剪貼簿資料,如果想佔用剪貼簿並在使用後原樣恢復剪貼簿的資料就會產生問題。試驗了很多方法後,嘗試學習別人C++的思路。使用winapi來處理

delphi 剪貼簿操作讀取剪貼簿內容

//全域性變數NextClipHwnd:HWND;//剪貼簿觀察鏈中下一個視窗控制代碼    procedure TForm1.FormShow(Sender: TObject);begin  //獲得剪貼簿觀察鏈中下一個視窗控制代碼,並將控制代碼註冊到剪貼簿觀察鏈中  Ne

js實現複製到剪貼簿功能相容所有瀏覽器

前段時間做專案的時候,有點選按鈕複製文字的需求,想使用操作windows剪下板實現,在網上查了些資料,發現目前好像只有IE支援直接訪問剪下板,實現需求的時候也只做了IE中的點選複製功能,其餘瀏覽器: if(window.clipboardData){ window.clip

js複製內容到剪貼簿程式碼js複製程式碼

例子 <script type="text/javascript">      function jsCopy(){          var e=document.getElementById("contents");//物件是contents   

利用python監聽剪貼簿內容並修改。

前言 由於我在讀論文的時候常常需要複製論文片段,然後論文(pdf格式)中常常有多餘的換行符,所以貼上到txt或者markdown文字中都會很不美觀,我希望能利用python指令碼把換行符去掉,在此記錄過程。 預期要實現的功能: 1)複製一個pdf中的論文片段,

neutron-metadata-proxy無響應導致windos2003密碼透傳失敗

sha 判斷 agent 系統 process type ado dbf 解決 一、故障現象 在某雲平臺出現指定域指定節點(node-1)上創建windos2003虛擬機無法透傳創建虛擬機時設定的系統登錄密碼,但是可以透傳制作鏡像時設定的密碼創建好windos2003虛擬機

SQL安裝服務起不來報錯TDSSNICLIENT初始化失敗錯誤0X80092004

TDSSNIClient初始化失敗,錯誤0x80092004,狀態程式碼0x80。原因:無法初始化SSL支援。 TDSSNIClient初始化失敗,錯誤0x80092004,狀態程式碼0x1。原因:初始化因基礎結構錯誤而失敗。由於網路庫中的內部錯誤,無法啟動網路庫。   經過幾天的搜尋

Dubbo新增服務ip白名單防止不法呼叫

1.新增類ValidationFilter繼承阿里巴巴的Filter package com.filter; import java.io.IOException; import java.io.InputStream; import java.util

Win10自動更新導致的Sql Server連線失敗

Sql Server使用 :常見的【Sql Server連線失敗】問題 -----------------------------------------------------------------------------------------------------

nw.js 實現 剪貼簿的複製copy 貼上功能 --clipboard api

nw.js node-webkit系列(10)Native UI API Clipboard的使用開發文件 clipboard api: http://liuxp.me/nwjs/References/Clipboard/參考網址:http://blog.csdn.net/z

虛擬機移動磁盤中途服務器斷電導致磁盤鎖定的處理辦法

ovirt可以通過修改數據庫,步驟如下1、OVIRT進入數據庫[root@vmhost2 ~]# su postgres 進入數據庫bash-4.2$ psqlcould not change directory to "/root"psql (9.2.23)Type "help" for help.2、po

NFS服務意外斷開導致掛載的客戶端“df -Th”命令無法使用及掛載目錄無法“cd”“ls”

問題處理解決思路:1、強制取消客戶端掛載2、重啟NFS服務,客戶端和服務端都需要重啟3、重新掛載NFS 處理方法:1、強制取消客戶端掛載 # cat /etc/mtab # umount -lf /mnt 2、重啟NFS服務,客戶端和服務端都需要重啟 # systemctl restart nfs # sys

剪貼簿匿名管道命名管道郵槽學習筆記

  原始碼在後面   程序間進行通訊的四種方式: 剪貼簿,匿名管道,命名管道,郵槽 1).ClipBoar OpenClipboard()          &

針對惠普伺服器SNMP採集頻繁導致服務停止的解決方案

運維軟體:zabbix採集方式:snmp採集裝置:惠普-DL380_Gen9-伺服器採集週期:根據指標要求頻率有5分鐘到1天主要命令:reset /map1樂維服務中發現,snmp採集惠普伺服器一段時間後,zabbix提示連線失敗,重啟ilo後又可以重新採集,我們可以利用這一點做一

**萬能的“一鍵複製到剪貼簿支援IE、火狐、谷歌及移動版瀏覽器**

說到點選按鈕“複製到剪貼簿",大家都可能用過,但是之前的實現方不是隻支援某些瀏覽器,就是要在網頁內嵌swf(Flash)檔案。 這兩種方法:第一種不能很好的相容多數瀏覽器,第二種方式下開發人員可能會擔心Flash的安全性問題。 現在出現了一種新的實現方式:clipboard

TIME_WAIT、NON_ESTABLISHED 連線數過高導致tomcat服務直接宕機

TCP常見配置參考地址: http://shift-alt-ctrl.iteye.com/blog/1966744;https://www.cnblogs.com/fczjuever/archive/2013/04/05/3000697.html 以上圖最大連線數接近了2000,這個對於單機環境來說基本已

Sqlite表結構讀取工具word批量轉html線上雲剪貼簿檔案批量提取工具;

工欲善其事必先利其器,本週為您推薦工具排行 Sqlite表結構讀取工具,word批量轉html,線上雲剪貼簿,檔案批量提取工具;     本週我們又要發乾貨了,準備好接受了嗎? 為什麼是乾貨,就是因為不是水貨,因為幹了,所以是乾貨,也就是實打實的。當然哈

一次意外:win7 中 DCOM Server Process Launcher 服務意外終止導致計算機重新啟動

       剛遇到這個問題,也是第一次遇到,先描述下問題:在記憶體使用率比較高的情況下,突然彈出對話方塊,提示:DCOM Server Process Launcher 服務意外終止...  (當時第一反應就是儲存截圖,結果由於動作慢了點,電腦過了一會就自動關閉程式,重啟了

MFC:使用剪貼簿怎麼將內容複製到剪貼簿

經常在論壇上見到一些使用者詢問如何在Visual C++中如何實現對剪貼簿的操作,其實在VC++/MFC中是相當簡單的。本文主要介紹瞭如下內容: 1、文字內容的操作 2、WMF資料的操作 3、點陣圖的操作 4、設定使用自定義格式 5、感知剪貼簿內容的改變 6、自動將資料貼上到另一應用程式視窗 一、文字內容的