Looping a Word macro over many list paragraphs causes memory issue
I'm hitting problem with a reasonably straightforward vba macro for Microsoft Word which is designed to get around some issues we're seeing with list indentation when we create PDFs versions from the Word doc.
The macro basically loops through each list in the document, and for each list paragraph associated with the list, it is setting the list template's bullet and text position to match what's applied at the paragraph level (code needs to be used with Word 2000 so not using list styles).
When dealing with large documents (60+ lists, ~350 list paragraphs), the macro runs through fine first time, but second time dies half way through with a "This method or property is not available because there is a memory or disk problem".
I've gone down the usual route of unsetting any object references used during the loop, so I can't see what might be holding on to the memory.
The code is quite simple and consists of a single procedure, currently stored in ThisDocument:
Option Explicit
Sub test2()
Dim i As Integer, n As Integer
Dim curList As List, curPar As Paragraph, templ As ListTemplate
Dim gapSize As Double, 开发者_C百科level As Integer
Application.ScreenUpdating = False
Application.Options.Pagination = False
For i = 1 To Lists.Count
Set curList = Lists(i)
For n = 1 To curList.ListParagraphs.Count
Set curPar = curList.ListParagraphs(n)
Set templ = curPar.Range.ListFormat.ListTemplate
level = curPar.Range.ListFormat.ListLevelNumber
gapSize = templ.ListLevels(level).TextPosition - templ.ListLevels(level).NumberPosition
templ.ListLevels(level).NumberPosition = curPar.LeftIndent - gapSize
templ.ListLevels(level).TextPosition = curPar.LeftIndent
templ.ListLevels(level).TabPosition = curPar.TabStops.After(curPar.LeftIndent - gapSize).position
Set templ = Nothing
Set curPar = Nothing
Next n
UndoClear
Set curList = Nothing
Next i
Application.ScreenUpdating = True
Application.Options.Pagination = True
End Sub
I've found a nasty, dirty solution that gets around the issue somewhat but is really a very poor fix. Basically, once we have gotten through one complete run of the macro, close and save the document and immediately reopen. This then allows the macro to be rerun immediately or at any stage because closing the document seems to eventually flush the memory properly. Obviously this can only be used if the user is happy to save as part of running the macro, but in my case it is
Your code looks OK and my sugestions will be just ideas to try doing the same another way...
Idea 1: insert a DoEvents somewhere in the innerloop, to facilitate garbage collection.
Idea 2: simplify your code by using FOR EACH constructs:
For Each curlist in Lists
For each curPar in curList.ListParagraphs
With curPar.Range.ListFormat.ListTemplate
.....
End With
Next curPar
Next curList
Besides UndoClear, you can also save the document at each loop.
It might heavily impact in your macro performance, though.
There's a similar issue here http://social.msdn.microsoft.com/Forums/en-US/vsto/thread/de7a88b4-914f-4895-a88a-659b732e8d87/
Hope this helps.
精彩评论