A LinkedIn post earlier this year showed a VBA macro compressing a 40-minute manual batch DXF export down to seconds. It drew significant engagement because every SolidWorks engineer who works with sheet metal has written some version of this macro, or knows someone who has.

The basic implementation is not complicated. Iterate assembly components, open each part, call ExportToDWG2, close. For clean assemblies with simple sheet metal parts and consistent filenames, it runs reliably. The problems surface when the assembly contains parts that don’t fit the happy path — and most production assemblies do.

What the Basic Macro Does

The core API call for sheet metal flat pattern export:

Dim swPart As SldWorks.PartDoc
Dim nRetVal As Long

' Action type: export as sheet metal flat pattern
Dim lExportOptions As Long
lExportOptions = swExportToDWG_e.swExportToDWG_ExportSheetMetal  ' = 2

' Bitmask controlling which geometry is included in the DXF
Dim lSheetMetalOptions As Long
lSheetMetalOptions = 1 + 4 + 8  ' Geometry=1, BendLines=4, Sketches=8

nRetVal = swPart.ExportToDWG2( _
    sOutputPath, _
    swModel.GetPathName(), _
    lExportOptions, _
    True, _      ' Export all sheets
    Nothing, _   ' Sheet names (Nothing = all)
    0, _         ' Width
    0, _         ' Height
    0, _         ' Scale mode
    lSheetMetalOptions)

The full swExportFlatPatternSheetMetalOptions_e bitmask values: Geometry=1, HiddenEdges=2, BendLines=4, Sketches=8, MergeCoplanarFaces=16, LibraryFeatures=32, FormingTools=64, BoundingBox=2048. Most macros use 13 (Geometry + BendLines + Sketches).

Return value 1 means success. Everything else is a failure. Most macros don’t check it. That’s where the silent failures start.

Edge Case 1: Multi-Configuration Sheet Metal Parts

An assembly typically includes parts with multiple configurations — a bracket in three lengths, a plate in two hole patterns. Each configuration has a different flat pattern. Your macro needs a DXF per configuration, not just the active one.

The naive iteration:

Dim vConfigs As Variant
vConfigs = swModel.GetConfigurationNames()

Dim i As Integer
For i = 0 To UBound(vConfigs)
    swModel.ShowConfiguration2 CStr(vConfigs(i))
    swModel.EditRebuild3
    ' ExportToDWG2 call...
Next i

This breaks in two ways.

Problem 1: Not every configuration has sheet metal features. A part with a “Default” solid-body config and a derived “Flat_Pattern” config will attempt to export a flat pattern from Default. ExportToDWG2 returns -1 (failure), which gets ignored. The macro moves on as if the export succeeded.

Problem 2: ShowConfiguration2 + EditRebuild3 doesn’t guarantee the model is fully regenerated before export. On heavy parts, the flat pattern kernel may still be computing when ExportToDWG2 fires. The resulting DXF contains geometry from the previous configuration.

Fix: after switching configurations, check swModel.NeedsRebuild2. If true, call swModel.ForceRebuild3(False) and wait for it to complete. Then check swPart.IsSheetMetal() — it returns True only when the active configuration has sheet metal features. Skip configs where it returns False.

Edge Case 2: Non-Sheet-Metal Thin Parts

Assemblies cut on laser or waterjet often include parts that aren’t modelled as sheet metal — a flat solid body, a plate made with Boss-Extrude, a face with cut features and no bend. These have no flat pattern. IsSheetMetal() returns False.

Calling ExportToDWG2 with swExportToDWG_ExportSheetMetal on a non-sheet-metal part produces one of three outcomes depending on SolidWorks version and model state:

  • Returns a failure code
  • Creates an empty DXF
  • Exports the last-saved drawing view instead of the face geometry

All three outcomes are wrong. The failure is silent. The DXF file exists, it just doesn’t contain what the laser operator needs.

Handling this properly requires a branch:

If swPart.IsSheetMetal() Then
    Call ExportSheetMetalFlat(swPart, sOutputPath)
Else
    ' Export top face projection — requires a drawing document
    Call ExportFaceFromDrawing(swModel, sOutputPath)
End If

The drawing-based path for non-sheet-metal flat parts adds complexity: you need a template, you need to know which face to project from, and you need to manage the drawing document lifecycle inside the macro. Most teams skip this and just flag non-sheet-metal parts for manual export — which defeats the purpose of a batch tool.

Edge Case 3: Layer Mapping for Laser Etching

ExportToDWG2 with the standard bitmask puts all geometry on a single layer unless you’ve configured the colour-to-layer mapping in SolidWorks options first. Laser cutters need geometry on separate layers:

  • Cut layer: outer profile, holes, slots — what the laser cuts through
  • Bend line layer: bend annotations for press brake programming — not cut
  • Etch layer: engraving paths, part numbers, text

The swExportFlatPatternOption_BendLines flag (bitmask value 4) includes bend lines in the output, but they land on the same layer as cut geometry unless you configure Tools > Options > Document Properties > Sheet Metal > Layer. This is a document-level setting in the part template, not an API parameter.

Your macro cannot set this reliably per part without modifying active document properties before each export — which is invasive and can corrupt document settings if the export is interrupted. The workarounds:

  1. Build the colour-to-layer map into every part template used by the team. Consistent at creation, but requires template governance.
  2. Post-process DXF files after export to remap layers programmatically (using DXFLib, ezdxf, or a custom parser on the DXF ASCII format).
  3. Use an add-in that drives layer assignment directly through the export API, independent of document-level settings.

Option 2 is the most common for teams that have already built a macro library — add a post-processing step that reads the DXF entity colours and assigns layers accordingly.

Edge Case 4: File Naming from Custom Properties

The standard macro pattern for output file naming:

sOutputPath = Left(swModel.GetPathName(), Len(swModel.GetPathName()) - 7) & ".dxf"

This breaks when internal part numbers don’t match filenames. A file named TopPlate_v2_FINAL.sldprt with a Part Number property of MFG-1042-A needs to produce MFG-1042-A.dxf, not TopPlate_v2_FINAL.dxf. The laser shop programs by part number. The filename is irrelevant to them.

Reading custom properties via API:

Dim swCustPropMgr As SldWorks.CustomPropertyManager
Set swCustPropMgr = swModel.Extension.CustomPropertyManager("")

Dim sValOut As String
Dim sValResolved As String
Dim bWasResolved As Boolean

swCustPropMgr.Get6 "Part Number", False, sValOut, sValResolved, bWasResolved

Use sValResolved, not sValOut. Resolved values expand linked properties like $PRP:"Description" that may be set as indirect references. The raw value (sValOut) returns the formula, not the result.

If sValResolved is empty, define a fallback: use the filename, or log the part as requiring manual naming. Silently falling back to filename with no logging means you’ll find the mismatch when someone at the laser cutter can’t locate the file in the job queue.

For configuration-level properties (where Part Number differs per configuration), use:

Set swCustPropMgr = swModel.Extension.CustomPropertyManager(swModel.IGetActiveConfiguration.Name)
swCustPropMgr.Get6 "Part Number", False, sValOut, sValResolved, bWasResolved

The empty string in CustomPropertyManager("") accesses part-level properties. Passing the configuration name accesses configuration-level properties, which is where variant part numbers should live.

Edge Case 5: Multi-Body Sheet Metal Parts

A part with multiple sheet metal bodies — common in weldment assemblies where several flat parts live in one .sldprt — requires one DXF per body, not one DXF per part.

Without explicit body selection, ExportToDWG2 on a multi-body part merges all bodies’ flat patterns into one DXF. The geometry from separate bodies with different materials and thicknesses lands in the same file. This is wrong for laser cutting — each body needs its own cut program.

The body iteration approach:

Dim vBodies As Variant
vBodies = swPart.GetBodies2(swBodyType_e.swSolidBody, True)

Dim j As Integer
For j = 0 To UBound(vBodies)
    Dim swBody As SldWorks.Body2
    Set swBody = vBodies(j)
    
    ' Select only this body
    swBody.Select2 False, Nothing
    
    ' Build output path using body name or cut list property
    Dim sCutListName As String
    sCutListName = GetBodyCutListName(swBody)  ' Custom function to read cut list props
    
    ' ExportToDWG2 now exports only the selected body's flat pattern
    nRetVal = swPart.ExportToDWG2(sBodyOutputPath, ...)
Next j

The behaviour of ExportToDWG2 without body selection on multi-body parts is not documented and differs across SolidWorks versions. Do not rely on it. Always explicitly select the body before export.

Body names from cut lists can be retrieved via IFeature iteration looking for CutListFolder feature types, then reading properties via IWldFolderFeat. This is more involved than it sounds — the cut list feature hierarchy is nested and the property bag is attached to a specific feature node, not the body directly.

Edge Case 6: Lightweight Components in Assemblies

When iterating assembly components with GetComponents2, parts in lightweight mode return a valid IModelDoc2 reference, but the geometry isn’t loaded. Calling ExportToDWG2 on a lightweight part produces an empty DXF or crashes.

Detection:

Dim swComp As SldWorks.Component2
If swComp.GetSuppressState2() = swComponentSuppressionState_e.swComponentLightweight Then
    ' Need to resolve before export
    swComp.SetSuppressState2 swComponentSuppressionState_e.swComponentFullyResolved, True, False
End If

Resolving a lightweight component triggers geometry loading for that component. On a large assembly where many components are lightweight for performance, resolving them all for export forces SolidWorks to load substantial geometry. Memory use climbs. On machines below 32 GB RAM with assemblies over ~500 components, this is where the macro hangs or crashes.

The practical mitigation: batch lightweight resolution in groups of 20–30 components, export the group, then let SolidWorks unload them before moving to the next group. This requires managing the IModelDoc2.CloseDoc and re-open cycle inside the loop, which most macros don’t implement.

The Pattern That Catches All of Them

The single most impactful fix you can make to any existing DXF export macro is to check return values and log:

nRetVal = swPart.ExportToDWG2(sOutputPath, ...)
If nRetVal <> 1 Then
    Dim sMsg As String
    sMsg = "FAIL | " & swModel.GetTitle() & _
           " | Config: " & swModel.IGetActiveConfiguration.Name & _
           " | Code: " & CStr(nRetVal) & _
           " | Path: " & sOutputPath
    Debug.Print sMsg
    ' Append to a log file
    Call AppendLog(sLogPath, sMsg)
End If

Without this, a batch run that silently fails on 8 of 40 parts looks like success until the fabricator reports missing files. With it, you have a failure list to investigate the morning after the run.

For a deeper look at the lSheetMetalOptions bitmask and which flags affect which geometry in the output, see SolidWorks DXF entity export settings. For how the three main approaches — VBA macro, PDMPublisher, and CadShift — compare at scale, see SolidWorks batch DXF export tools compared.

Where the Macro Ends and the Add-In Begins

VBA macros are the right tool for homogeneous assemblies: all proper sheet metal parts, single configurations, filenames that work as part numbers, no layer mapping requirements. They’re fast to write and easy to hand off.

The edge cases above are where macros accumulate technical debt. Multi-config iteration with rebuild checks, IsSheetMetal branching, body iteration for multibody parts, configuration-level property lookup with fallback logic, lightweight resolution management. Handled correctly, you have a 400-line macro that one person on the team understands. Handled incorrectly, you have a macro that mostly works and silently fails on the parts it doesn’t.

CadShift’s batch DXF export addresses multi-config export, thin-part detection, layer mapping via the settings panel, and file naming from any custom property token as first-class features — not as edge cases grafted onto a simple loop. The ChatGPT-generated SolidWorks macros post covers a related failure mode: AI-generated macros that look syntactically correct but hit exactly these edge cases at runtime.

The decision is straightforward. If the macro handles your current assembly, use it. When it stops being reliable, the time spent debugging and extending it will exceed what it would cost to move to tooling built for these cases.