web-development-kb-es.site

Error CLIPBRD_E_CANT_OPEN al configurar el Portapapeles desde .NET

¿Por qué el siguiente código a veces causa una excepción con el contenido "CLIPBRD_E_CANT_OPEN":

Clipboard.SetText(str);

Esto suele ocurrir la primera vez que se utiliza el Portapapeles en la aplicación y no después.

43
Robert Wagner

En realidad, creo que esta es la falla de la API Win32 .

Para configurar datos en el portapapeles, primero debe abrirlo . Solo un proceso puede tener el portapapeles abierto a la vez. Entonces, cuando verifique, si otro proceso tiene el portapapeles abierto por cualquier motivo , su intento de abrirlo fallará.

Da la casualidad de que Terminal Services realiza un seguimiento del portapapeles, y en versiones anteriores de Windows (anteriores a Vista), debe abrir el portapapeles para ver qué hay dentro ... lo que termina bloqueándolo. La única solución es esperar hasta que Terminal Services cierre el portapapeles y volver a intentarlo.

Sin embargo, es importante darse cuenta de que esto no es específico de Terminal Services: puede suceder con cualquier cosa. Trabajar con el portapapeles en Win32 es una condición de carrera gigante. Pero, dado que por diseño solo se supone que debe jugar con el portapapeles en respuesta a la entrada del usuario, esto generalmente no presenta un problema.

32
Tadmas

Esto es causado por un error/característica en el portapapeles de Terminal Services (y posiblemente otras cosas) y la implementación .NET del portapapeles. Un retraso en la apertura del portapapeles provoca el error, que suele pasar en unos pocos milisegundos.

La solución es intentarlo varias veces dentro de un ciclo y dormir en el medio.

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

Sé que esta pregunta es antigua, pero el problema aún existe. Como se mencionó anteriormente, esta excepción ocurre cuando el portapapeles del sistema está bloqueado por otro proceso. Desafortunadamente, hay muchas herramientas de recorte, programas para capturas de pantalla y herramientas de copia de archivos que pueden bloquear el portapapeles de Windows. Por lo tanto, obtendrá la excepción cada vez que intente utilizar Clipboard.SetText(str) cuando dicha herramienta esté instalada en su PC.

Solución:

nunca usar

Clipboard.SetText(str);

usar en su lugar

Clipboard.SetDataObject(str);
20
pr0gg3r

De hecho, podría haber otro problema entre manos. La llamada al marco (tanto WPF como winform) a algo como esto (el código es del reflector):

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);
}

Tenga en cuenta que SetDataObject siempre se llama con verdadero en este caso.

Internamente, eso activa dos llamadas a la api win32, una para configurar los datos y otra para eliminarlos de su aplicación para que esté disponible después de que se cierre la aplicación.

He visto varias aplicaciones (algunas chrome plugin y un administrador de descargas) que escuchan el evento del portapapeles. Tan pronto como llegue la primera llamada, la aplicación abrirá el portapapeles para buscar en el datos, y la segunda llamada a vaciar fallará.

No he encontrado una buena solución, excepto para escribir mi propia clase de portapapeles que usa la API win32 directa o llamar a setDataObject directamente con false para mantener los datos después de que se cierra la aplicación.

7
Yishai Galatzer

Resolví este problema para mi propia aplicación usando funciones nativas de Win32: OpenClipboard (), CloseClipboard () y SetClipboardData ().

Debajo de la clase de envoltura que hice. ¿Alguien podría por favor revisarlo y decir si es correcto o no. Especialmente cuando el código administrado se ejecuta como una aplicación x64 (uso Cualquier CPU en las opciones del proyecto). ¿Qué sucede cuando me vinculo a bibliotecas x86 desde la aplicación x64?

¡Gracias!

Aquí está el código:

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;
    }
}
5
Mar

Esto me pasó en mi aplicación WPF. Obtuve OpenClipboard Failed (Excepción de HRESULT: 0x800401D0 (CLIPBRD_E_CANT_OPEN)).

yo suelo

ApplicationCommands.Copy.Execute(null, myDataGrid);

la solución es limpiar el portapapeles primero

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