Ошибка CLIPBRD_E_CANT_OPEN при установке буфера обмена из .NET - PullRequest
43 голосов
/ 16 сентября 2008

Почему следующий код иногда вызывает исключение с содержимым "CLIPBRD_E_CANT_OPEN":

Clipboard.SetText(str);

Обычно это происходит при первом использовании буфера обмена в приложении, а не после этого.

Ответы [ 6 ]

35 голосов
/ 16 сентября 2008

Это вызвано ошибкой / функцией в буфере обмена служб терминалов (и, возможно, другими вещами) и реализацией буфера обмена в .NET. Задержка открытия буфера обмена вызывает ошибку, которая обычно проходит в течение нескольких миллисекунд.

Решение состоит в том, чтобы попробовать несколько раз в цикле и поспать между ними.

for (int i = 0; i < 10; i++)
{
    try
    {
        Clipboard.SetText(str);
        return;
    }
    catch { }
    System.Threading.Thread.Sleep(10);
} 
32 голосов
/ 16 сентября 2008

На самом деле, я думаю, что это ошибка Win32 API .

Чтобы установить данные в буфер обмена, вы должны открыть их в первую очередь. Только один процесс может одновременно открыть буфер обмена. Таким образом, когда вы проверяете, если по какой-либо причине буфер обмена по какой-либо причине *1008* открыт для другого процесса, ваша попытка открыть его не удастся.

Так получилось, что службы терминалов отслеживают буфер обмена, а в более старых версиях Windows (до Vista) вам нужно открыть буфер обмена, чтобы посмотреть, что внутри ... что в итоге блокирует вас. Единственное решение - подождать, пока службы терминалов закроют буфер обмена, и повторить попытку.

Важно понимать, что это не относится только к службам терминалов: это может случиться с чем угодно. Работа с буфером обмена в Win32 - гигантское состояние гонки. Но, поскольку по замыслу вы должны только возиться с буфером обмена в ответ на ввод данных пользователем, это обычно не представляет проблемы.

18 голосов
/ 24 августа 2016

Я знаю, что этот вопрос старый, но проблема все еще существует. Как упоминалось ранее, это исключение возникает, когда системный буфер обмена блокируется другим процессом. К сожалению, существует множество инструментов для снятия скриншотов, программ для создания скриншотов и файлов, которые могут блокировать буфер обмена Windows. Таким образом, вы будете получать исключение каждый раз, когда пытаетесь использовать Clipboard.SetText(str), когда такой инструмент установлен на вашем ПК.

Решение:

никогда не используйте

Clipboard.SetText(str);

используйте вместо

Clipboard.SetDataObject(str);
7 голосов
/ 30 июля 2012

На самом деле может быть другая проблема под рукой. Фреймворковый вызов (как WPF, так и winform) к чему-то вроде этого (код от отражателя):

private static void SetDataInternal(string format, object data)
{
    bool flag;
    if (IsDataFormatAutoConvert(format))
    {
        flag = true;
    }
    else
    {
        flag = false;
    }
    IDataObject obj2 = new DataObject();
    obj2.SetData(format, data, flag);
    SetDataObject(obj2, true);
}

Обратите внимание, что в этом случае SetDataObject всегда вызывается с true.

Внутренне это вызывает два вызова API win32: один для установки данных, а другой - для сброса их из вашего приложения, чтобы они были доступны после закрытия приложения.

Я видел несколько приложений (несколько плагинов Chrome и менеджер загрузок), которые прослушивают событие буфера обмена. Как только поступит первый вызов, приложение откроет буфер обмена, чтобы просмотреть данные, и второй вызов сброса не удастся.

Не нашел хорошего решения, кроме как написать свой собственный класс буфера обмена, использующий прямой win32 API, или вызвать setDataObject напрямую со значением false для хранения данных после закрытия приложения.

5 голосов
/ 11 мая 2015

Я решил эту проблему для своего собственного приложения, используя собственные функции Win32: OpenClipboard (), CloseClipboard () и SetClipboardData ().

Ниже класса оболочки, который я сделал. Может ли кто-нибудь , пожалуйста, просмотреть его и сказать, правильно ли это или нет . Особенно, когда управляемый код выполняется как приложение x64 (я использую любой процессор в настройках проекта). Что происходит, когда я связываюсь с библиотеками x86 из приложения x64?

Спасибо!

Вот код:

public static class ClipboardNative
{
    [DllImport("user32.dll")]
    private static extern bool OpenClipboard(IntPtr hWndNewOwner);

    [DllImport("user32.dll")]
    private static extern bool CloseClipboard();

    [DllImport("user32.dll")]
    private static extern bool SetClipboardData(uint uFormat, IntPtr data);

    private const uint CF_UNICODETEXT = 13;

    public static bool CopyTextToClipboard(string text)
    {
        if (!OpenClipboard(IntPtr.Zero)){
            return false;
        }

        var global = Marshal.StringToHGlobalUni(text);

        SetClipboardData(CF_UNICODETEXT, global);
        CloseClipboard();

        //-------------------------------------------
        // Not sure, but it looks like we do not need 
        // to free HGLOBAL because Clipboard is now 
        // responsible for the copied data. (?)
        //
        // Otherwise the second call will crash
        // the app with a Win32 exception 
        // inside OpenClipboard() function
        //-------------------------------------------
        // Marshal.FreeHGlobal(global);

        return true;
    }
}
0 голосов
/ 11 мая 2017

Это случилось со мной в моем приложении WPF. Я получил сбой OpenClipboard (исключение из HRESULT: 0x800401D0 (CLIPBRD_E_CANT_OPEN)).

я использую

ApplicationCommands.Copy.Execute(null, myDataGrid);

Решение - сначала очистить буфер обмена

Clipboard.Clear();
ApplicationCommands.Copy.Execute(null, myDataGrid);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...