The good news is - since Visio 2010 there has been an easy way to do this, using the ConnectedShapes()
method. The bad news is that you are limited to Visio 2007.
I will illustrate by example.
In the code below I have also included some older properties. Pre-2010, the method was to identify all the connectors and build a map by identifying the connected shapes and also identifying the presence (or absence) of arrows. Tedious but doable. Once you have set the code up, it can be re-used so the little amount of pain at the front in coding will help your reporting in the longer run.
The output is based on the following image on Page 1.

Private Sub ConnectionThings()
Dim testShape As Shape
Dim testPage As Page
Set testPage = ThisDocument.Pages(1)
Dim testArray() As Long
Dim iterator As Long
For Each testShape In testPage.Shapes
If Not testShape.OneD Then
testArray = testShape.ConnectedShapes(visConnectedShapesIncomingNodes, "")
For iterator = LBound(testArray) To UBound(testArray)
Debug.Print testShape.Text & " is connected to " & testPage.Shapes(testArray(iterator)).Text & " (incoming)."
Next iterator
testArray = testShape.ConnectedShapes(visConnectedShapesOutgoingNodes, "")
For iterator = LBound(testArray) To UBound(testArray)
Debug.Print testShape.Text & " is connected to " & testPage.Shapes(testArray(iterator)).Text & " (outgoing)."
Next iterator
End If
Next testShape
Debug.Print vbCrLf & "*** Demonstration of older properties *** "
For Each testShape In testPage.Shapes
Debug.Print testShape.Text & " is connected to " & testShape.Connects.Count & " shape(s)."
Debug.Print testShape.Text & " is glued to " & " 1D shape(s): " & IsEmpty(testShape.GluedShapes(visGluedShapesAll1D, ""))
Next testShape
Dim testConnectedShape As Shape
Dim testConnection As Connect
For Each testShape In testPage.Shapes
For Each testConnection In testShape.Connects
Debug.Print testShape.Text & " is connected from " & testConnection.FromSheet.Text & " to " & testConnection.ToSheet.Text
Next testConnection
Next testShape
End Sub
R1 is connected to R2 (outgoing).
R2 is connected to R1 (incoming).
R2 is connected to R3 (outgoing).
R3 is connected to R2 (incoming).
* Demonstration of older properties *
R1 is connected to 0 shape(s).
R1 is glued to 1D shape(s): False
R2 is connected to 0 shape(s).
R2 is glued to 1D shape(s): False
R3 is connected to 0 shape(s).
R3 is glued to 1D shape(s): False
C1 is connected to 2 shape(s).
C1 is glued to 1D shape(s): False
C2 is connected to 2 shape(s).
C2 is glued to 1D shape(s): False
C1 is connected from C1 to R1
C1 is connected from C1 to R2
C2 is connected from C2 to R2
C2 is connected from C2 to R3
** Perhaps you could convince your company to allow Visio 2010 or later? After all, 2007 is over a decade old and out of support. Even 2010 is going out of support. My code was developed in Visio 2019 or 365 (not sure which, couldn't find the version number).
Addendum: Here is some older code that I used to follow the arrows. This was part of a larger body of code to create a full report, and I offer this here as an example of how to find the arrow head type. BPMNShape
is a custom class as I was following a complex diagram - .BaseShape
was the actual Visio shape in use. In your instance, you could simplify that to a simple 2-D shape or whatever master the key nodes are using. 'IsIntermediateand
IsStart` merely confirm if the shapes are based on a particular master.
Private Function FindNextNonFlow2(ThePage As Page, TheShape As BPMNShape) As BPMNShape
' TheShape must be an intermediate or start
Dim t_Connect As Connect
Dim t_shape As New BPMNShape
Dim t_shape2 As New BPMNShape
Dim t_shape3 As New BPMNShape
Set t_shape.BaseShape = TheShape.BaseShape
If t_shape.IsSequence Then
If t_shape.ArrowCodeEnd = 13 Then
Set t_shape.BaseShape = ThePage.Shapes(t_shape.TriggerShapeEnd)
Else
Set t_shape.BaseShape = ThePage.Shapes(t_shape.TriggerShapeBegin)
End If
End If
If t_shape.IsIntermediate Or t_shape.IsStart Then
' Code here
' use FromConnects
' End arrow = 13
For Each t_Connect In t_shape.FromConnects
Set t_shape2.BaseShape = t_Connect.FromSheet
If t_shape2.IsSequence Then
If t_shape2.ArrowCodeEnd = 13 And Not (ThePage.Shapes(t_shape2.TriggerShapeEnd) = t_shape.BaseShape) Then
Set t_shape3.BaseShape = ThePage.Shapes(t_shape2.TriggerShapeEnd)
ElseIf t_shape2.ArrowCodeBegin = 13 And Not (ThePage.Shapes(t_shape2.TriggerShapeBegin) = t_shape.BaseShape) Then
Set t_shape3.BaseShape = ThePage.Shapes(t_shape2.TriggerShapeBegin)
End If
End If
Next t_Connect
If t_shape3.IsNotNothing Then Set t_shape = t_shape3
End If
Set FindNextNonFlow2 = t_shape
End Function
I had a "TO-DO" on the functions below (used in the above code): Add error checking and sensible fails.
Property Get ArrowCodeBegin() As Double
ArrowCodeBegin = p_TheShape.CellsSRC(visSectionObject, visRowLine, visLineBeginArrow).Result(visNoCast)
End Property
Property Get ArrowCodeEnd() As Double
ArrowCodeEnd = p_TheShape.CellsSRC(visSectionObject, visRowLine, visLineEndArrow).Result(visNoCast)
End Property
Property Get TriggerShapeEnd() As String
TriggerShapeEnd = FindShapeName( _
p_TheShape.CellsSRC(visSectionObject, visRowMisc, visEndTrigger).Formula)
'If p_TheShape Is Nothing Then Debug.Print "Issue: trid an operation on a null shape"
End Property
Property Get TriggerShapeBegin() As String
TriggerShapeBegin = FindShapeName( _
p_TheShape.CellsSRC(visSectionObject, visRowMisc, visBegTrigger).Formula)
End Property
Private Function FindShapeName(TheTriggerString As String) As String
Dim t_string As String
t_string = TheTriggerString
If Len(t_string) > 0 Then
t_string = Left(t_string, InStr(1, t_string, "!") - 1)
t_string = Right(t_string, Len(t_string) - InStr(1, t_string, "("))
End If
t_string = Replace(t_string, "'", "")
FindShapeName = Trim(t_string)
End Function