vba 在多个列表段落上循环 Word 宏会导致内存问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5002209/
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 12:39:39  来源:igfitidea点击:

Looping a Word macro over many list paragraphs causes memory issue

listvbafor-loopms-word

提问by Steven

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.

我遇到了一个用于 Microsoft Word 的相当简单的 vba 宏的问题,该宏旨在解决我们在从 Word 文档创建 PDF 版本时遇到的列表缩进问题。

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

该宏基本上循环遍历文档中的每个列表,并且对于与列表关联的每个列表段落,它设置列表模板的项目符号和文本位置以匹配在段落级别应用的内容(代码需要与 Word 2000 一起使用,因此不是使用列表样式)。

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

处理大型文档(60+ 个列表,~350 个列表段落)时,宏第一次运行良好,但第二次运行到一半时出现“此方法或属性不可用,因为存在内存或磁盘问题” .

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:

代码非常简单,由一个过程组成,当前存储在 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, 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

回答by Steven

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

我发现了一个讨厌的、肮脏的解决方案,它在某种程度上解决了这个问题,但实际上是一个非常糟糕的解决方案。基本上,一旦我们完成了一次完整的宏运行,关闭并保存文档并立即重新打开。这将允许立即或在任何阶段重新运行宏,因为关闭文档似乎最终会正确刷新内存。显然,这只能在用户乐于将其保存为运行宏的一部分时使用,但在我的情况下

回答by Patrick Honorez

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:

您的代码看起来不错,我的建议只是尝试以另一种方式做同样的事情的想法...
想法 1:在内循环中的某处插入一个 DoEvents,以促进垃圾收集。
想法 2:通过使用 FOR EACH 构造来简化您的代码:

For Each curlist in Lists
    For each curPar in curList.ListParagraphs
       With curPar.Range.ListFormat.ListTemplate
          .....
       End With
    Next curPar
Next curList

回答by Tiago Cardoso

Besides UndoClear, you can also save the document at each loop.

除了 UndoClear,您还可以在每个循环中保存文档。

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/

这里有一个类似的问题http://social.msdn.microsoft.com/Forums/en-US/vsto/thread/de7a88b4-914f-4895-a88a-659b732e8d87/

Hope this helps.

希望这可以帮助。