Search code examples
vbams-wordstylesparagraph

VBA WORD: find a paragraph that has a specific style


I am trying to write a code in VBA, where I will get the number of a paragraph that will have a specific style (let's say Heading 1). I am going through a loop and unfortunately I am getting such an error:

"Object variable or With block variable not set"

Here is my code:

Public Function FindParagraph(ByVal pStyle As String) As Integer
    Dim doc As Document
    Dim pNum As Integer
    Set doc = ActiveDocument

    For pNum = 1 To doc.Paragraphs.Count
        Debug.Print pNum, doc.Paragraphs(pNum).Range.Style
        If doc.Paragraphs(pNum).Range.Style = pStyle Then
            FindParagraph = pNum
            Exit For
        End If
    Next pNum
End Function

Sub DoSth()
    Dim i As Integer
    i = FindParagraph("Heading 1")
    Debug.Print i
End Sub

Debugger shows that the problem is in this line: pStyle = doc.Paragraphs(i).Range.Style And actually I am looking at my Word document and it is the first line of the Table of Contents. Do You know why is it like this?


Solution

  • The code you have provided does not compile. It gives an error at

    While Not (IsEmpty(pStyle))
    

    because the Method IsEmpty should only be used on a Variant type and the type you have assigned to pStyle is a String. To achieve your intent you will need to change this line to

    While Not pStyle = vbNullString
    

    Updated to provide revised function

    Sub TestFindParagraph()
    
        Dim IsFound As Boolean
        IsFound = FindParagraph(ActiveDocument.StoryRanges(wdMainTextStory), "Heading 1")
    
    End Sub
    
    
    Public Function FindParagraph(ByVal SearchRange As Word.Range, ByVal ParaStyle As String) As Long
    
        Dim ParaIndex As Long
        For ParaIndex = 1 To SearchRange.Paragraphs.Count
    
            If doc.Paragraphs(ParaIndex).Range.Style = ParaStyle Then
    
                FindParagraph = ParaIndex
                Exit Function
    
            End If
    
        Next
    
    End Function
    

    Update 2020-Apr-15 Resolving the TOC issue

    The code posted by the OP and by myself both fail when the paragraph is a Table of Contents field. This failure occurs because of the default member feature of VBA Objects.

    The default member of an object is a method that is called if the object instance is given without a qualifying Method. This feature can be helpful as it simplifies code, but, can lead to strange errors similar to that which we are experiencing.

    In Word, Styles are objects with numerous properties and methods. The default Method of Style is NameLocal (See the object browser for Word.Style) which returns a Variant containing a string (See the type for style in the locals windows). Consequently, even though pStyle is defined as a String type, VBA coercion allows the variant/string to be assigned to the String pStyle and everything appears to be OK.

    However, in the case of a TOC field it appears that Word does not return the style wrapping the TOC field, instead it returns the value of 'nothing' i.e. there is no style for a TOC. Nothing (not the same as vbNullString) cannot be assigned to a string and consequently an error occurs.

    There would appear to be two solutions to the problem encountered above.

    1. Change the code to use correct syntax for the information we require. i.e. Style.NameLocal. Unfortunately, this solution will also fail because we cannot call a method (NameLocal) on an object that is nothing.

    2. Change the type of variable for pStyle from String to Variant. Variant types can hold objects and consequently can hold the value of nothing which is generated when a paragraph is a TOC field.

    Solution 2 would appear to work fine however from a purist perspective you would have an intermediate variant variable that captures the result from Style and then tests the variant for nothing before assigning the string value or vbNullString to pStyle.

    Final Update 2020-Apr-15

    I was unfortunatly called away by Mrs F for some urgent jobs so forgot to add this final peice.

    The Default member trap can be avoided easily. This is due to the amazing work done by the folks over at Rubberduck.

    http://rubberduckvba.com/

    The Rubberduck addin for VBA (which is free) has, as one of its many talents, a much more rigorous code analysis (Code Inspections) of VBA. One of the inspections is to warn wherever a default member has been used in code. Rubberduck really does remove a significant amount of pain when writing VBA code as it helps you understand just exactly the assumptions you have made in your code (that you didn't realise you'd made)...