As more people migrate away from Word 2003 and 2007 to a newer version, more bugs are starting to come out of the woodwork. Again, this one was brought up in a forum.
When a developer writes code to use Word’s built-in Find functionality, it’s usually to do a “Replace all”, or to run a loop that stops after every “hit” until the entire search Range has been processed. It’s therefore common practice to pass
wdFindStop to the
Wrap property (or argument of the
It’s only rarely that we see code using
wdFindAsk, so perhaps it’s not surprising that the bug hadn’t been reported previously by earlier adapters of Word 2010…
In the problem scenario,
Find should only run on the current selection, then ask the user whether it should continue to execute across the entire document. This is quite legitimate and imitates the user interface. What’s happening is that Find does not stop after checking the current selection, but continues to run for the entire document (does the same as
wdFindAsk does work correctly when the end of the document is reached, asking the user if the search should continue from the beginning of the document.
Following is some VBA code that works around the problem, so that the user is queried both at the end of the selection and at the end of the document.
Sub FindWdFindAsk() Dim rngSelection As word.Range Dim rngFind As word.Range Dim txtFind As String Dim found As Boolean Dim valDocEnd As Long txtFind = "the" valDocEnd = ActiveDocument.content.End If Selection.Type wdSelectionNormal Then MsgBox "No selection available to search" Exit Sub End If 'We need to be able to always refer back to the original selection Set rngSelection = Selection.Range Set rngFind = rngSelection.Duplicate 'This will let us know where we are in the document 'We should see these numbers only once 'if we let Word traverse the entire document Debug.Print rngFind.Start, rngFind.End rngFind.Find.ClearAllFuzzyOptions rngFind.Find.ClearFormatting 'Search the selection in a loop. 'As wdFindStop is being used, found will be False 'when Execute reaches the end of the selection. Do found = ExecuteFind(rngFind, wdFindStop, txtFind) If found Then Debug.Print rngFind.Start, rngFind.End rngFind.Start = rngFind.End + 1 rngFind.End = rngSelection.End End If Loop While found 'Now ask the user if the search should continue beyond the selection. Dim userInput As VbMsgBoxResult userInput = _ MsgBox("The search has reached the end of the selection." & _ " Do you want to continue?", _ vbYesNo, "Workaround for wdFindAsk Word 2010/2013") 'If yes, we let the search continue, this time using wdFindAsk 'as it still works when the end of the document is reached. If userInput = vbYes Then Do rngFind.End = valDocEnd found = ExecuteFind(rngFind, wdFindAsk, txtFind) 'Once the end of the document is reached, 'the user will be asked if the search should continue 'from the beginning of the document. As long as 'the found Range is not within the original starting point '(selection), the search continues. Else the loop is exited. If found Then If Not rngFind.InRange(rngSelection) Then Debug.Print rngFind.Start, rngFind.End rngFind.Start = rngFind.End + 1 rngFind.End = valDocEnd Else Exit Do End If End If Loop While found End If End Sub Private Function ExecuteFind(rngFind As word.Range, _ wrap As WdFindWrap, _ findText As String) As Boolean Dim found As Boolean With rngFind.Find .Text = txtFind .wrap = wrap .MatchWholeWord = True found = .Execute End With ExecuteFind = found End Function