Write component quantity in the SOLIDWORKS assembly to custom property

Edit ArticleEdit Article
More 'Goodies'

This VBA macro calculates the total quantity of each component in the SOLIDWORKS assembly and writes it to the custom property.

This macro can be useful in conjunction with Export Flat Patterns From Part Or Assembly Components and Export To Multiple Formats macros.

Configuration

Macro can be configured by changing the constant parameters at the beginning of the macro as shown below:

Const PRP_NAME As String = "Qty" 'Name of the custom property to write quantity to
Const MERGE_CONFIGURATIONS As Boolean = False 'True to consider all configurations of the component as a single item
Const INCLUDE_BOM_EXCLUDED As Boolean = False 'True to write quantities based on the Feature Manager Tree instead of BOM

Notes

  • Macro will consider the user assigned quantity set via custom property (UNIT_OF_MEASURE)
  • Macro will consider configuration BOM options for children components (show, promote or hide)
  • Macro will write the quantity property to configuration if MERGE_CONFIGURATIONS is set to false and to the document property otherwise
  • Macro will not clear existing quantity if it is not in the current scope (for example if component is excluded from BOM)
  • Macro will fail for the unloaded components (e.g. lightweight)
  • Macro will attempt to resolve all lightweight components

Type BomPosition
    model As SldWorks.ModelDoc2
    Configuration As String
    Quantity As Double
End Type

Const PRP_NAME As String = "Qty"
Const MERGE_CONFIGURATIONS As Boolean = False
Const INCLUDE_BOM_EXCLUDED As Boolean = False

Dim swApp As SldWorks.SldWorks

Sub main()

    Set swApp = Application.SldWorks
    
try_:
    On Error GoTo catch_
    
    Dim swAssy As SldWorks.AssemblyDoc
    
    Set swAssy = swApp.ActiveDoc
    
    If swAssy Is Nothing Then
        Err.Raise vbError, "", "Assembly is not opened"
    End If
    
    swAssy.ResolveAllLightWeightComponents True

    Dim swConf As SldWorks.Configuration
    Set swConf = swAssy.ConfigurationManager.ActiveConfiguration

    Dim bom() As BomPosition
    ComposeFlatBom swConf.GetRootComponent3(True), bom
        
    If (Not bom) <> -1 Then
        WriteBomQuantities bom
    End If
    
    GoTo finally_
catch_:
    MsgBox Err.Description, vbCritical, "Count Components"
finally_:
    
End Sub

Sub ComposeFlatBom(swParentComp As SldWorks.Component2, bom() As BomPosition)
        
    Dim vComps As Variant
    vComps = swParentComp.GetChildren
    
    If Not IsEmpty(vComps) Then
    
        Dim i As Integer
        
        For i = 0 To UBound(vComps)
            
            Dim swComp As SldWorks.Component2
            Set swComp = vComps(i)
            
            If swComp.GetSuppression() <> swComponentSuppressionState_e.swComponentSuppressed And (False = swComp.ExcludeFromBOM Or INCLUDE_BOM_EXCLUDED) Then
                
                Dim swRefModel As SldWorks.ModelDoc2
                Set swRefModel = swComp.GetModelDoc2()
                
                If swRefModel Is Nothing Then
                    Err.Raise vbError, "", swComp.GetPathName() & " model is not loaded"
                End If
                
                Dim swRefConf As SldWorks.Configuration
                Set swRefConf = swRefModel.GetConfigurationByName(swComp.ReferencedConfiguration)
                
                Dim bomChildType As Integer
                bomChildType = swRefConf.ChildComponentDisplayInBOM
                
                If bomChildType <> swChildComponentInBOMOption_e.swChildComponent_Promote Then
                
                    Dim bomPos As Integer
                    bomPos = FindBomPosition(bom, swComp)
                    
                    If bomPos = -1 Then
                        
                        If (Not bom) = -1 Then
                            ReDim bom(0)
                        Else
                            ReDim Preserve bom(UBound(bom) + 1)
                        End If
                                            
                        bomPos = UBound(bom)
        
                        Dim refConfName As String
            
                        If MERGE_CONFIGURATIONS Then
                            refConfName = ""
                        Else
                            refConfName = swComp.ReferencedConfiguration
                        End If
        
                        Set bom(bomPos).model = swRefModel
                        bom(bomPos).Configuration = refConfName
                        bom(bomPos).Quantity = GetQuantity(swComp)
                                            
                    Else
                        bom(bomPos).Quantity = bom(bomPos).Quantity + GetQuantity(swComp)
                    End If
                
                End If
                
                If bomChildType <> swChildComponentInBOMOption_e.swChildComponent_Hide Then
                    ComposeFlatBom swComp, bom
                End If
                
            End If
            
        Next
    
    End If
    
End Sub

Function FindBomPosition(bom() As BomPosition, comp As SldWorks.Component2) As Integer
        
    FindBomPosition = -1
    
    Dim i As Integer
    
    If (Not bom) <> -1 Then
        
        Dim refConfName As String
        
        If MERGE_CONFIGURATIONS Then
            refConfName = ""
        Else
            refConfName = comp.ReferencedConfiguration
        End If
        
        For i = 0 To UBound(bom)
            If LCase(bom(i).model.GetPathName()) = LCase(comp.GetPathName()) And LCase(bom(i).Configuration) = LCase(refConfName) Then
                FindBomPosition = i
                Exit Function
            End If
        Next
    End If
    
End Function

Function GetQuantity(comp As SldWorks.Component2) As Double

On Error GoTo err_

    Dim refModel As SldWorks.ModelDoc2
    Set refModel = comp.GetModelDoc2
    
    Dim qtyPrpName As String
    
    qtyPrpName = GetPropertyValue(refModel, comp.ReferencedConfiguration, "UNIT_OF_MEASURE")
    
    If qtyPrpName <> "" Then
        GetQuantity = CDbl(GetPropertyValue(refModel, comp.ReferencedConfiguration, qtyPrpName))
    Else
        GetQuantity = 1
    End If
    
    Exit Function

err_:
    Debug.Print "Failed to extract quantity of " & comp.Name2 & ": " & Err.Description
    GetQuantity = 1

End Function

Function GetPropertyValue(model As SldWorks.ModelDoc2, conf As String, prpName As String) As String
    
    Dim confSpecPrpMgr As SldWorks.CustomPropertyManager
    Dim genPrpMgr As SldWorks.CustomPropertyManager
    
    Set confSpecPrpMgr = model.Extension.CustomPropertyManager(conf)
    Set genPrpMgr = model.Extension.CustomPropertyManager("")
    
    Dim prpResVal As String
    
    confSpecPrpMgr.Get3 prpName, False, "", prpResVal
    
    If prpResVal = "" Then
        genPrpMgr.Get3 prpName, False, "", prpResVal
    End If
    
    GetPropertyValue = prpResVal
    
End Function

Sub WriteBomQuantities(bom() As BomPosition)
    
    Dim i As Integer
    
    If (Not bom) <> -1 Then
        
        For i = 0 To UBound(bom)
            
            Dim refConfName As String
            
            Dim swRefModel As SldWorks.ModelDoc2
            Set swRefModel = bom(i).model
            
            If MERGE_CONFIGURATIONS Then
                refConfName = ""
            Else
                refConfName = bom(i).Configuration
                
                If swRefModel.GetBendState() <> swSMBendState_e.swSMBendStateNone Then
                
                    Dim swConf As SldWorks.Configuration
                    Set swConf = swRefModel.GetConfigurationByName(refConfName)
                    
                    Dim vChildConfs As Variant
                    vChildConfs = swConf.GetChildren()
                    
                    If Not IsEmpty(vChildConfs) Then
                        Dim j As Integer
                        
                        For j = 0 To UBound(vChildConfs)
                            
                            Dim swChildConf As SldWorks.Configuration
                            Set swChildConf = vChildConfs(j)
                            
                            If swChildConf.Type = swConfigurationType_e.swConfiguration_SheetMetal Then
                                SetQuantity swRefModel, swChildConf.Name, bom(i).Quantity
                            End If
                            
                        Next
                        
                    End If
                    
                End If
                
            End If
            
            SetQuantity swRefModel, refConfName, bom(i).Quantity
            
        Next
    End If
    
End Sub

Sub SetQuantity(model As SldWorks.ModelDoc2, confName As String, qty As Double)
    
    Dim swCustPrpsMgr As SldWorks.CustomPropertyManager
    Set swCustPrpsMgr = model.Extension.CustomPropertyManager(confName)
    
    swCustPrpsMgr.Add3 PRP_NAME, swCustomInfoType_e.swCustomInfoText, qty, swCustomPropertyAddOption_e.swCustomPropertyReplaceValue
    swCustPrpsMgr.Set2 PRP_NAME, qty
    
End Sub

Product of Xarial Product of Xarial