不使用剪贴板 (VBA) 复制 Word 文档内容

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/461840/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 10:11:27  来源:igfitidea点击:

copy Word document contents without using clipboard (VBA)

vbams-wordword-vba

提问by hello_earth

I was wondering how to avoid using Windows clipboard, when you want to "replicate" multiple sections of a Word document (using VBA in macros)

我想知道如何避免使用 Windows 剪贴板,当您想“复制”Word 文档的多个部分(在宏中使用 VBA)

Why to avoid? Because we're using Word on a server, in a multiuser environment (I know that it is officially frowned upon)

为什么要避免?因为我们在服务器上使用 Word,在多用户环境中(我知道官方不赞成)

Otherwise, this would be easily accomplished with Selection.Copy and Selection.Paste methods.

否则,这可以通过 Selection.Copy 和 Selection.Paste 方法轻松完成。

Thanks.

谢谢。

采纳答案by hello_earth

I finally resolved to copy word by word. FormattedText seemed to work fairly well, until the last word (some special (evidently) characters), where suddenly the cell that I just filled with copied content would go blank. When I increased the number of cells, other run-time errors would pop up, like Your table got corrupted, and other ambiguous ones. Somehow, the source cell that I was copying from always seemed to have these peculiar chars in the end with ASCII codes 13 and 7. I know what 13 means, but 7? Anyway, I decided to copy everything apart from this last character with code 7. It seems to work alright. Both formatting and fields are copied too. In any case, the whole story proved to me for one more time that programming in VBA is mostly trial-and-error occupation. You are never sure when something might break.. unless I am missing update on some crucial concepts..

我终于下定决心逐字抄写。FormattedText 似乎工作得相当好,直到最后一个单词(一些特殊(显然)字符),突然我刚刚填充复制内容的单元格会变成空白。当我增加单元格的数量时,会弹出其他运行时错误,例如您的表已损坏,以及其他不明确的错误。不知何故,我从中复制的源单元格似乎总是以 ASCII 代码 13 和 7 结尾这些特殊字符。我知道 13 是什么意思,但是 7?无论如何,我决定用代码 7 复制除了最后一个字符之外的所有内容。它似乎工作正常。格式和字段也会被复制。无论如何,整个故事又一次向我证明,在 VBA 中编程主要是反复试验。你永远不确定什么时候会坏掉..

Here's the chunks of the code I used. The idea is that first we have a document with a single 1x1 cell table, with some rich text content. In the first piece of the code (inside a macro) I multiply the cells:

这是我使用的代码块。这个想法是首先我们有一个带有单个 1x1 单元格表的文档,其中包含一些富文本内容。在代码的第一部分(在宏中),我将单元格相乘:

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

In the second part of the macro I populate each empty cell with the contents of the first cell:

在宏的第二部分,我用第一个单元格的内容填充每个空单元格:

   ' 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

Here are the images of the Word document in question. First image is before running the macro, second is between the first chunk of code and the last, while the third image is the resulting document.

以下是相关 Word 文档的图像。第一个图像是在运行宏之前,第二个是在第一个代码块和最后一个代码块之间,而第三个图像是生成的文档。

Image 1Image 2Image 3

图 1图 2图 3

That's it.

就是这样。

回答by Wade Hatler

In Office 2007+ VSTO, you can export the block with Range.ExportFragmentand then go to your new document and import it with Range.ImportFragment. I haven't used this in production, but experimented with it and it seems to work OK.

在 Office 2007+ VSTO 中,您可以使用Range.ExportFragment导出块,然后转到您的新文档并使用Range.ImportFragment导入它。我没有在生产中使用过它,但对其进行了试验,它似乎工作正常。

One caveat, I got errors when trying to export as a .docx, but RTF seemed to work ok.

一个警告,我在尝试导出为 .docx 时出错,但 RTF 似乎工作正常。

Both methods exist in VBA as well, but I only tested the VSTO methods.

这两种方法也存在于 VBA 中,但我只测试了 VSTO 方法。

回答by Plavozont

This doesn't always work, with text fields, diagramms, for example, or if you need to copy it to another document, but it's good for copying simple formatted text inside one document.

这并不总是适用,例如文本字段、图表,或者如果您需要将其复制到另一个文档,但它适用于在一个文档中复制简单的格式化文本。

'First select something, then do
Word.WordBasic.CopyText
'Then move somewhere
Word.WordBasic.OK;

To copy the whole document to a new document use this:

要将整个文档复制到新文档,请使用以下命令:

Word.Application.Documents.Add Word.ActiveDocument.FullName

回答by Jeff Spencer

I ran into a similar issue. I wanted to copy a table from one word doc to another using Powershell without using the clipboard. Since a user using the computer while the script ran could break the script by using the clipboard. The solution I came up with was:

我遇到了类似的问题。我想在不使用剪贴板的情况下使用 Powershell 将表格从一个 word doc 复制到另一个 word doc。由于在脚本运行时使用计算机的用户可能会使用剪贴板破坏脚本。我想出的解决方案是:

  1. Open the source document and put a bookmark covering the range of what I wanted (in my case a single table).
  2. Save the source document with its bookmark in another location (to avoid changing the source document).
  3. Opened the destination document and created a range object for where I wanted the table placed.
  4. Used range.InsertFilewith the first parameter of the source file with my bookmark and the second parameter of my bookmark name. This single operation pulled the entire table plus source formatting directly into the destination document.
  1. 打开源文档并放置一个书签,涵盖我想要的范围(在我的情况下是单个表格)。
  2. 将带有书签的源文档保存在另一个位置(以避免更改源文档)。
  3. 打开目标文档并为我想要放置表格的位置创建一个范围对象。
  4. 使用range.InsertFile与我的书签源文件和我的书签名称的第二个参数的第一个参数。这个单一的操作将整个表格和源格式直接拉到目标文档中。

I then added code based on where the insertion was being done and how much longer the story was to select the inserted table to allow further operations on it.

然后,我根据插入的位置以及故事需要多长时间来选择插入的表以允许对其进行进一步操作添加代码。

I tried many any other methods to move the table and this was by far the best. Sorry I can't provide VBA code for this solution.

我尝试了许多其他方法来移动桌子,这是迄今为止最好的。抱歉,我无法为此解决方案提供 VBA 代码。

回答by John Mo

Use the Text property of the Selection object to put the data into a string variable rather than onto the clipboard:

使用 Selection 对象的 Text 属性将数据放入字符串变量而不是剪贴板:

Dim strTemp as String

Dim strTemp 作为字符串

strTemp = Selection.Text

strTemp = Selection.Text

You can then insert the text stored in the variable elsewhere as needed.

然后,您可以根据需要在其他地方插入存储在变量中的文本。