How do I generate a numbered paragraph Word Cross Reference field in VB?

Anonymous
2010-10-06T22:23:01+00:00

Hi There,

Does anyone know how the 9 digit unique number used in a Microsoft Word 2003 SP3 cross reference field for a numbered paragraph is derived or calculated, and what VB function I can use to extract or create it?

I use a macro (see below) that creates and inserts a cross reference field. The aim is to quickly create a cross reference from a button rather than go through the tedious "insert>reference>cross reference and select" menus.

The macro tags the reference with a letter "b" followed by an 8 digit random number (eg toggle field codes shows "{ REF b70554752 \n \h }.

The behaviour of this method of cross referencing works well most of the time, but has a couple of annoying flaws.  

Firstly, the small risk that a cross reference may be given the same number (ie the random number generator kicscks out the same number twice in a document!). Not really concerned about this as it is very unlikely to occur.

Secondly, and by far the biggest problem, is where a cross reference is created to a numbered paragraph, and the numbered paragraph is subsequently deleted. Instead of the cross reference going to "Error! - Reference Not Found" (as a 'manually inserted' cross reference does), it updates to a different, usually nearby, numbered paragraph.

On comparing the format of a 'manually inserted' cross reference field with my macro generated field, it appears that the "Microsoft" cross reference uses a 9 digit number that is somehow created uniquely based on the paragraph (for example "{ REF _Ref274201605 \n \h }"). This means that if the paragraph referred to is deleted, the reference is no longer valid and the bookmark (correctly) errors ever time.

Does anyone know how the 9 digit unique number used in a Microsoft Word 2003 SP3 cross reference field for a numbered paragraph is derived or calculated, and what VB function I can use to extract or create it?

Many thanks in advance!

Cheers

...Steve

For reference, the current macro is as follows:

___________________

Sub Add_crossRef_to_selected_para()

Dim n As Long

Dim myBookmark As String

n = Int(Rnd() * 100000000) + 1

With ActiveDocument.Bookmarks

.Add Range:=Selection.Range, Name:="b" & n

.DefaultSorting = wdSortByLocation

.ShowHidden = True

End With

Selection.InsertCrossReference ReferenceType:="Bookmark", ReferenceKind:= _

wdNumberNoContext, ReferenceItem:="b" & n, InsertAsHyperlink:=True, _

IncludePosition:=False

End Sub

________________________

Microsoft 365 and Office | Word | For home | Windows

Locked Question. This question was migrated from the Microsoft Support Community. You can vote on whether it's helpful, but you can't add comments or replies or follow the question.

0 comments No comments

41 answers

Sort by: Newest
  1. Paul Edstein 82,871 Reputation points Volunteer Moderator
    2010-10-13T22:56:00+00:00

    Hi Steve,

    Maybe inspiriation has struck. Try:

    Sub CrossRefThisListPara()

    Application.ScreenUpdating = False

    Dim i As Integer, xRefs As Variant

    'Get the CrossReferenceItems collection

    xRefs = ActiveDocument.GetCrossReferenceItems(wdRefTypeNumberedItem)

    With Selection

      .Collapse wdCollapseEnd

      On Error Resume Next

      'Loop through the CrossReferenceItems collection to find the current paragraph

      For i = 1 To UBound(xRefs)

        If ActiveDocument.ListParagraphs(i).Range.End = .Paragraphs.First.Range.End Then

          'Insert a Cross-Reference to the selected paragraph, using the Bookmark ID allocated by Word

          .InsertCrossReference ReferenceType:=wdRefTypeNumberedItem, ReferenceKind:=wdNumberFullContext, _

            ReferenceItem:=i, InsertAsHyperlink:=True, IncludePosition:=False

          Exit For

        End If

      Next

    End With

    Application.ScreenUpdating = True

    End Sub

    Comparing the paragraph end positions, rather than the whole range seems to work. It also obviates the need to insert needless bookmarks for a mass of numbered paragraphs for which there will never be a cross-reference.


    Cheers,

    macropod MS MVP - Word

    Was this answer helpful?

    0 comments No comments
  2. Anonymous
    2010-10-13T22:29:23+00:00

    Hi macropod,

    Gotta love Microsoft!

    Despite all your great work on this issue, for which I state again how grateful I am, I think I've got to go back to the original macro and live with it's warts.

    I've learnt heaps during this interchange, and who kniows - maybe inspiration will come to you, me or another reader and a perfect solution rises:-)

    Thanks again, macropod.

    Cheers

    ...Steve

    Was this answer helpful?

    0 comments No comments
  3. Paul Edstein 82,871 Reputation points Volunteer Moderator
    2010-10-13T06:03:26+00:00

    Hi Steve,

    Sadly, for a paragraph to which a cross-reference doesn't already exist, there isn't any way of getting the current paragraph's bookmarkID other than by first inserting a cross-reference to it. I haven't yet found a way to get that other than by looping through the GetCrossReferenceItems collection and allocating a cross-reference to every paragraph in the collection. Having done that, it's a simple matter to retrieve the paragraph's bookmarkID and use that. Hence the addition of the 'If .Paragraphs.First.Range.BookmarkID = 0 Then' test to skip the loop for paragraphs with an existing bookmarkID.

    Adding/deleting paragraphs doesn't seem to affect the results for me - any new cross-references point to the correct paragraphs. Of course, that any existing cross-refs will need updating (eg via a Print Preview or Ctrl-A, F9).


    Cheers,

    macropod MS MVP - Word

    Was this answer helpful?

    0 comments No comments
  4. Anonymous
    2010-10-13T05:20:17+00:00

    hi Macropod,

    I have Show Hidden bookmarks' on.

    If I delete all the bookmarks in the test document, it generally seems to work, although it was always inserting the xref for the previous para, so I deleted the "-1" from "ReferenceItem:=ActiveDocument.Bookmarks.Item(.Paragraphs.First.Range.BookmarkID - 1).Name" and that was then OK.

    Inserting xrefs in a sequence of paras and then doing things like insert new paras in the middle, and deleting existing paras, then do an update fields and the xrefs get mixed up.

    Also, I will not be able to apply or use this macro to an existing (usually very complex and long) document with existing xrefs as I can't delete the existing bookmarks (some of the bookmarks are used by other functions in the document), and i wouldn't want to lose all the existing xrefs created through bookmarking by the original macro.

    I don't really understand the depth and complexity of the functions you are using, but isn't there just a function that says "whats the crossref ID of my current para" followed by "insert that crossref at cursor", thus avoiding the need to go through and create IDs for every para at startup?

    Cheers

    ...Steve

    Was this answer helpful?

    0 comments No comments
  5. Paul Edstein 82,871 Reputation points Volunteer Moderator
    2010-10-13T04:32:49+00:00

    Hi Steve,

    It seems this only works if 'show hidden bookmarks' is 'on'. try the following:

    Sub CrossRefThisListPara()

    Application.ScreenUpdating = False

    Dim i As Integer, xRefs As Variant, rngTmp As Range, blnStatus

    blnStatus = ActiveDocument.Bookmarks.ShowHidden

    ActiveDocument.Bookmarks.ShowHidden = True

    xRefs = ActiveDocument.GetCrossReferenceItems(wdRefTypeNumberedItem)

    With Selection

      .Collapse wdCollapseEnd

      If .Paragraphs.First.Range.BookmarkID = 0 Then

        On Error Resume Next

        For i = 1 To UBound(xRefs)

          'Ensure each list para has a Bookmark ID allocated by Word

          If ActiveDocument.ListParagraphs(i).Range.BookmarkID = 0 Then

            Set rngTmp = ActiveDocument.ListParagraphs(i).Range

            With rngTmp

              .End = .Start

              'Create the ID by inserting a Cross-Reference to the current paragraph

              .InsertCrossReference ReferenceType:=wdRefTypeNumberedItem, _

               ReferenceKind:=wdNumberFullContext, ReferenceItem:=i

              'Delete the Cross-Reference

              .MoveEnd wdCharacter, 1

              .Fields(1).Delete

            End With

          End If

        Next

      End If

      'Inserting a Cross-Reference to the selected paragraph, using the Bookmark ID allocated by Word

      .InsertCrossReference ReferenceType:=wdRefTypeBookmark, ReferenceKind:=wdNumberFullContext, _

        ReferenceItem:=ActiveDocument.Bookmarks.Item(.Paragraphs.First.Range.BookmarkID - 1).Name, _

        InsertAsHyperlink:=True, IncludePosition:=False

    End With

    Set rngTmp = Nothing

    ActiveDocument.Bookmarks.ShowHidden = blnStatus

    Application.ScreenUpdating = True

    End Sub

    One quirk I've just noticed is that the code still won't assign a bookmark name for the very last list paragraph in the document - if that's the last paragraph in the document. Haven't figured that one out yet, but it's easy enough to simply scroll through the Insert|Cross-Reference dialogue to the last entry to create that one. Thereafter the code inserts the xref for that para also.


    Cheers,

    macropod MS MVP - Word

    Was this answer helpful?

    0 comments No comments