VBA LOGO

Traverse Assembly Tree Recursively -SOLIDWORKS API

Amen Jlili

This topic is most definitely a recurring one. I find myself having to go back to old pieces of code I wrote a while ago and copy-paste. I thought it would be a good idea to congregate all that in one useful post for future references.

Unfortunately, the code samples provided by SOLIDWORKS Corp lacks proper recursion. Below, you will find the same example that recursively drills down on an assembly tree in C#, VB.NET and VBA.

Note: While the logic respects the assembly order, it will not traverse the FeatureManager display tree as it appears in SOLIDWORKS (i.e. it ignores components organized into folders). To traverse the FeatureManager design tree exactly as it appears, use this object.

Note: Highlighted green line in the C# and VB.NET sample need to be updated by user with a proper assembly path. The VBA code sample assumes that an assembly document is open and active in SOLIDWORKS.


VBA


  Dim swApp As SldWorks.SldWorks
Dim swRootAssemblyModelDoc As ModelDoc2
 

Sub main()

    Set swApp = Application.SldWorks
    
    swApp.CommandInProgress = True
    
    Set swRootAssemblyModelDoc = swApp.ActiveDoc
    
    Dim swFeature As Feature
    
    Set swFeature = swRootAssemblyModelDoc.FirstFeature
           
    While Not swFeature Is Nothing
     TraverseFeatureForComponents swFeature
     Set swFeature = swFeature.GetNextFeature
    Wend
    
    
    swApp.CommandInProgress = False
    
End Sub

Private Sub TraverseFeatureForComponents(ByVal swFeature As Feature)
    Dim swSubFeature As Feature
                
    Dim swComponent As Component2
    
    Dim typeName As String
    
    typeName = swFeature.GetTypeName2
   
    If typeName = "Reference" Then
        Set swComponent = swFeature.GetSpecificFeature2
         
        If Not swComponent Is Nothing Then
         
         LogComponentName swComponent
           
           Set swSubFeature = swComponent.FirstFeature()
             While Not swSubFeature Is Nothing
                TraverseFeatureForComponents swSubFeature
                Set swSubFeature = swSubFeature.GetNextFeature()
             Wend
        End If
    End If
End Sub

Private Sub LogComponentName(ByVal swComponent As Component2)
    Dim parentCount As Long
    
    Dim swParentComponent As Component2
    Set swParentComponent = swComponent.GetParent()
    
    While Not swParentComponent Is Nothing
     parentCount = parentCount + 1
     Set swParentComponent = swParentComponent.GetParent()
    Wend
     
    Dim indentation As String
    indentation = Replicate(" ", parentCount)
    Debug.Print indentation & swComponent.Name2
End Sub
        
Public Function Replicate(RepeatString As String, ByVal NumOfTimes As Long)
    Dim s As String
    Dim c As Long
    Dim l As Long
    Dim i As Long

    l = Len(RepeatString)
    c = l * NumOfTimes
    s = Space$(c)

    For i = 1 To c Step l
        Mid(s, i, l) = RepeatString
    Next

    Replicate = s
 
End Function


C#


using SolidWorks.Interop.sldworks;
using SolidWorks.Interop.swconst;
using System;
using System.Linq;

namespace AssemblyTreeTraversal
{
    class Program
    {
        static void Main(string[] args)
        {
            SldWorks swApp = default(SldWorks);
            ModelDoc2 swModel = default(ModelDoc2);
            
            string assemblyFileName = @"C:\PDM2020\example\Full_Grill_Assembly.SLDASM";

            swApp = System.Activator.CreateInstance(Type.GetTypeFromProgID("SldWorks.Application")) as SldWorks;

            if (swApp == null)
                throw new Exception("Failed to open SOLIDWORKS");
            
            swApp.Visible = true;

            // increase performance 
            swApp.CommandInProgress = true;

            swModel = swApp.OpenDoc(assemblyFileName, (int)swDocumentTypes_e.swDocASSEMBLY) as ModelDoc2;

            Console.WriteLine("Document opened. Tree:");

             var swRootAssemblyModelDoc = swApp.ActiveDoc as ModelDoc2;
             Action<Component2> action = LogComponentName;
            
            var swFeature = swRootAssemblyModelDoc.FirstFeature() as Feature;
            while (swFeature != null)
            {
                TraverseFeatureForComponents(swFeature, action);
                swFeature = swFeature.GetNextFeature() as Feature;

            }

            
            swApp.CommandInProgress = false;

            Console.ReadLine();
            
            swApp.QuitDoc(swModel.GetTitle());
            swApp.ExitApp();
        }

        static void TraverseFeatureForComponents(Feature swFeature, Action<Component2> performAction)
        {
            var swSubFeature = default(Feature);
           
                var swComponent = swFeature.GetSpecificFeature2() as Component2;
                if (swComponent != null)
                {
                    performAction(swComponent);

                    swSubFeature = swComponent.FirstFeature();
                    while (swSubFeature != null)
                    {
                        TraverseFeatureForComponents(swSubFeature, performAction);
                        swSubFeature = swSubFeature.GetNextFeature() as Feature;
                    }
                }
                 
            
        }
        static void LogComponentName(Component2 swComponent)
        {
            // this code is not performant  
            int parentCount = 0;
            Component2 swParentComponent;
            swParentComponent = swComponent.GetParent();
            while (swParentComponent != null)
            {
                parentCount++;
                swParentComponent = swParentComponent.GetParent();
            }
            string indentation = string.Join(string.Empty, Enumerable.Repeat(" ", parentCount));
            Console.WriteLine($"{indentation}{swComponent.Name}");
        }


         
    }
}


VB.NET


Imports SolidWorks.Interop.sldworks
Imports SolidWorks.Interop.swconst

Namespace AssemblyTreeTraversal
    Class Program
        Private Shared Sub Main(ByVal args As String())
            Dim swApp As SldWorks = Nothing
            Dim swModel As ModelDoc2 = Nothing
            Dim assemblyFileName As String = "C:\PDM2020\example\Full_Grill_Assembly.SLDASM"

            swApp = System.Activator.CreateInstance(Type.GetTypeFromProgID("SldWorks.Application"))

            If swApp Is Nothing Then Throw New Exception("Failed to open SOLIDWORKS")
            swApp.Visible = True
            swApp.CommandInProgress = True
            swModel = swApp.OpenDoc(assemblyFileName, swDocumentTypes_e.swDocASSEMBLY)
            Console.WriteLine("Document opened. Tree:")
            Dim swRootAssemblyModelDoc As ModelDoc2 = swApp.ActiveDoc
            Dim action As Action(Of Component2) = AddressOf LogComponentName
            Dim swFeature As Feature = swRootAssemblyModelDoc.FirstFeature()

            While swFeature IsNot Nothing
                TraverseFeatureForComponents(swFeature, action)
                swFeature = swFeature.GetNextFeature()
            End While

            swApp.CommandInProgress = False
            Console.ReadLine()
            swApp.QuitDoc(swModel.GetTitle())
            swApp.ExitApp()
        End Sub

        Private Shared Sub TraverseFeatureForComponents(ByVal swFeature As Feature, ByVal performAction As Action(Of Component2))
            Dim swSubFeature = Nothing
            Dim swComponent = TryCast(swFeature.GetSpecificFeature2(), Component2)

            If swComponent IsNot Nothing Then
                performAction(swComponent)
                swSubFeature = swComponent.FirstFeature()

                While swSubFeature IsNot Nothing
                    TraverseFeatureForComponents(swSubFeature, performAction)
                    swSubFeature = swSubFeature.GetNextFeature()
                End While
            End If
        End Sub

        Private Shared Sub LogComponentName(ByVal swComponent As Component2)
            Dim parentCount As Integer = 0
            Dim swParentComponent As Component2
            swParentComponent = swComponent.GetParent()

            While swParentComponent IsNot Nothing
                parentCount += 1
                swParentComponent = swParentComponent.GetParent()
            End While

            Dim indentation As String = String.Join(String.Empty, Enumerable.Repeat(" ", parentCount))
            Console.WriteLine($"{indentation}{swComponent.Name}")
        End Sub
    End Class
End Namespace

More great articles

Protect macros with a password – Valid for Excel and SOLIDWORKS

TLDR: Protect macros modules from viewing by adding a password from the protection tab at Tools > Macro Name Properties.A…

Read Story
SOLIDWORKS VBA vs SOLIDWORKS .NET

Top reasons to upgrade your VBA macros in 2020

Converting a SOLIDWORKS VBA macro to an add-in. VBA macros continue to be the choice of the SOLIDWORKS community for…

Read Story

Crack any SOLIDWORKS password-protected VBAmacro with screenshots

Disclaimer: The information shared in this article is intended to show how easy it is to unlock the password protection…

Read Story
Arrow-up
×