Generating SolidWorks drawings manually — open part, new drawing, place views, fill title block, insert BOM, save PDF — is fine for a handful of parts. At scale it becomes a bottleneck. The SolidWorks API exposes every step of that workflow, and a well-structured macro or add-in can generate complete drawing packages for an entire assembly in minutes.

This post covers the full pipeline: creating drawing documents from a template, adding model views, populating title block annotations from custom properties, inserting BOMs, and exporting to PDF. Both VBA (for quick scripts) and C# (for production add-ins) approaches are shown.

The Pipeline

The generation workflow has six discrete steps that map directly to API calls:

  1. Create the drawing document from a template
  2. Insert model views (standard orthographic views, flat pattern view for sheet metal)
  3. Auto-size and auto-align views on the sheet
  4. Populate title block annotations from the part’s custom properties
  5. Insert BOM (if the model is an assembly)
  6. Export to PDF and optionally to DXF

Each step is independent enough that you can automate them individually. Start with whatever is consuming the most manual time.

Step 1: Creating the Drawing Document

' VBA: Create a new drawing from a template
Sub CreateDrawingFromTemplate()
    Dim swApp As SldWorks.SldWorks
    Dim swDraw As SldWorks.DrawingDoc
    Dim drawPath As String
    
    Set swApp = Application.SldWorks
    
    ' Path to your drawing template (.drwdot)
    Dim templatePath As String
    templatePath = "C:\SolidWorks\Templates\A3_Template.drwdot"
    
    ' NewDocument creates any document type from a template
    ' Arguments: templatePath, paperSize (0=A-size), width(m), height(m)
    drawPath = swApp.GetUserPreferenceStringValue(swUserPreferenceStringValue_e.swFileLocationsDocumentTemplates)
    
    Set swDraw = swApp.NewDocument(templatePath, 0, 0, 0)
    
    If swDraw Is Nothing Then
        MsgBox "Failed to create drawing — check template path"
        Exit Sub
    End If
    
    ' swDraw is now an active empty drawing with one sheet
    Debug.Print "Created drawing: " & swDraw.GetPathName()
End Sub

The NewDocument call creates the drawing and activates it. The third and fourth arguments (width, height) are ignored when you provide a template; the template’s sheet format defines the paper size.

In C# (for add-ins):

// C#: Create drawing from template
ISldWorks swApp = /* your ISldWorks instance */;

string templatePath = @"C:\SolidWorks\Templates\A3_Template.drwdot";
IModelDoc2 drawDoc = (IModelDoc2)swApp.NewDocument(templatePath, 0, 0, 0);
IDrawingDoc swDraw = (IDrawingDoc)drawDoc;

Selecting the Right Template

If you need to select a template programmatically based on part characteristics (paper size for a large assembly vs small part), use the API to query part bounding box and decide:

// Determine template based on approximate sheet metal blank size
IBody2 flatBody = GetFlatPatternBody(partDoc); // your helper
double[] bbox = (double[])flatBody.GetBodyBox();
double width  = bbox[3] - bbox[0];  // metres
double height = bbox[4] - bbox[1];

string template = (width > 0.42 || height > 0.30)
    ? @"Templates\A2_Template.drwdot"
    : @"Templates\A3_Template.drwdot";

Step 2: Inserting Model Views

' VBA: Insert a standard three-view layout from a part file
Sub InsertViews(swDraw As SldWorks.DrawingDoc, partPath As String)
    Dim swSheet As SldWorks.Sheet
    Dim swView As SldWorks.View
    
    Set swSheet = swDraw.GetCurrentSheet()
    
    ' InsertModelView3 inserts the first view
    ' Arguments: modelPath, viewName, scale_type (1=custom), scale, x, y, alignH, error
    Dim errors As Long
    Set swView = swDraw.CreateDrawViewFromModelView3( _
        partPath, _
        "*Front", _        ' standard named view
        0.5, 0.5, _        ' x, y position in metres from sheet origin
        errors)
    
    If swView Is Nothing Then
        Debug.Print "View insert failed, error: " & errors
        Exit Sub
    End If
    
    ' The first view sets the scale. Projected views use the same scale
    ' swView.ScaleDecimal = 0.5  ' 1:2
    
    ' Project right view from front
    Dim swRightView As SldWorks.View
    swDraw.ActivateView swView.Name
    Set swRightView = swDraw.CreateUnfoldedView( _
        swView.Name, _
        0.5 + 0.15, 0.5, _ ' offset 150mm to the right
        errors)
End Sub

For sheet metal flat pattern views, use the *Flat Pattern named view string:

Set swView = swDraw.CreateDrawViewFromModelView3( _
    partPath, _
    "*Flat Pattern", _
    0.1, 0.1, _
    errors)

The flat pattern view requires the part’s Flat-Pattern feature to be unsuppressed. If it is suppressed, the view will insert as an empty frame — no geometry. Check IFeature.Suppressed on the flat pattern feature before inserting.

Auto-Scale Views to Fit

Manually choosing a scale for each part is fragile. A better approach is to insert at scale 1:1, get the view bounding box, then rescale to fit within the sheet’s drawing area:

// C#: Auto-scale a view to fit within a target region
void AutoScaleView(IView view, double maxWidthM, double maxHeightM)
{
    double[] bbox = (double[])view.GetOutline();
    // bbox: [minX, minY, maxX, maxY] in sheet coordinates (metres)
    double viewW = bbox[2] - bbox[0];
    double viewH = bbox[3] - bbox[1];
    
    double scaleW = maxWidthM / viewW;
    double scaleH = maxHeightM / viewH;
    double scale  = Math.Min(scaleW, scaleH) * 0.9; // 10% margin
    
    // Round to nearest standard scale (1:1, 1:2, 1:5, 1:10, etc.)
    double[] stdScales = { 1.0, 0.5, 0.25, 0.2, 0.1, 0.05 };
    scale = stdScales.OrderBy(s => Math.Abs(s - scale)).First();
    
    view.ScaleDecimal = scale;
}

Step 3: Populating the Title Block

The title block in a SOLIDWORKS drawing template is a sheet format (.sldfrm). Editable fields in the title block are note annotations linked to custom properties via the $PRPSHEET: and $PRPMODEL: syntax. When the property exists on the referenced model, the annotation displays it automatically.

If the notes are not linked (they are static text in the template), you must update them programmatically:

' VBA: Find a note by its text content and replace it
Sub FillTitleBlockNote(swDraw As SldWorks.DrawingDoc, _
                       searchText As String, newValue As String)
    Dim swSheet As SldWorks.Sheet
    Set swSheet = swDraw.GetCurrentSheet()
    
    ' EditTemplate opens the sheet format for editing
    swDraw.EditTemplate
    
    Dim noteCount As Long
    Dim notes() As String
    noteCount = swSheet.GetAnnotationCount()
    
    Dim swAnn As SldWorks.Annotation
    Dim i As Long
    For i = 1 To noteCount
        ' GetAnnotations returns IDispatch array — iterate differently
    Next i
    
    ' Better: iterate via FeatureManager annotations
    Dim swNote As SldWorks.Note
    Dim swFeat As SldWorks.Feature
    Set swFeat = swDraw.FirstFeature()
    
    Do While Not swFeat Is Nothing
        If swFeat.GetTypeName2() = "BlockDef" Then
            ' skip block defs
        Else
            Dim swAnn2 As SldWorks.Annotation
            Set swAnn2 = swFeat.GetFirstAnnotation2()
            Do While Not swAnn2 Is Nothing
                If swAnn2.GetType() = swAnnotationType_e.swNote Then
                    Set swNote = swAnn2.GetSpecificAnnotation()
                    If InStr(swNote.GetText(), searchText) > 0 Then
                        swNote.SetText newValue
                    End If
                End If
                Set swAnn2 = swAnn2.GetNext2()
            Loop
        End If
        Set swFeat = swFeat.GetNextFeature()
    Loop
    
    swDraw.EditSheet
End Sub

The more robust approach is to use the $PRPSHEET: link in the template itself, and then just set the custom property on the drawing document:

' VBA: Set drawing-level custom property (used by $PRPSHEET: links in title block)
Sub SetDrawingProperty(swDraw As SldWorks.ModelDoc2, propName As String, propValue As String)
    Dim swCustMgr As SldWorks.CustomPropertyManager
    Set swCustMgr = swDraw.Extension.CustomPropertyManager("")  ' "" = top-level document
    
    ' Add or update
    Dim result As Long
    result = swCustMgr.Add3(propName, swCustomInfoType_e.swCustomInfoText, propValue, _
             swCustomPropertyAddOption_e.swCustomPropertyReplaceValue)
End Sub

' Usage: mirror model custom properties into the drawing
Dim swPartDoc As SldWorks.PartDoc
Set swPartDoc = swApp.OpenDoc6(partPath, swDocumentTypes_e.swDocPART, _
    swOpenDocOptions_e.swOpenDocOptions_Silent, "", 0, 0)

Dim partCustMgr As SldWorks.CustomPropertyManager
Set partCustMgr = swPartDoc.Extension.CustomPropertyManager("")

Dim propNames() As String, propValues() As String, propTypes() As Long
partCustMgr.GetAll2 propNames, propTypes, propValues

Dim j As Long
For j = 0 To UBound(propNames)
    SetDrawingProperty swDraw, propNames(j), propValues(j)
Next j

This pulls every custom property from the part (Material, PartNumber, Revision, Finish, etc.) and sets it on the drawing document. Any $PRPSHEET:PartNumber link in the title block will then display the correct value without manual entry.

Step 4: Inserting the BOM

For assemblies, the BOM is the most time-consuming manual step. The API inserts a BOM table and gives you access to every cell.

' VBA: Insert a BOM into a drawing and export it
Sub InsertAndExportBOM(swDraw As SldWorks.DrawingDoc)
    Dim swSheet As SldWorks.Sheet
    Set swSheet = swDraw.GetCurrentSheet()
    
    ' Get the first view (assembly view to attach BOM to)
    Dim views() As String
    views = swSheet.GetViewNames()
    
    Dim swView As SldWorks.View
    Set swView = swDraw.GetFirstView()
    
    Dim swTableAnnotation As SldWorks.TableAnnotation
    
    ' InsertTableAnnotation2: view, anchorType, bomType, x, y, config, filename, tableStyle
    Set swTableAnnotation = swDraw.InsertTableAnnotation2( _
        False, _                                            ' don't use auto anchor
        swBOMConfigurationAnchor_e.swBOMConfigAnchor_TopLeft, _
        swBomType_e.swBomType_Indented, _                   ' indented BOM
        0.05, 0.05, _                                       ' x, y on sheet (metres)
        swView.ReferencedDocument, _                        ' assembly doc
        "", _                                               ' use active config
        "")                                                 ' use default table template
    
    If swTableAnnotation Is Nothing Then
        Debug.Print "BOM insert failed"
        Exit Sub
    End If
    
    ' Iterate rows and columns to verify / fix data
    Dim rowCount As Long, colCount As Long
    rowCount = swTableAnnotation.RowCount
    colCount = swTableAnnotation.ColumnCount
    
    Dim r As Long, c As Long
    For r = 0 To rowCount - 1
        For c = 0 To colCount - 1
            Dim cellText As String
            cellText = swTableAnnotation.Text(r, c)
            ' cellText is the display value for this cell
        Next c
    Next r
    
    ' Export BOM to CSV
    Dim csvPath As String
    csvPath = "C:\Output\BOM_" & swView.ReferencedDocument.GetTitle() & ".csv"
    swTableAnnotation.SaveAsFile csvPath
End Sub

InsertTableAnnotation2 is the correct API for programmatic BOM insertion. Note that IDrawingDoc.InsertBom3 is deprecated in recent versions and InsertTableAnnotation2 is the replacement.

Customizing columns before inserting: Use ITableAnnotation.SetColumnTitle and ITableAnnotation.SetColumnWidth after insertion to adjust the layout. Column width is in metres.

Step 5: Exporting to PDF

' VBA: Export current drawing to PDF
Sub ExportToPDF(swDraw As SldWorks.ModelDoc2, outputPath As String)
    Dim swExportPDFData As SldWorks.ExportPdfData
    Set swExportPDFData = swApp.GetExportFileData(swExportDataFileType_e.swExportPdf)
    
    ' Export all sheets
    swExportPDFData.SetSheets swSheetsToExport_e.swExportData_ExportAllSheets, Nothing
    swExportPDFData.ViewPdfAfterSaving = False
    
    Dim errors As Long, warnings As Long
    Dim result As Boolean
    result = swDraw.Extension.SaveAs3(outputPath, 0, 0, swExportPDFData, Nothing, errors, warnings)
    
    If Not result Then
        Debug.Print "PDF export failed: error=" & errors & ", warnings=" & warnings
    End If
End Sub

SaveAs3 with an ExportPdfData object is the correct call for PDF export. The older SaveAs overloads without the data argument do not give you control over sheet selection or PDF quality settings.

Error codes from SaveAs3 worth knowing:

  • errors = 2: model contains suppressed features that affect the drawing — rebuild first
  • errors = 9: the output path does not exist or is read-only
  • errors = 12: requires a full install of SolidWorks (not a viewer) — hit when running headless via Task Scheduler without a licensed installation

Putting It Together: Batch Generation Script

The complete batch pipeline iterates a list of part files, creates a drawing for each, and exports PDF and DXF:

Sub BatchGenerateDrawings()
    Dim partFiles() As String
    partFiles = Array( _
        "C:\Parts\BracketA.SLDPRT", _
        "C:\Parts\PlateB.SLDPRT", _
        "C:\Parts\ChannelC.SLDPRT")
    
    Dim i As Long
    For i = 0 To UBound(partFiles)
        Dim partPath As String
        partPath = partFiles(i)
        
        ' Open part silently
        Dim errors As Long, warnings As Long
        Dim swPart As SldWorks.ModelDoc2
        Set swPart = swApp.OpenDoc6(partPath, _
            swDocumentTypes_e.swDocPART, _
            swOpenDocOptions_e.swOpenDocOptions_Silent, _
            "", errors, warnings)
        
        If swPart Is Nothing Then GoTo NextPart
        
        ' Create drawing
        Dim swDraw As SldWorks.DrawingDoc
        ' ... (CreateDrawingFromTemplate, InsertViews calls)
        
        ' Populate title block
        ' ... (SetDrawingProperty calls)
        
        ' Export
        Dim baseName As String
        baseName = "C:\Output\" & Left(Dir(partPath), Len(Dir(partPath)) - 7)
        ExportToPDF swDraw, baseName & ".pdf"
        
        ' Save drawing
        swDraw.Save3 swSaveAsOptions_e.swSaveAsOptions_Silent, errors, warnings
        
        ' Close part and drawing
        swApp.CloseDoc swDraw.GetPathName()
        swApp.CloseDoc partPath
        
NextPart:
    Next i
End Sub

The key discipline here is opening parts in Silent mode (swOpenDocOptions_Silent). Without it, SOLIDWORKS shows UI for missing references, update prompts, and warnings — the script blocks and requires manual intervention. Silent mode suppresses all UI, so the script runs unattended. If a part has unresolved references in silent mode, it opens with lightweight components; add a CompletelyResolve call before creating the drawing view.

Task Scheduler vs API for Unattended Runs

If you want this to run overnight or on a schedule, SOLIDWORKS Task Scheduler macros and how to pass folder paths correctly covers the setup. Task Scheduler launches SOLIDWORKS headlessly and runs a macro — the same VBA above, pointed at a folder rather than a hardcoded array.

For more complex drawing automation (Property Manager Pages, event-driven generation as parts are saved), the upgrade path to a C# add-in is covered in when to upgrade from a SolidWorks macro to a full add-in.

The Manual Steps This Does Not Replace

The API cannot reliably auto-dimension views (dimension placement is a complex spatial problem and the API does not expose a “smart” dimensioning algorithm). Title block fields that require judgment (drawing notes, tolerance block overrides, non-standard revision notes) still need manual review. The pipeline above gets you from zero to a dimensioned-free drawing with views, title block data, and BOM in the correct format — the final review pass takes seconds instead of minutes.

For teams that export DXF flat patterns alongside drawings, CadShift’s batch export handles the DXF side in parallel with the drawing generation — the same part list drives both outputs with consistent naming and layer mapping.