tags:

views:

4386

answers:

3

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

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

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

Thanks.

A: 

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

Dim strTemp as String

strTemp = Selection.Text

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

John Mo
huh? what about other stuff, like ole images, field codes, etc? otherwise fine if all you want is text
Anonymous Type
A: 

Thank you both for your answers, and sorry it took me so long to reply. See, I was trying to find some solution to it all.

Godeke> definitely I'll search into other programs for the stuff i'm doing - but for the time being I'll have to stick with Word :(

John Mo> yes, Text is in fact the only property that does the job, but it does it so poorly. basically, as i am finding out, it seems to be the only way to make an actual COPY of textual data.. but what if I want formatting, and other objects (like fields) to be copied too?

Actually, I thought it would be a lot easier, but in the end it's not the case.

Important: I am on Ms Office 2007

My pain grew when I found out that there is very little information about this stuff on the internet (maybe I'm so foolish that it's only me who has this problem). In any case - there is this FormattedText property of a Range and Selection objects, which is supposed to be able to be set with the formatted text of another range/selection. While I didn't try the original simple example Microsoft gives (maybe I will - but it's so exhausting to spend time on stuff like that), i tried to do as instructed on the range objects of various cells in a table. Basically, I want to copy the contents of one cell to all other cells in a table - using FormattedText property. Obviously, this doesn't work for any number of cells..

In any case. I don't know if you have any suggestions, but here's the code:

   Dim r As Row
   Dim c As Cell
   Dim b As Boolean
   b = False
   For Each r In ActiveDocument.Tables(1).Rows
       For Each c In r.Cells
            If b = True Then ' don't copy first cell to itself
                c.Range.FormattedText = ActiveDocument.Tables(1).Rows(1).Cells(1).Range.FormattedText
            End If
            b = True
       Next c
   Next r

With this code as it is, nothing happens. Basially, in the line where I try to set FormattedText, if I skip both FormattedText properties and leave just the range objects, everything works, but no formatting is preserved, and the special fields are not copied. Now, there is this TextRetrievalMode property on the Range object, which is supposed to control if hidden characters and fields are retrieved with the Text property. This might work, but I haven't tried it yet when copying whole formatted Range objects.

Probably i'll end up copying formatting character by character - or word by word. Or i'll leave the whole idea of copying. In any case, it's very frustrating...

:|

keftebub
+3  A: 

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..

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:

(NOTE that I put // in front of each apostrophe-type VB comment so that the comment would be colored correctly)

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.

Image 1 Image 2 Image 3

That's it.

keftebub
+1 because that is epic code.