SolidWorks APIVBASolidWorks 2016+ · built-in VBA editorMIT license
Export a flat BOM (part counts) from a SolidWorks assembly to CSV
Purchasing wants "how many of each part is in this machine?" and the drawing BOM answers per-subassembly, not for the whole tree. This macro flattens the entire assembly: every component at every level, suppressed ones skipped, counted by file + configuration (so a short and long version of the same part number stay separate rows), written to a CSV that opens straight in Excel.
Before you run it
- An assembly open and saved (the CSV lands next to it)
- SolidWorks type-library references ticked in the VBA editor
The code
Option Explicit
' Flat parts count for the active assembly -> CSV next to the assembly file.
' Counts every component at every level; suppressed components are skipped.
' Rows are keyed by file + configuration, so config variants count separately.
Sub main()
Dim swApp As SldWorks.SldWorks
Set swApp = Application.SldWorks
Dim swModel As SldWorks.ModelDoc2
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
swApp.SendMsgToUser "Open an assembly first."
Exit Sub
End If
If swModel.GetType <> swDocASSEMBLY Then
swApp.SendMsgToUser "This macro runs on assemblies only."
Exit Sub
End If
If swModel.GetPathName = "" Then
swApp.SendMsgToUser "Save the assembly first (the CSV goes next to it)."
Exit Sub
End If
Dim swAssy As SldWorks.AssemblyDoc
Set swAssy = swModel
swAssy.ResolveAllLightWeightComponents False ' lightweight comps report nothing
Dim counts As Object
Set counts = CreateObject("Scripting.Dictionary")
Dim vComps As Variant
vComps = swAssy.GetComponents(False) ' False = all levels, flattened
Dim i As Long
For i = 0 To UBound(vComps)
Dim swComp As SldWorks.Component2
Set swComp = vComps(i)
If swComp.GetSuppression <> swComponentSuppressed Then
Dim key As String
key = swComp.GetPathName & "|" & swComp.ReferencedConfiguration
counts(key) = counts(key) + 1
End If
Next i
Dim csvPath As String
csvPath = Left$(swModel.GetPathName, _
InStrRev(swModel.GetPathName, ".") - 1) & "_BOM.csv"
Dim f As Integer
f = FreeFile
Open csvPath For Output As #f
Print #f, "File,Configuration,Quantity"
Dim k As Variant
For Each k In counts.Keys
Dim pieces() As String
pieces = Split(k, "|")
Dim baseName As String
baseName = Mid$(pieces(0), InStrRev(pieces(0), "\") + 1)
Print #f, baseName & "," & pieces(1) & "," & counts(k)
Next k
Close #f
swApp.SendMsgToUser counts.Count & " unique part/config rows written to:" & _
vbNewLine & csvPath
End SubHow it works
GetComponents(False)is the whole trick: withFalseit returns every component instance at every level as one flat array — no recursion needed.- A
Scripting.Dictionarykeyed onpath|configurationcounts instances; reading a missing key returns Empty, andEmpty + 1 = 1, so the count line works without an existence check. GetSuppression <> swComponentSuppressedskips suppressed components — they're modeled, but they're not in the machine.ResolveAllLightWeightComponentsruns first because lightweight components can report empty data to the API.- Output goes through plain
Open/Print— no Excel automation, so it runs in seconds on thousand-part assemblies.
Gotchas & honest limits
- This is a flat count, not an indented BOM — subassembly structure is deliberately erased. For indented BOMs use the drawing BOM table.
- Filenames containing commas will break the CSV columns; wrap fields in quotes if your naming allows commas (better: don't allow commas).
- Counts are model truth, not engineering truth: envelope components and "exclude from BOM" flags are not consulted in this minimal version — that's the first upgrade to make.
- Huge assemblies opened lightweight take a pause on the resolve step. That's the price of correct data.
Goes deeper
Want this adapted to your shop — or built into a real tool?
Samples are the free 80%. The last 20% is the part I do for a living.