vba - pegar - portapapeles windows
copiar contenido de documentos de Word sin usar el portapapeles(VBA) (5)
Me preguntaba cómo evitar el uso del portapapeles de Windows, cuando desea "replicar" varias secciones de un documento de Word (usando VBA en macros)
¿Por qué evitar? Porque estamos usando Word en un servidor, en un entorno multiusuario (sé que oficialmente está mal visto)
De lo contrario, esto se lograría fácilmente con los métodos Selection.Copy y Selection.Paste.
Gracias.
Use la propiedad Text del objeto Selection para poner los datos en una variable de cadena en lugar de en el portapapeles:
Dim strTemp como cadena
strTemp = Selection.Text
A continuación, puede insertar el texto almacenado en la variable en otro lugar según sea necesario.
Finalmente resolví copiar palabra por palabra. FormattedText pareció funcionar bastante bien, hasta la última palabra (algunos caracteres especiales (evidentemente)), donde de repente la celda que acabo de llenar con contenido copiado quedaría en blanco. Cuando aumentaba el número de celdas, aparecían otros errores de tiempo de ejecución, como por ejemplo, Tu tabla se corrompió y otras ambiguas. De alguna manera, la celda fuente de la que estaba copiando siempre parecía tener estos caracteres peculiares al final con los códigos ASCII 13 y 7. Sé lo que significa 13, pero 7? De todos modos, decidí copiar todo aparte de este último personaje con el código 7. Parece que funciona bien. Tanto el formato como los campos se copian también. En cualquier caso, toda la historia me demostró una vez más que la programación en VBA es principalmente de ensayo y error. Nunca está seguro de cuándo se puede romper algo ... a menos que me pierda la actualización de algunos conceptos cruciales.
Aquí están los pedazos del código que utilicé. La idea es que primero tenemos un documento con una sola tabla de células 1x1, con un contenido de texto enriquecido. En la primera parte del código (dentro de una macro) multiplico las celdas:
(TEN EN CUENTA que puse // delante de cada comentario de VB tipo apóstrofo para que el comentario se coloreara correctamente)
Dim cur_width As Integer, i As Integer, max_cells As Integer, cur_row As Integer
Dim origin_width As Integer
If ActiveDocument.Tables.Count = 1 _
And ActiveDocument.Tables(1).Rows.Count = 1 _
And ActiveDocument.Tables(1).Columns.Count = 1 _
Then
max_cells = 7 //'' how many times we are going to "clone" the original content
i = 2 //'' current cell count - starting from 2 since the cell with the original content is cell number 1
cur_width = -1 //'' current width
cur_row = 1 //'' current row count
origin_width = ActiveDocument.Tables(1).Rows(1).Cells(1).Width
//'' loop for each row
While i <= max_cells
//'' adjust current width
If cur_row = 1 Then
cur_width = origin_width
Else
cur_width = 0
End If
//'' loop for each cell - as long as we have space, add cells horizontally
While i <= max_cells And cur_width + origin_width < ActiveDocument.PageSetup.PageWidth
Dim col As Integer
//'' / returns floor() of the result
col = i / ActiveDocument.Tables(1).Rows.Count
// ''add cell, if it is not already created (which happens when we add rows)
If ActiveDocument.Tables(1).Rows(cur_row).Cells.Count < col Then
ActiveDocument.Tables(1).Rows(cur_row).Cells.Add
End If
// ''adjust new cell width (probably unnecessary
With ActiveDocument.Tables(1).Rows(cur_row).Cells(col)
.Width = origin_width
End With
// ''keep track of the current width
cur_width = cur_width + origin_width
i = i + 1
Wend
//'' when we don''t have any horizontal space left, add row
If i <= max_cells Then
ActiveDocument.Tables(1).Rows.Add
cur_row = cur_row + 1
End If
Wend
End If
En la segunda parte de la macro llené cada celda vacía con el contenido de la primera celda:
//'' duplicate the contents of the first cell to other cells
Dim r As Row
Dim c As Cell
Dim b As Boolean
Dim w As Range
Dim rn As Range
b = False
i = 1
For Each r In ActiveDocument.Tables(1).Rows
For Each c In r.Cells
If i <= max_cells Then
// '' don''t copy first cell to itself
If b = True Then
//'' copy everything word by word
For Each w In ActiveDocument.Tables(1).Rows(1).Cells(1).Range.Words
//'' get the last bit of formatted text in the destination cell, as range
//'' do it first by getting the whole range of the cell, then collapsing it
//'' so that it is now the very end of the cell, and moving it one character
//'' before (because collapsing moves the range actually beyond the last character of the range)
Set rn = c.Range
rn.Collapse Direction:=wdCollapseEnd
rn.MoveEnd Unit:=wdCharacter, Count:=-1
//'' somehow the last word of the contents of the cell is always Chr(13) & Chr(7)
//'' and especially Chr(7) causes some very strange and murky problems
//'' I end up avoiding them by not copying the last character, and by setting as a rule
//'' that the contents of the first cell should always contain an empty line in the end
If c.Range.Words.Count <> ActiveDocument.Tables(1).Rows(1).Cells(1).Range.Words.Count Then
rn.FormattedText = w
Else
//''MsgBox "The strange text is: " & w.Text
//''the two byte values of this text (which obviously contains special characters with special
//''meaning to Word can be found (and watched) with
//''AscB(Mid(w.Text, 1, 1)) and AscB(Mid(w.Text, 2, 1))
w.MoveEnd Unit:=WdUnits.wdCharacter, Count:=-1
rn.FormattedText = w
End If
Next w
End If
b = True
End If
i = i + 1
Next c
Next r
Aquí están las imágenes del documento de Word en cuestión. La primera imagen es antes de ejecutar la macro, la segunda es entre el primer fragmento de código y la última, mientras que la tercera imagen es el documento resultante.
Eso es.
Esto no siempre funciona, con campos de texto, diagramas, por ejemplo, o si necesita copiarlo a otro documento, pero es bueno para copiar texto con formato simple dentro de un documento.
''First select something, then do
Word.WordBasic.CopyText
''Then move somewhere
Word.WordBasic.OK;
Para copiar el documento completo a un documento nuevo, use esto:
Word.Application.Documents.Add Word.ActiveDocument.FullName
Me encontré con un problema similar. Quería copiar una tabla de un documento de Word a otro usando Powershell sin usar el portapapeles. Dado que un usuario que utiliza la computadora mientras se ejecutaba la secuencia de comandos podía romper la secuencia de comandos mediante el uso del portapapeles. La solución que se me ocurrió fue:
- Abra el documento de origen y coloque un marcador que cubra el rango de lo que quería (en mi caso, una sola tabla).
- Guarde el documento fuente con su marcador en otra ubicación (para evitar cambiar el documento fuente).
- Abrí el documento de destino y creé un objeto de rango para el lugar donde quería colocar la tabla.
-
range.InsertFile
con el primer parámetro del archivo de origen con mi marcador y el segundo parámetro de mi nombre de marcador. Esta operación única extrajo la tabla completa más el formato de la fuente directamente en el documento de destino.
Luego agregué el código en función de dónde se realizaba la inserción y cuánto tiempo más era la historia para seleccionar la tabla insertada para permitir más operaciones en ella.
Probé muchos otros métodos para mover la mesa y este fue de lejos el mejor. Lo siento, no puedo proporcionar el código VBA para esta solución.
En Office 2007+ VSTO, puede exportar el bloque con Range.ExportFragment y luego ir a su nuevo documento e importarlo con Range.ImportFragment . No lo he usado en producción, pero experimenté con él y parece funcionar bien.
Una advertencia, recibí errores al intentar exportar como .docx, pero RTF parecía funcionar bien.
Ambos métodos existen también en VBA, pero solo probé los métodos de VSTO.