2010-04-05 12 views
13

Haré todo lo posible para explicar en detalle lo que estoy tratando de lograr.¿Cómo respaldo y restauro el portapapeles del sistema en C#?

Estoy usando C# con los controladores de ventana IntPtr para realizar una operación de copia CTRL-C en una aplicación externa desde mi propia aplicación C#. Tuve que hacer esto porque no había forma de acceder al texto directamente usando GET_TEXT. Entonces estoy usando el contenido de texto de esa copia dentro de mi aplicación. El problema aquí es que ahora he sobrescrito el portapapeles.

Lo que me gustaría ser capaz de hacer es:

  1. copia de seguridad del contenido original del portapapeles que podría haber sido marcada por cualquier aplicación que no sea la mía.
  2. Luego realice la copia y almacene el valor en mi aplicación.
  3. Restaure los contenidos originales del portapapeles para que el usuario tenga acceso a sus datos originales del portapapeles.

Este es el código que he probado hasta ahora:

private void GetClipboardText() 
{ 

    text = ""; 

    IDataObject backupClipboad = Clipboard.GetDataObject(); 

    KeyboardInput input = new KeyboardInput(this); 
    input.Copy(dialogHandle); // Performs a CTRL-C (copy) operation 

    IDataObject clipboard = Clipboard.GetDataObject(); 
    if (clipboard.GetDataPresent(DataFormats.Text)) 
    { 
     // Retrieves the text from the clipboard 
     text = clipboard.GetData(DataFormats.Text) as string; 
    } 

    if (backupClipboad != null) 
    { 
     Clipboard.SetDataObject(backupClipboad, true); // throws exception 
    } 
} 

estoy usando el System.Windows.Clipboard y no System.Windows.Forms.Clipboard. La razón de esto fue que cuando realicé el CTRL-C, la clase Clipboard de System.Windows.Forms no devolvió ningún dato, pero sí el portapapeles del sistema.

Intenté algunas de las llamadas de usuario de nivel bajo como OpenClipboard, EmptyClipboard y CloseClipboard esperando que me ayudaran a hacer esto, pero hasta el momento sigo recibiendo excepciones COM al intentar restaurar.

Pensé que quizás esto tenía que ver con el parámetro OpenClipboard que está esperando un identificador de ventana IntPtr de la aplicación que quiere tomar el control del portapapeles. Como mencioné que mi aplicación no tiene una GUI, es un desafío. No estaba seguro de qué pasar aquí. Tal vez alguien puede arrojar algo de luz sobre eso?

¿Estoy usando la clase Clipboard incorrectamente? ¿Hay alguna manera clara de obtener el identificador de ventana IntPtr de una aplicación sin GUI? ¿Alguien sabe de una mejor manera de respaldar y restaurar el portapapeles del sistema?

+0

Me encontré con el mismo error y encontré esta publicación. Sin embargo, obtuve este error solo si llamo Clipboard.GetDataObject(). SetData (myData). Funciona bien si llamo Clipboard.SetDataObject (myData). ¿Alguna explicación de por qué? Mi aplicación está basada en WPF si es importante. – newman

Respuesta

6

Se podría guardar el contenido del portapapeles en un diccionario, y restaurarla después: la necedad

public IDictionary<string, object> GetClipboardData() 
{ 
    var dict = new Dictionary<string, object>(); 
    var dataObject = Clipboard.GetDataObject(); 
    foreach(var format in dataObject.GetFormats()) 
    { 
     dict.Add(format, dataObject.GetData(format)); 
    } 
    return dict; 
} 

public void SetClipboardData(IDictionary<string, object> dict) 
{ 
    var dataObject = Clipboard.GetDataObject(); 
    foreach(var kvp in dict) 
    { 
     dataObject.SetData(kvp.Key, kvp.Value); 
    } 
} 

... 

var backup = GetClipboardData(); 
// Do something with the clipboard... 
... 
SetClipboardData(backup); 
+0

El problema que tengo es que cualquier SetData o SetDataObject que realizo me da una excepción COM porque no pudo abrir el portapapeles. Voy a probar ese método, pero el problema subyacente es que el portapapeles parece bloqueado. – gtaborga

+1

Esta es la excepción que obtengo en la primera llamada de SetData en ese bucle: "No se puede establecer datos en un objeto de datos OLE congelado" – gtaborga

+0

Pruebe Clipboard.SetData en lugar de IDataObject.SetData, luego ... –

17

de lo que tratan de hacer esto. No puede restaurar fielmente el portapapeles a su estado anterior. Puede haber docenas de formatos de datos sin procesar presentes mediante el "procesamiento retrasado", y si intenta renderizarlos todos, hará que la aplicación de origen se quede sin recursos. Es como entrar en un restaurante y decir "dame uno de todo".

Supongamos que el usuario ha seleccionado 500 filas x 100 columnas en Excel, y que ha copiado eso en el portapapeles. Excel "anuncia" que puede producir esta información en aproximadamente 25 formatos diferentes, incluido Bitmap. Una vez que lo pega como un mapa de bits, fuerza a Excel para que lo represente como un mapa de bits. Eso es 50000 celdas, y sería un mapa de bits de aproximadamente 10,000 x 15,000 píxeles. ¿Y espera que el usuario espere mientras Excel lo tose, junto con otros 24 formatos? No factible.

Además, vas a desencadenar eventos WM_DrawClipboard, lo que afectará a otros espectadores del portapapeles.

Abandonar.

+5

"Los programas no deben transferir datos a nuestro fuera del portapapeles sin una instrucción explícita del usuario." - Charles Petzold, Programación de Windows 3.1, Microsoft Press, 1992 –

+0

Por eso es la única vez que escribo el manejo del Portapapeles código fue cuando se implementó Cortar, Copiar y Pegar en un menú en una aplicación .NET. – Powerlord

+0

Nunca tuve la intención de renderizar todos los datos que se están respaldando. La cantidad de datos recuperados con el CTRL-C es aproximadamente la longitud de una oración en el texto. Esperaba una forma de volver a poner el contenido original del portapapeles después de usar el portapapeles para mis propias necesidades. ¿Es posible restaurar el portapapeles sin obtener un error de "no se puede abrir el portapapeles" en este escenario? – gtaborga

Cuestiones relacionadas