Should Word for 365 ComputeStatistics macro recognize IncludeFootnotesAndEndnotes argument in a Range? - vba

I want to write a Word macro that counts words in an active document section including footnote text.
This method works correctly when applied to the entire document:
SectionWordCount = ActiveDocument.ComputeStatistics(Statistic:=wdStatisticWords, _
IncludeFootnotesAndEndnotes:=True)
I can count words in an active section without the footnote text when this method, without the Include argument, is applied to a range defined as the active section:
SectionNum = Selection.Information(wdActiveEndSectionNumber)
Set myRange = ActiveDocument.Sections(SectionNum).Range
SectionWordCount = myRange.ComputeStatistics(Statistic:=wdStatisticWords)
However, this method fails when I attempt to set the Include argument true:
SectionNum = Selection.Information(wdActiveEndSectionNumber)
Set myRange = ActiveDocument.Sections(SectionNum).Range
SectionWordCount = myRange.ComputeStatistics(Statistic:=wdStatisticWords, _
IncludeFootnotesAndEndnotes:=True)
This provokes 'Run-time error 448: Named argument not found.'
Does anyone have a fix or work around in a macro that will provide the word count including footnotes for the active document section?
A Workaround That Has Its Own Error
Having seen no response, I will add this attempted workaround. Since the IncludeFootnotesAndEndnotes flag seems inoperable with a text range encompassing the active section, I extended the macro to iterate through each document footnote and add those individual footnote word counts to the total for the section. However, this encounters an issue that the footnotes subject to iteration are not limited to footnotes within the active section, so that the final word count captures all document footnotes (it overcounts).
So, how can I limit the iteration to just the footnotes within the active section?
This is the revised macro:
Sub SectionWordCount()
Dim SectionWordCount As Integer
Dim SectionNum As Integer
Dim f As Footnote
Dim fTempCount As Integer
SectionWordCount = 0
SectionNum = 0
fTempCount = 0
SectionNum = Selection.Information(wdActiveEndSectionNumber)
Set myRange = ActiveDocument.Sections(SectionNum).Range
SectionWordCount = myRange.ComputeStatistics(Statistic:=wdStatisticWords)
' Now get word count in each footnote and accumulate in <fTempCount>
For Each f In myRange.Footnotes
' For some reason Word is iterating over entire document (all footnotes) rather than those associated with the active section.
fTempCount = fTempCount + f.Range.ComputeStatistics(Statistic:=wdStatisticWords)
Next
SectionWordCount = SectionWordCount + fTempCount
MsgBox "Section " & SectionNum & vbCrLf & _
"The current section has " & SectionWordCount & " words including footnotes."
End Sub
Revised and working macro
Sub SectionWordCount()
Dim SectionWordCount As Integer
Dim SectionNum As Integer
Dim f As Footnote
Dim fTempCount As Integer
SectionWordCount = 0
SectionNum = 0
fTempCount = 0
SectionNum = Selection.Information(wdActiveEndSectionNumber)
Set myRange = ActiveDocument.Sections(SectionNum).Range
SectionWordCount = myRange.ComputeStatistics(Statistic:=wdStatisticWords)
If myRange.Footnotes.Count > 0 Then
For idx = 1 To myRange.Footnotes.Count
Set f = myRange.Footnotes(idx)
fTempCount = fTempCount + f.Range.ComputeStatistics(Statistic:=wdStatisticWords)
Next
End If
SectionWordCount = SectionWordCount + fTempCount
MsgBox "Section " & SectionNum & vbCrLf & _
"The current section has " & SectionWordCount & " words including footnotes."
End Sub

IncludeFootnotesAndEndnotes is only available on document-level (https://learn.microsoft.com/de-de/office/vba/api/word.document.computestatistics) but not on range-level (https://learn.microsoft.com/de-de/office/vba/api/word.range.computestatistics)
There seems to be a bug in VBA.
You have to iterate footnotes by index not via the collection:
' Now get word count in each footnote and accumulate in <fTempCount>
If myrange.Footnotes.Count > 0 Then
For i = 1 To myrange.Footnotes.Count
Set f = myrange.Footnotes(i)
' For some reason Word is iterating over entire document (all footnotes) rather than those associated with the active section.
fTempCount = fTempCount + f.Range.ComputeStatistics(Statistic:=wdStatisticWords)
Next
end if
```

Related

Writing Excel data to Word content controls without error messages

This question is about using content controls to move data values from Excel to Word in VBA. Please note I have enabled the "Microsoft Word 16.0 Object Library" under references in the MSExcel VBA environment.
My project needs to send Excel data to specific places in a Word document.
PROBLEM: It seems I am not using the contentcontrols properly and keep getting runtime errors I'm not finding much information about. Either RTE-438
Object doesen't support this method
or RTE-424
Object Required
Description of what the code does: There are two baseline workbooks with multiple worksheets. Another analysis workbook uses each of these is programmed with VLOOKUP(INDIRECT...),) to generate tables for reports put into a word document. A Variant is used to change the tabs being sourced in the baseline workbook. The analysis is basically CATS-DOGS=PETS. on each cycle through, tables that are not informational (no difference between two baseline workbooks) are skipped and the next tab is analyzed. If a table is informative, then a PDF is produced. The report (a Word document) is updated. Table is added to the report. Upon completion, the next tab or evaluation table is considered.
Sub CommandButton1_Click()
Dim Tabs(0 To 18) As Variant
Tabs(0) = "01"
Tabs(1) = "02"
Tabs(2) = "03"
Tabs(3) = "03"
Tabs(4) = "04"
Tabs(5) = "05"
Tabs(6) = "06"
Tabs(7) = "07"
Tabs(8) = "08"
Tabs(9) = "09"
Tabs(10) = "10"
Tabs(11) = "11"
Tabs(12) = "12"
Tabs(13) = "13"
Tabs(14) = "14"
Tabs(15) = "15"
Tabs(16) = "16"
Tabs(17) = "17"
Tabs(18) = "18"
Dim xlApp As Object
On Error Resume Next
Set xlApp = GetObject("excel.applicaiton")
If Err.Number = 429 Then
Err.Clear
Set xlApp = CreateObject("excel.applicaiton")
End If
On Error GoTo 0
Dim controlThis As String ' the controlThis variable is to the address of the particular data unit that should be passed to a word.documents.contentcontrols to update the text in the word document based on the change in the actual data.
Dim NetworkLocation As String
NetworkLocation = "\\myServer\myFolder\mySubfolder\"
Dim CATS As String
CATS = "kittens.xlsx"
Excel.Application.Workbooks.Open FileName:=(NetworkLocation & "Other Subforder\ThisWway\" & CATS)
Dim DOGS As String
DOGS = "puppies.xlsx"
Excel.Application.Workbooks.Open FileName:=(NetworkLocation & "differentSubfolder\ThatWay\" & DOGS)
'Populates the array with analysis tables
Dim Temples As Object
Dim Template(3 To 9) As Variant
Template(3) = "\3\EVAL Table 3.xlsx"
Template(4) = "\4\EVAL Table 4.xlsx"
Template(5) = "\5\EVAL Table 5.xlsx"
Template(6) = "\6\EVAL Table 6.xlsx"
Template(7) = "\7\EVAL Table 7.xlsx"
Template(8) = "\8\EVAL Table 8.xlsx"
Template(9) = "\9\EVAL Table 9.xlsx"
Dim strXLname As String
Dim opener As Variant
For Each opener In Template
strXLname = NetworkLocation & "Other Subfolder\EVAL Tables\WonderPets" & opener
Excel.Application.Workbooks.Open FileName:=strXLname
Dim currentDiffernce As Long
currentDifference = ActiveSheet.Cells(5, 6).Value
'This code cycles through the different EVAL Table templates
ActiveSheet.Cells(1, 1).Value = CATS
ActiveSheet.Cells(2, 1).Value = DOGS
Dim k As Variant
For Each k In Tabs
controlThis = k & "-" & eval 'passes a string to the wdApp.contentcontrol
ActiveSheet.Rows.Hidden = False
ActiveSheet.Cells(1, 4).Value = k 'initialize k
ActiveSheet.Calculate
DoEvents
currentDifference = ActiveSheet.Cells(5, 6).Value 'stop blank tables from being produced using the total delta in the preprogrammed spreadsheet
If currentDifference = 0 Then 'since the total difference in the current analysis is 0 this bit of code skips to the next WonderPet
Else
controlThis = k & "-" & opener '(Was eval as variant used with thisTable array)passes a string to the wdApp.contentcontrol
Call PDFcrate 'Print the Table to a PDF file. Worked well and was made a subroutine.
Dim objWord As Object
Dim ws As Worksheet
'Dim cc As Word.Application.ContentControls
Set ws = ActiveWorkbook.Sheets("Sheet1")
Set objWord = CreateObject("Word.Application")
objWord.Visible = True
objWord.Documents.Open FileName:="myFilePath\Myfile.docx", noencodingdialog:=True ' change as needed
With objWord.ActiveDocument
.ContentControls(controlThis & " cats").Range.Text = eval.ActiveSheet.Cells(5, 4) 'These are the updates to the report for each content control with the title. Substituting SelectContentControlsByTitle() gives RTE-424 'Object Required'
.ContentControls(controlThis & " dogs").Range.Text = eval.ActiveSheet.Cells(5, 5)
.ContentControls(controlThis & " pets").Range.Text = eval.ActiveSheet.Cells(5, 6)
.ContentControls(controlThis & " Table).range. = 'Need to add the PDF to the report, perhaps using an RichTextConentConrols...additional suggestions welcomed (haven't researched it yet).
End With
Set objWord = Nothing
Word.Application.Documents.Close SaveChanges:=True 'Saves and Closes the document
Word.Application.Quit 'quits MS Word
End If
Next 'repeats for each tab with name "k" in the workbooks
Excel.Application.Workbooks(strXLname).Close
Next 'repeat for each evalTable
Excel.Application.Workbooks(CATS).Close
Excel.Application.Workbooks(DOGS).Close
End Sub
Word's content controls can't be picked up using a string as the index value the way other things can. The following line from the code sample in the question can't work:
.ContentControls(controlThis & " cats").Range.Text = eval.ActiveSheet.Cells(5, 4)
The only valid index value for a ContentControl is ID, which is a long number (GUID) assigned by the Word application when a ContentControl is generated.
The reason for this is that more than one content control can have the same Title (name) and/or Tag. Since this information is not unique it can't be used to pick up a single content control.
Instead, code needs to use either Document.SelectContentControlsByTitle or Document.SelectContentControlsByTag. These return an collection of content controls that meet the specified criterium. For example:
Dim cc as Word.ContentControls ' As Object if late-binding is used
With objWord.ActiveDocument
Set cc = .SelectContentControlsByTitle(controlThis & " cats")
'Now loop all the content controls in the collection to work with individual ones
End With
If it's certain there's only one content control with the Title, or only the first one is wanted, then it's possible to do this:
Dim cc as Word.ContentControl ' As Object if late-binding is used
With objWord.ActiveDocument
Set cc = .SelectContentControlsByTitle(controlThis & " cats").Item(1)
cc.Range.Text = eval.ActiveSheet.Cells(5, 4)
End With
Tip 1: Using ActiveDocument is not considered good practice for Word. As with ActiveCell (or anything else) in Excel, it's not certain that the "active" thing is the one that should be manipulated. More reliable is to use an object, which in this case can be assigned directly to the document being opened. Based on the code in the question:
Dim wdDoc as Object 'Word.Document
Set wdDoc = objWord.Documents.Open(FileName:="myFilePath\Myfile.docx", noencodingdialog:=True)
With wdDoc 'instead of objWord.ActiveDocument
Tip 2: Since the code in the question targets multiple content controls, rather than declaring multiple content control objects it might be more efficient to put the titles and values in an array and loop that.
This fixed it... looping through may have been the thing that got me unstuck.
The use of the plural ContentControls or singular ContentControl didn't seem to matter. My next trick is to get the tables into the word document... any thoughts?
Set wdDoc = Word.Application.Documents(wdDocReport)
Dim evalData(0 To 2) As Variant
evalData(0) = " CATS"
evalData(1) = " DOGS"
evalData(2) = " PETS"
Dim j As Variant
Dim i As Integer
i = 4
For Each j In evalData
Dim cc As Word.ContentControls
With Word.Application.Documents(wdDocReport)
.SelectContentControlsByTitle(controlThis & j).Item (1).Range.Text = ActiveWorkbook.ActiveSheet.Cells(5, i).Value
i = i + 1
End With
Next
Word.Application.Documents.Close SaveChanges:= True
Word.Application.Quit
Only one worksheet ever takes focus so the ActiveWorkbook and ActiveWorksheet didn't hurt me here

ActiveDocument.Printout issue

I have two word documents, source and target. My target document is pulling values from a table inside source document and putting those concatenated values stored inside a variable named ReportHeader into it's page header. I have used two For-Next loops, the outer loops takes care of designated rows inside source document and this loop begins at 6th row till count of total rows inside that table.
My inner loop named "For xPages = 1 To numPages" takes care of number of parges required for each Annexure that it finds inside the table and loops through found number of pages for a particular Annexure reference.
Below is reference screenshot of my table. Please ignore the fact the few preceding lines of my tableare not being shown here. My business begins with 6th row that shows Annexure A.
Everything works fine as long as I test values in Debug.print or Msgbox but when I sent these values for printing using ActiveDocument.PrintOut, I notice an abnormal printing behaviour. First few rows starting at row 6 of table are ignored and later not all the pages are sent to printing.
Any feedback from you guys would be much appreciated.
Thanks
Syed
Sub PrintMyHeaders()
Dim r As Range
Dim sourceDoc, jobNumber, AnnexureRaw, Annexure, ReportHeader As String
Dim numPages As Integer
Application.ScreenUpdating = False
jobNumber = InputBox("Enter job number")
sourceDoc = ActiveDocument.Name
ActiveDocument.Tables(3).Range.ListFormat.RemoveNumbers
Set r = ActiveDocument.Tables(3).Range
For Each doc In Documents
If doc.Name = "Template.doc" Then Found = True
Next doc
If Found <> True Then
Documents.Open FileName:="C:\Users\smi\Documents\Template.doc"
Else
Documents("Template.doc").Activate
End If
Documents(sourceDoc).Activate
For i = 6 To r.Rows.Count
AnnexureRaw = Replace(r.Rows(i).Cells(2).Range.Text, "", "")
Annexure = Replace(AnnexureRaw, Chr(13), "")
numPages = Val(r.Rows(i).Cells(3).Range.Text)
For xPages = 1 To numPages
counter = counter + 1
ReportHeader = "PAGE " & xPages & " OF " & numPages & vbCrLf _
& "OUR REF: TKU-" & jobNumber & "/2018" & vbCrLf _
& "ANNEXURE : " & Chr(34) & Annexure & Chr(34)
Documents("Template.doc").Activate
If ActiveWindow.View.SplitSpecial <> wdPaneNone Then
ActiveWindow.Panes(2).Close
End If
If ActiveWindow.ActivePane.View.Type = wdNormalView Or ActiveWindow. _
ActivePane.View.Type = wdOutlineView Then
ActiveWindow.ActivePane.View.Type = wdPrintView
End If
ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader
Selection.Font.Name = "Arial"
Selection.Font.Size = 8
Selection.Font.Bold = True
Selection.Text = ReportHeader
Selection.ParagraphFormat.LineSpacingRule = wdLineSpaceExactly
Selection.ParagraphFormat.LineSpacing = 6
Selection.ParagraphFormat.Alignment = wdAlignParagraphRight
ActiveDocument.PrintOut
'Debug.Print ReportHeader & vbCrLf
Documents(sourceDoc).Activate
Next xPages
Next
Documents("template.doc").Activate
ActiveDocument.Close SaveChanges:=wdDoNotSaveChanges
Documents(sourceDoc).Activate
Application.ScreenUpdating = True
End Sub
When printing out documents in relatively quick succession, things can get "mixed up" if background printing is turned on. This is an option in Word:
File/Options/Advanced, section "Print"
In the object model, to turn it off programmatically you can use the following. If the user likes having it turned on, save the current setting, turn it off, then restore the setting at the end of the code:
Options.PrintBackground = False
Since speed of execution is a concern, your code can be optimized. The following suggestions can also help to make it more self-documenting. Note that I'm not testing, just writing from the top of my head, so I may make a typo or two...
Put Option Explicit at the top of your code modules. This will save you from frustrating error messages if you mistype a variable name.
Use declared objects throughout. Referring back to ActiveDocument each time is less efficient (VBA has to figure out which it is, every time. Also, the active document could change during code execution, which would mess things up.) Ditto for repeatedly requesting Tables(3).
If your concern when looping a collection is to ensure a certain member is present (a particular document, in your case) you can use Exit For to break off the loop before all members have been queried.
It's not necessary to activate a document in order to work with it in code. Once you have Document objects, that's all you need.
It's also not necessary to fiddle with the Views in order to work with a header or footer. I've deleted those lines.
I hope I've kept "everything straight"!
Option Explicit
Sub PrintMyHeaders()
Dim r As Range
Dim sourceDoc, jobNumber, AnnexureRaw, Annexure, ReportHeader As String
Dim numPages As Integer
Dim sourceTable as Word.Table, doc as Word.Document
Dim tDoc as Word.Document
Application.ScreenUpdating = False
jobNumber = InputBox("Enter job number")
Set sourceDoc = ActiveDocument
Set sourceTable = sourceDoc.Tables(3)
sourceTable.Range.ListFormat.RemoveNumbers
Set r = sourceTable.Range
For Each doc In Documents
If doc.Name = "Template.doc" Then
Found = True
Exit For
End If
Next doc
If Found <> True Then
Set tDoc = Documents.Open(FileName:="C:\Users\smi\Documents\Template.doc")
Else
Set tDoc = Documents("Template.doc")
End If
For i = 6 To r.Rows.Count
AnnexureRaw = Replace(r.Rows(i).Cells(2).Range.Text, "", "")
Annexure = Replace(AnnexureRaw, Chr(13), "")
numPages = Val(r.Rows(i).Cells(3).Range.Text)
For xPages = 1 To numPages
counter = counter + 1
ReportHeader = "PAGE " & xPages & " OF " & numPages & vbCrLf _
& "OUR REF: TKU-" & jobNumber & "/2018" & vbCrLf _
& "ANNEXURE : " & Chr(34) & Annexure & Chr(34)
Dim rngHeader as Word.Range
Set rngHeader = tDoc.Sections(1).Headers(wdHeaderFooterPrimary).Range
rngHeader.Font.Name = "Arial"
rngHeader.Font.Size = 8
rngHeader.Font.Bold = True
rngHeader.Text = ReportHeader
rngHeader.ParagraphFormat.LineSpacingRule = wdLineSpaceExactly
rngHeader.ParagraphFormat.LineSpacing = 6
rngHeader.ParagraphFormat.Alignment = wdAlignParagraphRight
tDoc.PrintOut
'Debug.Print ReportHeader & vbCrLf
Next xPages
Next
tDoc.Close SaveChanges:=wdDoNotSaveChanges
Application.ScreenUpdating = True
End Sub

Excel VBA not splitting named ranges/rows when using page break in macro

Currently I'm trying to print a sheet in pdf in excel and then let a code set the pagebreaks automatically. The code should not break up named ranges in the sheet. The named ranges have multiple rows attached to them, so those rows should stay together on one page under that named range. On this sheet there are also hidden named ranges with rows. The code should not take those in account.
I have tried the code below, but I keep getting an error. See image below the code.
Sub CommandButton1_Click()
'Change pages breaks so it is only split on a named range top or bottom
Dim n As Name
Dim RngRows() As Integer
Dim PageBreakRows() As Integer
Dim NumPageBreaks As Integer
Dim i As Integer
Dim TtlRows As Integer
Dim MaxRowsPerPage As Integer
Dim strBreakRow As String
Dim intBreakRow As Integer
i = 1
TtlRows = 0
NumPageBreaks = 0
MaxRowsPerPage = 17
'clear any settings that exist
ActiveSheet.ResetAllPageBreaks
For Each n In ActiveWorkbook.Names
'operate only on ranges that start with RANGE in their name
If Mid(n.Name, 1, 1) = "P" Then
'if named range is visible
If Range(n).EntireRow.Hidden = False Then
Debug.Print "Processing Range " & n.Name & " with #"
Rows = " & Range(n).Rows.Count"
'add # rows in range to row count.
TtlRows = TtlRows + Range(n).Rows.Count
'if rount count larger than max allowable add a page break
If TtlRows > MaxRowsPerPage Then
'take first row of current named range and add page break
ActiveSheet.HPageBreaks.Add before:=Range(Range(n).Rows(1).Address)
'update Totl row count
TtlRows = Range(n).Rows.Count
End If
Else
Debug.Print "Range hidden: " & n.Name & " with # rows=" & Range(n).Rows.Count
End If 'end visible check
End If 'end name check
Next
End Sub
All the references are correct.
So I have no idea what is wrong here. Does anybody know the solutions? Or know a better code from experience?
New image after deleting line: "Rows = " & Range(n).Rows.Count" "

VBA to insert reference page into MS word endnote

Book endnotes often forgo superscript numbers for page numbers. E.g., instead of
Abe Lincoln was assassinated with a pistol.^33
:
33. A single-shot derringer pistol.
books by several authors write
Abe Lincoln was assassinated with a pistol.
:
Page 297. Abe Lincoln was shot single-shot derringer pistol.
Word doesn't have this feature, so I believe it would have to be a Macro. I came up with simple code below that loops through all of the endnotes and adds
"Page ???. "
before each endnote, but what does "???" need to be to correctly insert the page number in my manuscript that the citation's located on?
Sub RedefineExistingEndNotes()
Dim fn As Endnote
For Each fn In ActiveDocument.Endnotes
fn.Range.Paragraphs(1).Range.Font.Reset
fn.Range.Paragraphs(1).Range.Characters(1).InsertBefore "Page" & "???" & " - "
Next fn
End Sub
Try the below VBA code:
Sub InsertPageNumberForEndnotes()
Dim endNoteCount As Integer
Dim curPageNumber As Integer
If ActiveDocument.Endnotes.Count > 0 Then
For endNoteCount = 1 To ActiveDocument.Endnotes.Count
Selection.GoTo What:=wdGoToEndnote, Which:=wdGoToAbsolute, Count:=endNoteCount
curPageNumber = Selection.Information(wdActiveEndPageNumber)
ActiveDocument.Endnotes(endNoteCount).Range.Select
ActiveDocument.Application.Selection.Collapse (WdCollapseDirection.wdCollapseStart)
ActiveDocument.Application.Selection.Paragraphs(1).Range.Characters(1).InsertBefore "Page " & CStr(curPageNumber) & " - "
Next
End If
End Sub
An alternative might be to use PAGEREF fields and hide the endnote references, e.g.
Sub modifyEndNotes()
Const bookmarkText As String = "endnote"
Dim en As Word.Endnote
Dim rng As Word.Range
For Each en In ActiveDocument.Endnotes
en.Reference.Bookmarks.Add bookmarkText & en.Index
en.Reference.Font.Hidden = True
Set rng = en.Range
rng.Paragraphs(1).Range.Font.Hidden = True
rng.Collapse WdCollapseDirection.wdCollapseStart
rng.Text = "Page . "
rng.SetRange rng.End - 2, rng.End - 2
rng.Fields.Add rng, WdFieldType.wdFieldEmpty, "PAGEREF " & bookmarkText & en.Index & " \h", False
'if necessary...
'rng.Fields.Update
en.Range.Font.Hidden = False
Next
Set rng = Nothing
End Sub
For a second run, you'd need to remove and re-insert the text and fields you had added.
Unfortunately, a further look suggests that it would be difficult, if not impossible, to hide the endnote references (in the endnotes themselves) without hiding the paragraph marker at the end of the first endnote para, which means that all the endnotes will end up looking like a single messy note. So I deleted this Answer.
However, the OP thought the approach could be modified in a useful way so I have undeleted. I can't re-research it right away but some possibilities might be to replace every endnote mark by a bullet (as suggested by the OP) or perhaps even something as simple as a space or a "-".
For example, something like this (which also hides the references using a different technique)...
Sub modifyEndNotes2()
' this version also formats the endnotes under page headings
Const bookmarkText As String = "endnote"
Dim en As Word.Endnote
Dim f As Word.Field
Dim i As Integer
Dim rng As Word.Range
Dim strSavedPage As String
strSavedPage = ""
For Each en In ActiveDocument.Endnotes
en.Reference.Bookmarks.Add bookmarkText & en.Index
Set rng = en.Range
rng.Collapse WdCollapseDirection.wdCollapseStart
If CStr(en.Reference.Information(wdActiveEndPageNumber)) <> strSavedPage Then
strSavedPage = CStr(en.Reference.Information(wdActiveEndPageNumber))
rng.Text = "Page :-" & vbCr & " - "
rng.SetRange rng.End - 6, rng.End - 6
rng.Fields.Add rng, WdFieldType.wdFieldEmpty, "PAGEREF " & bookmarkText & en.Index & " \h", False
rng.Collapse WdCollapseDirection.wdCollapseEnd
Else
rng.Text = "- "
End If
Next
If ActiveDocument.Endnotes.Count > 1 Then
ActiveDocument.Styles(wdStyleEndnoteReference).Font.Hidden = True
Else
ActiveDocument.Styles(wdStyleEndnoteReference).Font.Hidden = False
End If
Set rng = Nothing
End Sub
In the above case, notice that there is only one link to each page, that formatting might be needed to make it obvious that it is a link, and so on.

Word VBA Range from Words Object

Context: I'm writing a Word VBA macro that loops through each word in a document, identifies the acronyms, and creates an acronym list as a new document. The next step is to identify whether the acronym is in parentheses (meaning it's likely spelled out) on its first occurrence. So, I'd like to expand the range to find out whether the characters on either side of the word are "(" and ")".
Issue: I can't figure out how to assign the range of the word to a range variable that I can then expand. Using "rngWord = ActiveDocument.Words(k)" (where k is the counter variable) gets the error #91, Object Variable or With block variable not set. So presumably there's a method or property for Words that I'm missing. Based on Microsoft's VBA reference, though, the members of the Words collection are already ranges, so I'm stumped on why I can't assign one to a range variable.
Dim intArrayCount As Integer
Dim booAcroMatchesArray As Boolean
Dim intNextAcro As Integer
Dim strAcros(1000) As String
Dim strContext(1000) As String
Dim booAcroDefined(1000) As Boolean
Dim strTestMessage As String
i = 1
booAcroMatchesArray = False
intNextAcro = 1
For k = 1 To ActiveDocument.Words.Count
strWord = ActiveDocument.Words(k).Text
rngWord = ActiveDocument.Words(k) //The line that's missing something
MsgBox strWord
rngWord.Expand Unit:=wdCharacter
strWordPlus = rngWord
MsgBox strWordPlus
strWord = Trim(strWord)
If strWord = UCase(strWord) And Len(strWord) >= 2 And IsLetter(Left(strWord, 1)) = True Then
'MsgBox ("Word = " & strWord & " and Length = " & Len(strWord))
For intArrayCount = 1 To 1000
If strWord = strAcros(intArrayCount) Then booAcroMatchesArray = True
Next intArrayCount
'MsgBox ("Word = " & strWord & " Match = " & booAcroMatchesArray)
If booAcroMatchesArray = False Then
strAcros(intNextAcro) = strWord
intNextAcro = intNextAcro + 1
End If
booAcroMatchesArray = False
End If
Next k
Object variables need to be assigned using Set. Instead of:
rngWord = ActiveDocument.Words(k)
use
Set rngWord = ActiveDocument.Words(k)
This small sample worked correctly:
Sub WordRangeTest()
Dim rngWord As Range
Set rngWord = ActiveDocument.Words(1)
MsgBox (rngWord.Text)
End Sub