PDA

View Full Version : [SOLVED:] Enumerating Footnotes Crashes Word



UniquarkJ
07-13-2011, 01:33 PM
Hi All,
This is my first post, so please excuse any etiquette breaches. I'm trying to create an errata list from a document with tracked changes: Page #, Line #, Type of change, Changed text. My macro works perfectly for the main text, but it randomly crashes when it gets into the footnotes. The crash happens as soon as I try to access the revisions in a new footnote, but not for every footnote. Word also crashes if I step up to that line of code and then try to use the Locals viewer to see the contents of that variable. So, I'm looking for a different way to do it. The code for the footnotes is pasted below. Please suggest alternatives.
By the way, I'm running Word 2011 on Mac OS X 10.6

Thanks.


Dim change As Revision
Dim curNote As Footnote
Dim rowCount As Long
Dim docName As String
Dim errataList As Table
Dim changeRange As Range
If Documents(docName).Footnotes.count > 0 Then
For Each curNote In Documents(docName).Footnotes
If curNote.Range.Revisions.count > 0 Then
For Each change In curNote.Range.Revisions
Set changeRange = curNote.Range.Duplicate
changeRange.SetRange Start:=changeRange.Start, End:=change.Range.Start
errataList.Rows.Add
rowCount = rowCount + 1
errataList.Cell(rowCount, 1).Range.Text = Str(change.Range.Information(wdActiveEndAdjustedPageNumber))
errataList.Cell(rowCount, 2).Range.Text = Str(curNote.Index)
errataList.Cell(rowCount, 3).Range.Text = Str(changeRange.ComputeStatistics(wdStatisticLines))
errataList.Cell(rowCount, 4).Range.Text = Switch(change.Type = wdRevisionDelete, "Delete", change.Type = wdRevisionInsert, "Insert", change.Type = wdRevisionProperty, "Format", True, "Unknown")
errataList.Cell(rowCount, 5).Range.Text = change.Range.Text
ActiveDocument.Save
Set changeRange = Nothing
Selection.EndKey unit:=wdStory
Next
End If
Next
End If

macropod
07-15-2011, 01:45 AM
Hi Uniquarkj,

Which line in the code is highlighted when the code fails, and what is the error message?

FWIW, you might get better/more comprehensive results with:

Dim Rev As Revision
Dim FtNt As Footnote
Dim docName As String
Dim errataList As Table
Dim RngRev As Range
Dim RevType As String
With Documents(docName)
If .Footnotes.Count > 0 Then
For Each FtNt In .Footnotes
With FtNt.Range
If .Revisions.Count > 0 Then
For Each Rev In .Revisions
Set RngRev = .Duplicate
RngRev.End = Rev.Range.Start
With errataList
.Rows.Add
With .Rows.Last
.Cells(1).Range.Text = FtNt.Range.Information(wdActiveEndAdjustedPageNumber)
.Cells(2).Range.Text = FtNt.Index
.Cells(3).Range.Text = RngRev.ComputeStatistics(wdStatisticLines)
Select Case Rev.Type
Case 0: RevType = "No revision"
Case 1: RevType = "Insertion"
Case 2: RevType = "Deletion"
Case 3: RevType = "Property changed"
Case 4: RevType = "Paragraph number changed"
Case 5: RevType = "Field display changed"
Case 6: RevType = "Revision marked as reconciled conflict"
Case 7: RevType = "Revision marked as a conflict"
Case 8: RevType = "Style changed"
Case 9: RevType = "Replaced"
Case 10: RevType = "Paragraph property changed"
Case 11: RevType = "Table property changed"
Case 12: RevType = "Section property changed"
Case 13: RevType = "Style definition changed"
Case 14: RevType = "Content moved from"
Case 15: RevType = "Content moved to"
Case 16: RevType = "Table cell inserted"
Case 17: RevType = "Table cell deleted"
Case 18: RevType = "Table cells merged"
Case Else: RevType = "Unknown Revision"
End Select
.Cells(4).Range.Text = RevType
.Cells(5).Range.Text = Rev.Range.Text
End With
End With
Next
End If
End With
Next
ActiveDocument.Save
Set RngRev = Nothing
End If
End With

UniquarkJ
07-15-2011, 09:03 AM
Hi Macropod,


Which line in the code is highlighted when the code fails, and what is the error message?

My code always fails with the inner For Each loop highlighted ("For Each change In curNote.Range.Revisions"). I don't get any error message from VBA because the failure brings down Word in its entirety. The message I get from Microsoft Error Reporting is "Microsoft Word has encountered a problem and needs to close. We are sorry for the inconvenience." That's the same message I get whenever Word crashes for any reason.

The crash never happens in the first two footnotes (which do have revisions). Of course, the code skips over the next few footnotes because there are no revisions in them. The crash usually happens in the next footnote that does have revisions.

I've tried this with a copy of the document I actually need to process as well as a clean DOCX mock up with revisions in the main text and the footnotes. The code crashes in both cases, so I'm guessing that the problem is not caused by corruption in the document.


FWIW, you might get better/more comprehensive results with:

Thank you very much for suggesting a better version of my code. I can see that your code is much more comprehensive and cleaner. Unfortunately, this version also crashes in the same way. The first two times it crashed, I did not see exactly which line it was on, but I don't think it was on the For Each line that was crashing my code. The third time it crashed, when I was watching more carefully, it did crash on the same For Each line.

The only code I added to your code to make it run was the set up of the actual errata document:


docName = ActiveDocument.Name
Documents.Add
Set errataList = ActiveDocument.Tables.Add(Selection.Range, 1, 5)
errataList.Cell(1, 1).Range.Text = "Page"
errataList.Cell(1, 2).Range.Text = "Footnote"
errataList.Cell(1, 3).Range.Text = "Line"
errataList.Cell(1, 4).Range.Text = "Action"
errataList.Cell(1, 5).Range.Text = "Affected text"
ActiveDocument.Save


This code was added before the first With statement, so it does not participate in the looping.

If you don't mind, I'd like to ask a few questions about your code so I can learn more about VBA.

1. I noticed that you moved the Save line outside of the For Each loops. Is this because such frequent saving causes problems in your experience? I put the save there because I was experiencing this crashing and wanted to know how far the code got.

2. I also noticed that you moved the release of the temporary range object outside the For Each loops. Of course, you are not aware of this, but this code is at the end of the macro, so I assume that releasing the object there is the same as not releasing it at all. I put the release inside the For Each loops to see if the crashing was being caused by a need for more garbage collection, but it did not seem to help. In your experience, does VBA handle garbage collection well?

3. I can see that the With structures are cleaner and easier to read. In your experience, do they do anything to reduce this type of crashing or reduce any other functionality problems?

4. Finally, does this code work correctly on your computer? What version of Word and what operating system are you running?

Again, I very much appreciate your help.

Frosty
07-15-2011, 09:22 AM
I'm not in front of a computer at the moment, but can you recreate this crash bug every time on a new document? Or is it only crashing on a specific document?

Also, can you duplicate this crash bug in a clean session of Word (started from winword /a in the run command)

Obviously, if it's a crash bug, it has nothing to do with your coding (efficient or otherwise), since nothing you do in VBA should cause the winword.exe to crash. Of course, that's just a should. In reality, there are ways to avoid crash bugs, but you have to be really specific in identifying the crash bug before you start trying to code around it.

Best way to do it is to write code which creates a new document and sets up the scenario that creates the crash (in your case, create a new document, add some text, add some footnotes, turn on track changes, delete/adjust/add some footnotes).

Then write the simplest version of the code which will crash that newly created document... Then post the two and bits of code and we can probably a) at least get Microsoft to put it on the bug list and b) provide some work around code to avoid the crash

Frosty
07-15-2011, 11:40 AM
Oh jeez, and I just noticed that you're running Word 2011 on the Mac OS. My above advice applies, but the likelihood of finding a crash bug for that exact circumstance on a different version (and different OS) is pretty low.

macropod
07-15-2011, 04:31 PM
Hi Uniquarkj,

With the footnote that the crash occurs on, is there anything different about it compared to the others (eg spans more than one page, kind of change)? What happens if you accept the change there, or delete that footnote?

Regarding your questions:
1. A single save at the end of processing is more efficient than saving at each step. Saving at each step in a rapidly-executing loop may indeed cause problems.

2. Since you're redefining the target range's scope, repeatedly setting it to nothing is simply inefficient.

3. Using With ... End With is more efficient than calling methods from their parents and, IMHO, usually makes the code easier to read. I wouldn't expect it to affect application stability, though.

4. I've only tested it with one footnote, containing a revision. This is on a Win7 64-bit system running 32-bit installations of Office 2003 & Office 2010. If you could post a cut-down copy of the problem document in which the code fails on your system, I could do more testing with a document with known issues.

It may be that there is a fault in your Word installation. Have you tried repairing it? (Don't ask me how - I don't use a Mac and the procedure there is different to the PC procedure.

UniquarkJ
07-15-2011, 04:37 PM
Hi Frosty,

Thanks for your suggestions. I understand that not everyone on this forum will be using the same system I'm using, but I'm hoping that someone can point me to a way around this problem. I have done as you suggested. The following code generates a very simple document with three footnotes in the first (and only) paragraph. Then it makes the same change to each of those footnotes and asks the user to save the document. It works fine on my system. I don't think I'm using any platform-dependent features, so this code should create essentially the same document on any standard Word installation.


Sub CreateTestCase()
'Create the document
Documents.Add
With ActiveDocument
With .Range
.Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras congue laoreet posuere."
.Footnotes.Add Range:=ActiveDocument.Characters(11), Text:="This is the first footnote."
.Footnotes.Add Range:=ActiveDocument.Characters(69), Text:="This is the second footnote."
.Footnotes.Add Range:=ActiveDocument.Characters(87), Text:="This is the third footnote."
End With
'Track some changes in the footnotes
.TrackRevisions = True
With .Footnotes(1).Range
.Words(3).Delete
.Words(4).InsertAfter ("the ")
End With
With .Footnotes(2).Range
.Words(3).Delete
.Words(4).InsertAfter ("the ")
End With
With .Footnotes(3).Range
.Words(3).Delete
.Words(4).InsertAfter ("the ")
End With
.Save
End With
End Sub


Next, I used the following the code to create the errata list. This is the code contributed by macropod minus the unused cases and with the addition of my code to create the blank document with a table in it.



Sub ErrataList1()
Dim Rev As Revision
Dim FtNt As Footnote
Dim docName As String
Dim errataList As Table
Dim RngRev As Range
Dim RevType As String
docName = ActiveDocument.Name
Documents.Add
Set errataList = ActiveDocument.Tables.Add(Selection.Range, 1, 5)
errataList.Cell(1, 1).Range.Text = "Page"
errataList.Cell(1, 2).Range.Text = "Footnote"
errataList.Cell(1, 3).Range.Text = "Line"
errataList.Cell(1, 4).Range.Text = "Action"
errataList.Cell(1, 5).Range.Text = "Affected text"
ActiveDocument.Save
With Documents(docName)
If .Footnotes.count > 0 Then
For Each FtNt In .Footnotes
With FtNt.Range
If .Revisions.count > 0 Then
For Each Rev In .Revisions
Set RngRev = .Duplicate
RngRev.End = Rev.Range.Start
With errataList
.Rows.Add
With .Rows.last
.Cells(1).Range.Text = FtNt.Range.Information(wdActiveEndAdjustedPageNumber)
.Cells(2).Range.Text = FtNt.Index
.Cells(3).Range.Text = RngRev.ComputeStatistics(wdStatisticLines)
Select Case Rev.Type
Case 1: RevType = "Insertion"
Case 2: RevType = "Deletion"
Case Else: RevType = "Unknown Revision"
End Select
.Cells(4).Range.Text = RevType
.Cells(5).Range.Text = Rev.Range.Text
End With
End With
ActiveDocument.Save
Set RngRev = Nothing
Next
End If
End With
Next
End If
End With
End Sub


Just as with my code on my other documents, the code crashes Word somewhat randomly, but usually at the "For Each Rev In .Revisions" line. It crashes almost every time, but if I step through the code very slowly, it seems to be able to make it through the document. Another possibility is that switching the focus away from Word and the Visual Basic Editor somehow avoids the crashing. When I simply clicked on the desktop before executing the "For Each Rev" line each time, the code did not crash.

Of course, that is not a usable solution for a document with several thousand changes in hundreds of footnotes. Given that I'm not going to rewrite Word 2011 and I don't have access to another version, I think I need a different way to step through the revisions of a footnote. Any ideas?

Thanks

UniquarkJ
07-15-2011, 04:57 PM
Hi macropod,

I must have been writing my post just as you were submitting yours. Thanks for your additional help.



With the footnote that the crash occurs on, is there anything different about it compared to the others (eg spans more than one page, kind of change)? What happens if you accept the change there, or delete that footnote?


I don't think there is anything special about that footnote because the problem happens in several different documents, including the test case discussed in my previous response to Frosty.



Regarding your questions:
1. A single save at the end of processing is more efficient than saving at each step. Saving at each step in a rapidly-executing loop may indeed cause problems.

2. Since you're redefining the target range's scope, repeatedly setting it to nothing is simply inefficient.

3. Using With ... End With is more efficient than calling methods from their parents and, IMHO, usually makes the code easier to read. I wouldn't expect it to affect application stability, though.

4. I've only tested it with one footnote, containing a revision. This is on a Win7 64-bit system running 32-bit installations of Office 2003 & Office 2010. If you could post a cut-down copy of the problem document in which the code fails on your system, I could do more testing with a document with known issues.

It may be that there is a fault in your Word installation. Have you tried repairing it? (Don't ask me how - I don't use a Mac and the procedure there is different to the PC procedure.

I would also expect all those saves to be problematic. However, I don't think they have anything to do with this particular problem. First, when I remove the save from the loop, the code still crashes. Second, when I run very similar code on the main text of several hundred pages and hundreds of revisions with the save in the loop, I get no crashing on several different documents.

I'm not surprised that you did not get the problem when testing the code on a single footnote. The code has never crashed for me on the first footnote. I'm also not surprised you did not get the crash because I suspect that this problem is caused by a problem in Word 2011. I would be interested to know if the problem recurs on other versions of Word, but that information does not help me with my immediate problem. I really just need to find a way around this problem using my current system.

I have not tried reinstalling the application, but I did try creating a fresh user account and running the code from there. That is the general procedure when testing for system corruption on a Mac. I got the same crashing problem on that new user that I get on my regular user.

Thanks for your help.

Frosty
07-15-2011, 06:15 PM
I'll take a look at your code over the weekend.

The first thing to try is a for x = 1 to .revisions.count loop instead of a for each loop, since the collection could be the problem.

But I'll have more ideas when I actually test. Thanks for doing the legwork.

Frosty
07-15-2011, 06:20 PM
Oh, and just as anecdotal evidence: I have come across many a Microsoft bug which did not cause a crash when stepping through the code, but did when simply running the code.

And in answer to an earlier question--my sense is that VBA garbage collection is abysmal, but that you rarely encounter problems because of it (since most people don't expect Word to work properly after a week of continuous uptime)

macropod
07-15-2011, 07:43 PM
Hi Uniquarkj,

I have not tried reinstalling the application, but I did try creating a fresh user account and running the code from there. That is the general procedure when testing for system corruption on a Mac. I got the same crashing problem on that new user that I get on my regular user.
I suspect all that would tell you is whether the problem is with the user account - not whether it's with the application. That's because all user accounts use the same underlying application code.

I'll take another look at the problem with your setup code later on when I have time.

macropod
07-16-2011, 10:24 PM
Hi Uniquarkj,

Do you want the good news first, or the bad news first?

The good news is that the macro runs fine with the Test Case on my PC. Or, depending on your perspective, maybe that's the bad news, because the bad news is that's all the good news I have at this time ...

UniquarkJ
07-24-2011, 08:42 AM
Well, that project is completed, so I probably won't be working on this code any more until I need it again. I did manage to get it working, mostly. As it turns out, the bug (I have confirmed that it exists on a fresh install of Snow Leopard and Word 2011) only affects the third or subsequent pass through a revisions collection. So, as can be seen in the code below, I work through the footnotes revision collection just once, keeping track of the footnote numbering myself, rather than working through the footnotes and each revision collections within them.

In case anyone needs it, I have included the full version below. Of course, use it at your own risk. The code is supposed to give me a list of all the tracked changes in a document, by page number and line number on the page. Naturally, there are a few oddities: 1. The line numbers in the footnotes are counted from the first line of the footnote, not from the top of the page as I wanted. 2. Sometimes, when a table row spans pages, the line numbering continues to count up and the page number does not change until the next row. 3. When a footnote spans pages, the page number reported is the page where the footnote starts and the line numbers keep incrementing until the next footnote as is to be expected from the first issue mentioned.

When I was working on this, I began a completely different set of code to actually step through a document one line at a time, grabbing the revisions on each line as the code went through. I ran out of time, so I never finished that version, but I did get far enough to see that it would work. However, it is rather complex because Word does not provide easy access to the concept of lines on a page, so footnotes and tables must be special cased.


Sub errataList()
Dim Rev As Revision
Dim curUnit, curRev, curRevPage As Long
Dim docName As String
Dim errataList As Table
Dim unitRange As Range
docName = ActiveDocument.Name
Documents.Add
Set errataList = ActiveDocument.Tables.Add(Selection.Range, 1, 5)
errataList.Rows.last.Cells(1).Range.Text = "Page"
errataList.Rows.last.Cells(2).Range.Text = "Footnote"
errataList.Rows.last.Cells(3).Range.Text = "Line"
errataList.Rows.last.Cells(4).Range.Text = "Action"
errataList.Rows.last.Cells(5).Range.Text = "Affected text"
ActiveDocument.Save
Set unitRange = Documents(docName).Range.Duplicate
curUnit = 1
With Documents(docName).Revisions
For curRev = 1 To .count
Set Rev = .Item(curRev)
With errataList
.Rows.Add
With .Rows.last
.Cells(1).Range.Text = Rev.Range.Information(wdActiveEndAdjustedPageNumber)
.Cells(2).Range.Text = "0Main text"
.Cells(3).Range.Text = Rev.Range.Information(wdFirstCharacterLineNumber)
Select Case Rev.Type
Case 0: .Cells(4).Range.Text = "No revision"
Case 1: .Cells(4).Range.Text = "Insertion"
Case 2: .Cells(4).Range.Text = "Deletion"
Case 3: .Cells(4).Range.Text = "Property changed"
Case 4: .Cells(4).Range.Text = "Paragraph number changed"
Case 5: .Cells(4).Range.Text = "Field display changed"
Case 6: .Cells(4).Range.Text = "Revision marked as reconciled conflict"
Case 7: .Cells(4).Range.Text = "Revision marked as a conflict"
Case 8: .Cells(4).Range.Text = "Style changed"
Case 9: .Cells(4).Range.Text = "Replaced"
Case 10: .Cells(4).Range.Text = "Paragraph property changed"
Case 11: .Cells(4).Range.Text = "Table property changed"
Case 12: .Cells(4).Range.Text = "Section property changed"
Case 13: .Cells(4).Range.Text = "Style definition changed"
Case 14: .Cells(4).Range.Text = "Content moved from"
Case 15: .Cells(4).Range.Text = "Content moved to"
Case 16: .Cells(4).Range.Text = "Table cell inserted"
Case 17: .Cells(4).Range.Text = "Table cell deleted"
Case 18: .Cells(4).Range.Text = "Table cells merged"
Case Else: .Cells(4).Range.Text = "Unknown Revision"
End Select 'Case Rev.Type
.Cells(5).Range.Text = Rev.Range.Text
End With '.Rows.last
End With 'errataList
Next 'curRev = 1 To count
End With 'Documents(docName).Revisions
ActiveDocument.Save
If Documents(docName).StoryRanges.count >= wdFootnotesStory Then
With Documents(docName).StoryRanges(wdFootnotesStory)
Set unitRange = .Duplicate
curUnit = 1
For Each Rev In .Revisions
With Rev.Range
While .Start > Documents(docName).Footnotes(curUnit).Range.End
curUnit = curUnit + 1
Wend '.Start > Documents(docName).Footnotes(curUnit).Range.End
If .Start <= Documents(docName).Footnotes(curUnit).Range.Start Then
unitRange.End = .Start + 3
Else '.Start <= Documents(docName).Footnotes(curUnit).Range.Start
unitRange.End = .Start
End If '.Start <= Documents(docName).Footnotes(curUnit).Range.Start
unitRange.Start = Documents(docName).Footnotes(curUnit).Range.Start
End With 'Rev.Range
With errataList
.Rows.Add
With .Rows.last
.Cells(1).Range.Text = unitRange.Information(wdActiveEndAdjustedPageNumber)
.Cells(2).Range.Text = curUnit
.Cells(3).Range.Text = unitRange.ComputeStatistics(wdStatisticLines)
Select Case Rev.Type
Case 0: .Cells(4).Range.Text = "No revision"
Case 1: .Cells(4).Range.Text = "Insertion"
Case 2: .Cells(4).Range.Text = "Deletion"
Case 3: .Cells(4).Range.Text = "Property changed"
Case 4: .Cells(4).Range.Text = "Paragraph number changed"
Case 5: .Cells(4).Range.Text = "Field display changed"
Case 6: .Cells(4).Range.Text = "Revision marked as reconciled conflict"
Case 7: .Cells(4).Range.Text = "Revision marked as a conflict"
Case 8: .Cells(4).Range.Text = "Style changed"
Case 9: .Cells(4).Range.Text = "Replaced"
Case 10: .Cells(4).Range.Text = "Paragraph property changed"
Case 11: .Cells(4).Range.Text = "Table property changed"
Case 12: .Cells(4).Range.Text = "Section property changed"
Case 13: .Cells(4).Range.Text = "Style definition changed"
Case 14: .Cells(4).Range.Text = "Content moved from"
Case 15: .Cells(4).Range.Text = "Content moved to"
Case 16: .Cells(4).Range.Text = "Table cell inserted"
Case 17: .Cells(4).Range.Text = "Table cell deleted"
Case 18: .Cells(4).Range.Text = "Table cells merged"
Case Else: .Cells(4).Range.Text = "Unknown Revision"
End Select 'Case Rev.Type
.Cells(5).Range.Text = Rev.Range.Text
End With '.Rows.last
End With 'errataList
Next 'Rev In .Revisions
End With 'Documents(docName).StoryRanges(wdFootnotesStory)
End If 'Documents(docName).StoryRanges.count >= wdFootnotesStory
ActiveDocument.Save
End Sub