Подтвердить что ты не робот

Ошибка CLIPBRD_E_CANT_OPEN при настройке буфера обмена из .NET.

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

Clipboard.SetText(str);

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

Решение:

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

Clipboard.SetText(str);

используйте

Clipboard.SetDataObject(str);

Ответ 4

На самом деле может быть и другая проблема. Рамочный вызов (как 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 всегда вызывается с истинным в этом случае.

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

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

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

Ответ 5

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

Ниже класс обертки, который я сделал. Может ли кто-нибудь просить проверить его и сообщить, правильно ли он или нет. Особенно, когда управляемый код работает как приложение x64 (я использую любой CPU в вариантах проекта). Что происходит, когда я ссылаюсь на библиотеки 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;
    }
}

Ответ 6

Это происходит со мной в моем приложении WPF. У меня возникла ошибка OpenClipboard (исключение из HRESULT: 0x800401D0 (CLIPBRD_E_CANT_OPEN)).

Я использую

ApplicationCommands.Copy.Execute(null, myDataGrid);

решение состоит в том, чтобы сначала очистить буфер обмена

Clipboard.Clear();
ApplicationCommands.Copy.Execute(null, myDataGrid);