Writing macros

Macro authoring spec

The complete contract for a macro that runs under SwMacroFlow, stated in one place.

Writing a macro with an AI assistant? Copy this whole section, paste it in, and add what you want the macro to do. Everything the assistant needs is here - it does not need the rest of this help page, and it does not need to know anything else about SwMacroFlow.


What the host does

SwMacroFlow is a SOLIDWORKS automation tool that runs a VBA macro (.swp) over many documents unattended. For each file in scope it opens the document, makes it active, calls the macro's entry-point Sub, then closes the document. There is also a run once mode in which the chain runs a single time with no document open.

The macro is not modified. The host runs a throwaway copy in which user-supplied input values have been substituted and MsgBox and InputBox have been redefined so they report instead of opening a dialog. The copy lives under %TEMP%\SwMacroFlow\ and is deleted when the batch ends.

Several macros may be chained. For each file the host opens once, runs every ticked macro in list order against that open document, then closes it. Unsaved changes are discarded on close.

Template

A macro that satisfies every rule below. Start here.

Option Explicit

' --- Inputs: one Const per field, always As String, token is the whole literal. ---
Const ExportFolder As String = "@ExportFolder"  'Type: FolderPath 'Tooltip: "Where to write the files" 'Value: "C:\Exports"
Const Overwrite    As String = "@Overwrite"     'Type: Bool       'Tooltip: "Replace existing files"    'Value: True
Const MaxRetries   As String = "@MaxRetries"    'Type: Integer    'Tooltip: "Attempts per file"         'Value: 1
Const FileName     As String = "@FileName"      'Type: String     'Tooltip: "Output file name"          'Value: "{PartNumber}.pdf"

Sub main()

    Dim swApp As SldWorks.SldWorks
    Dim model As SldWorks.ModelDoc2
    Dim target As String
    Dim retries As Long
    Dim errors As Long
    Dim warnings As Long

    Set swApp = Application.SldWorks
    Set model = swApp.ActiveDoc

    ' No document: either the file failed to open, or this is the run-once mode.
    If model Is Nothing Then Exit Sub

    ' Inputs arrive as text. Convert, and guard against blank.
    retries = 1
    If Len(MaxRetries) > 0 Then retries = CInt(MaxRetries)

    ' Restrict to the document type this macro makes sense for.
    If model.GetType <> swDocDRAWING Then
        MsgBox "Not a drawing, skipped"
        Exit Sub
    End If

    If Len(Dir(ExportFolder, vbDirectory)) = 0 Then MkDir ExportFolder

    ' FileName may already contain resolved {Property} tokens from the host.
    target = ExportFolder & "\" & FileName

    ' A Bool input is the text "True" or "False".
    If Len(Dir(target)) > 0 And Overwrite <> "True" Then
        MsgBox "Already exists, left alone: " & target
        Exit Sub
    End If

    If model.Extension.SaveAs(target, 0, 0, Nothing, errors, warnings) Then
        MsgBox "Wrote " & target
    Else
        MsgBox "SaveAs failed (error " & errors & ") for " & target, vbCritical
    End If

End Sub

The entry point

The host calls a Sub that takes no arguments. A Sub named main is preferred, in any standard module, case-insensitively. If there is none, the first argument-less Sub the VBA project reports is used, and that order is not under your control.

Always define Sub main(). A macro with no argument-less Sub is rejected at load with "This macro has no runnable procedure - it needs a Sub that takes no arguments."

The document

The active document is the file the host just opened. Reach it with Application.SldWorks.ActiveDoc. It is never passed as an argument.

ActiveDoc is Nothing when the document failed to open, and always in the run-once mode. Guard for it and Exit Sub.

The host closes the document after the chain finishes with it, and closing discards unsaved changes. A macro that modifies a document must save it.

The same Sub is called again for the next file in the same VBA session, so module-level state persists between files. Reset it at the top of main or do not use it.

In batch mode, do not open or close documents yourself - the host does that. In run-once mode there is no document; do your own work (folder walk, report, application options) without relying on ActiveDoc.

Inputs

Grammar

Const <Name> As String = "@<Token>"   '<Key>: <value>   '<Key>: <value>
  • Const begins the line, optionally indented. Declarations are recognised in any standard module.
  • As String is required on every input, whatever the declared Type:.
  • <Token> is letters, digits and underscores. The "@<Token>" literal must be the entire string - nothing else inside the quotes.
  • The metadata is an ordinary VBA comment tail. Each '<Key>: segment runs until the next ' that introduces a recognised key, so an apostrophe inside a tooltip is safe.
  • Quotes around a metadata value are optional.
  • One line per declaration is preferred, aligned as in the template above - but a declaration may be continued with a trailing _, and so may its metadata tail. Give every key its own ', including on a continued line, or the key is read as part of the previous one:
  Const WidthPx As String = "@WidthPx" _
      'Type: Integer 'Tooltip: "Thumbnail width in pixels" _
      'Value: 256

A declaration preceded by a comment line ending in _ is swallowed by that comment, exactly as VBA sees it, and creates no input.

The host replaces every occurrence of @<Token> in the source with the user's value before running (except when that value carries {Property} placeholders - see below). The user sees a field labelled <Token> (the @ is dropped). The Const identifier <Name> is what your VBA code reads; the field label comes from the token.

Metadata keys

All optional, all case-insensitive. Unknown keys are ignored.

KeyApplies toMeaning
Type:allWhich control to build. String if omitted.
Tooltip:allHover text.
Value:allThe default the form starts with. Never a filter or a constraint.
Filter:FilePathExtensions the picker narrows to, comma-separated, e.g. ".sldprt, .sldasm".
Options:OptionThe dropdown's choices, comma-separated.

Types

Type:SynonymsControlValue your code receives
Stringanything unrecognisedText boxthe text typed
IntegerIntWhole-number text boxthe digits as text - use CInt()
BoolBooleanCheckboxthe text "True" or "False"
FilePathText box plus file pickerthe full path
FolderPathText box plus folder pickerthe full path
OptionDropdownDropdownthe chosen item's text, never an index

An Option whose Value: is not one of its own Options: raises a warning and the first option is selected.

Input rules

  • Every input value is a string, whatever its Type:. That is why As String is mandatory: Const Q As Integer = "@Quantity" is a VBA type mismatch and fails the load check.
  • Blank is always allowed and substitutes an empty string. Guard before converting.
  • Only a Const declaration creates a field. A token used elsewhere is still substituted but adds no control; an undeclared token raises a warning.
  • A token inside a ' or Rem comment is ignored.
  • The same token declared twice is one field that fills in both declarations.
  • "bob@example.com" and "C:\out\@name.txt" are left alone - the token must be the whole literal.
  • Inputs are per macro row. Two macros that both declare @Name each get their own value.

Validation before Run

Blank is always legal. Run is blocked (and the reason names the macro) when:

ConditionMessage shape
Non-blank Integer that will not parseEnter a valid whole number for every number input in …
Malformed {Property} braces in a String, FilePath, or FolderPath valueFix every property placeholder in …
Non-blank FilePath that does not exist (and has no {Property} tokens)Choose a file that exists for every file input in …

FolderPath is not existence-checked - macros commonly create the folder themselves. A FilePath whose value contains well-formed {Property} tokens also skips the existence check, because the path is not meant to exist until each document resolves it.

Running a macro by hand (optional)

The host never edits your macro - it substitutes into a throwaway copy. So a Const still holds the literal text "@ExportFolder" when you press F5 in the VBA editor, and the macro builds paths out of the placeholder text.

Only worth doing for a macro that has to work both ways. Declare the inputs twice, with the same identifiers, and ship the manual block commented:

' ===== SwMacroFlow Inputs - filled in by the app. Leave these uncommented. =====
Const ExportFolder As String = "@ExportFolder" 'Type: FolderPath 'Tooltip: "Where exports go"
Const ExportType   As String = "@ExportType"   'Type: Option     'Options: PDF, DWG 'Value: "PDF"

' ===== Manual Run - uncomment this block AND comment the block above. =====
'Const ExportFolder As String = "C:\Exports"
'Const ExportType   As String = "PDF"

Identical names are the safety net: leave both blocks live and VBA refuses to compile a duplicate Const, so the mistake surfaces when the macro is loaded instead of running a whole batch with the wrong values.

Guard the other direction - neither block live - on an input that is never legitimately blank, which means an Option or a Bool:

If Left$(ExportType, 1) = "@" Then
    MsgBox "No inputs were supplied. Uncomment the 'Manual Run' block, or run it " & _
           "from SwMacroFlow.", vbCritical
    Exit Sub
End If

Manual values have to match what the host substitutes: a Bool is the text "True" or "False", an Option is spelled exactly as in its Options: list, and {Property} / {FileName} do not work - they are expanded by VBA the host injects, so a manual run has no resolver. Use a literal, or leave it blank and derive it from the document.

Property placeholders in input values

A String, FilePath, or FolderPath value the user types may mix literal text with {PropertyName} tokens - for example {PartNumber}_{Revision}.pdf. Braces are reserved for that syntax in those three types; there is no way to escape a literal brace. Tokens are highlighted magenta in the Inputs panel as you type.

{FileName} is reserved: it always resolves to the open document's filename with its extension stripped (Part1.SLDPRT -> Part1), never a custom property - even one literally named FileName. Matched case-insensitively, so {filename} is the same token. Every other {Name} looks up a custom property as described below. (This placeholder was called {Title} in earlier versions; {Title} is now an ordinary custom-property lookup.)

Unlike an "@Name" token (baked into the temp copy before the batch starts), each {Property} is resolved per document while the macro runs, against the open document only:

  1. Active configuration's properties first
  2. Then file-level custom properties

Lookup is case-insensitive and uses the resolved value, so expressions like SW-Mass become the evaluated number rather than the expression text.

OutcomeResult
Property foundToken replaced with the resolved value
Property missing from both storesThat file fails with a named error; the batch continues. Does not expand to empty.
No document open (run-once, or open failed)That run fails - cannot resolve against a document
Malformed braces (a{b, { }, nested)Run is blocked before the batch starts

Integer, Bool, and Option inputs stay literal - they never resolve property tokens.

Your macro code does not expand {Property} itself. When the user enters {PartNumber}.pdf into a String input, the host resolves it before (or as) your Const receives the value for that file. Treat the Const as ordinary text that already holds the final string.

Do not use {Property} inputs in a macro that only runs in run-once mode with no document - there is nothing to resolve against.

Reporting

MsgBox is redefined in the copy the host runs. Each call writes one line to that file's result instead of opening a dialog. The row shows the most severe line; the log keeps them all.

CallRowReturns
MsgBox "text"Green - statusvbOK
MsgBox "text", vbCriticalRed - the file failedvbOK
MsgBox "text", vbExclamationAmber - finished, but not entirelyvbOK
MsgBox "text", vbInformation / vbQuestionGreen - statusvbOK
MsgBox "text", vbYesNoAmber - prompt auto-answeredvbNo
MsgBox "text", vbOKCancelAmbervbCancel
MsgBox "text", vbYesNoCancelAmbervbCancel
MsgBox "text", vbRetryCancelAmbervbCancel
MsgBox "text", vbAbortRetryIgnoreAmbervbAbort
InputBox("text", , "42")Amber"42" - the Default argument
An unhandled VBA runtime errorRed, as Error <n>: <description>-
Missing {Property} / no document to resolveRed, named error from the host-
No call at allGreen-

Severity order is red, then amber, then green. Within one severity the first message wins, and the row's status and text always come from the same call.

Write messages that identify the file or the value that varies - a row is read alongside hundreds of others.

Amber has two meanings and they are worth telling apart. vbExclamation is you saying the run finished but not entirely - use it whenever the honest answer is "3 of 5 sheets", because without it that file reads as a clean success. A button set other than the default is the batch saying it guessed an answer nobody was there to give; if the macro needs a yes/no or a path, make it an input rather than a MsgBox / InputBox prompt.

Must

  • Define Sub main() with no arguments.
  • Set Option Explicit and declare every variable.
  • Guard If model Is Nothing Then Exit Sub before touching the document.
  • Declare every input as Const <Name> As String = "@<Token>".
  • Convert Integer inputs with CInt(), and compare Bool inputs against the text "True".
  • Check the document type with model.GetType if the macro only suits one kind.
  • Save any document you change.
  • Report failure with MsgBox "...", vbCritical and return from the Sub.
  • Report a partial success with MsgBox "...", vbExclamation rather than letting it pass as green.

Must not

  • Do not call VBA.MsgBox. The VBA. prefix binds to the type library and cannot be intercepted - it opens a real modal dialog and the batch hangs until someone clicks it. Use a bare MsgBox.
  • Do not show a UserForm. A form's dialog cannot be intercepted either, and hangs the batch the same way.
  • Do not declare an input as anything but As String.
  • Do not use GetCurrentMacroPathName to locate files near your macro - the running copy is in %TEMP%\SwMacroFlow\ and that is the path you get back. Use a FilePath or FolderPath input instead.
  • Do not open or close documents yourself in batch mode; the host does it.
  • Do not rely on ActiveDoc in the run-once mode - there is none.
  • Do not depend on module-level state surviving cleanly from one file to the next.
  • Do not use End or Stop - End tears down the VBA project mid-batch.
  • Do not expect {Property} tokens to work without an open document.

Symptom to cause

What you seeCause
"Macro has a compile error" when adding itUsually an input declared as something other than As String.
"This macro has no runnable procedure"No argument-less Sub. Add Sub main().
"Can't read this macro's VBA project"SOLIDWORKS VBA editor: Tools → Options → Security → Trust Center → Macro Settings → tick Trust access to the VBA project object model.
"Fix every property placeholder in …"A String / FilePath / FolderPath value has malformed braces.
"Choose a file that exists …"A FilePath without {Property} tokens points at a missing file.
The batch hangs on the first fileA VBA.MsgBox call or a UserForm somewhere in the project.
Every row is amberA MsgBox with a button set other than the default, or an InputBox, is being reached on every file - or every file really is a partial success reported with vbExclamation.
An input has no field on the formThe token was used but never declared as a Const, or the literal is not exactly "@Token". A declaration on the line after a comment ending in _ is part of that comment.
An input is a plain text box with no tooltip or default, though the metadata is thereOn a continued declaration, a key lost the ' in front of it and was read as part of the previous key.
A wrong procedure runsThe entry point is not named main.
Error 91 on every fileActiveDoc was used without the Is Nothing guard.
Red row naming a missing propertyA {Property} token was not found on that document.
Red row about cannot resolve / no document{Property} used in run-once mode, or the document failed to open.
Changes are not savedThe macro modified the document but never saved it; closing discarded the edit.
The macro cannot find a file beside itselfGetCurrentMacroPathName returns the temporary copy's path. Use a FilePath or FolderPath input instead.