Macro to export selected bodies to foreign format

Edit ArticleEdit Article
More 'Goodies'

When exporting part file to most of the foreign format supported by SOLIDWORKS it is possible to select the scope bodies of export, allowing to only process selected bodies.

Export bodies dialog
Export bodies dialog

However this feature is not supported by all formats. For example the formats such as 3D xml, xaml, amf, 3mf will always export all bodies, regardless of the selection.

This VBA macro allows to export only selected bodies to any format supported by SOLIDWORKS.

Select the bodies, faces, edges or vertices and run the macro and specify the name of export to produce a result.

Private Declare PtrSafe Function GetSaveFileName Lib "comdlg32.dll" Alias "GetSaveFileNameA" (pOpenfilename As OPENFILENAME) As LongPtr

Private Type OPENFILENAME
  lStructSize As Long
  hwndOwner As LongPtr
  hInstance As LongPtr
  lpstrFilter As String
  lpstrCustomFilter As String
  nMaxCustFilter As Long
  nFilterIndex As Long
  lpstrFile As String
  nMaxFile As Long
  lpstrFileTitle As String
  nMaxFileTitle As Long
  lpstrInitialDir As String
  lpstrTitle As String
  Flags As LongPtr
  nFileOffset As Integer
  nFileExtension As Integer
  lpstrDefExt As String
  lCustData As Long
  lpfnHook As Long
  lpTemplateName As String
End Type

Const FILTER As String = "3D Manufacturing Format (*.3mf)|*.3mf|3D XML (*.3dxml)|*.3dxml|Additive Manufacturing File (*.amf)|*.amf|Microsoft XAML (*.xaml)|*.xaml|All Files (*.*)|*.*"
Dim swApp As SldWorks.SldWorks

Sub main()

    Set swApp = Application.SldWorks
    
try_:
    
    On Error GoTo catch_

    Dim swModel As SldWorks.ModelDoc2
    Set swModel = swApp.ActiveDoc
    
    If swModel Is Nothing Then
        Err.Raise vbError, "", "Please open model"
    End If
    
    Dim vBodies As Variant
    vBodies = CollectSelectedBodies(swModel)
    
    If Not IsEmpty(vBodies) Then
        Dim filePath As String
        filePath = BrowseForFileSave("Select file path to save", FILTER)
        
        If filePath <> "" Then
            ExportBodies filePath, vBodies
        End If
    Else
        Err.Raise vbError, "", "Select bodies to export"
    End If
    
    GoTo finally_
    
catch_:
    swApp.SendMsgToUser2 Err.Description, swMessageBoxIcon_e.swMbStop, swMessageBoxBtn_e.swMbOk
finally_:

End Sub

Function BrowseForFileSave(title As String, filters As String) As String
    
    Dim of As OPENFILENAME
    Const FILE_PATH_BUFFER_SIZE As Integer = 260
    
    of.lpstrFilter = Replace(filters, "|", Chr(0)) & Chr(0)
    of.lpstrTitle = title
    of.nMaxFile = FILE_PATH_BUFFER_SIZE
    of.nMaxFileTitle = FILE_PATH_BUFFER_SIZE
    of.lpstrFile = String(FILE_PATH_BUFFER_SIZE, Chr(0))
    of.Flags = &H200000
    of.lStructSize = LenB(of)
    
    If GetSaveFileName(of) Then
        
        Dim filePath As String
        filePath = Left(of.lpstrFile, InStr(of.lpstrFile, vbNullChar) - 1)
        
        Dim vFilters As Variant
        vFilters = Split(FILTER, "|")
        Dim ext As String
        ext = vFilters((of.nFilterIndex - 1) * 2 + 1)
        ext = Right(ext, Len(ext) - InStrRev(ext, ".") + 1)
        
        If LCase(Right(filePath, Len(ext))) <> LCase(ext) Then
            filePath = filePath & ext
        End If
        
        BrowseForFileSave = filePath
        
    Else
        BrowseForFileSave = ""
    End If
    
End Function

Function CollectSelectedBodies(model As SldWorks.ModelDoc2) As Variant
    
    Dim swSelMgr As SldWorks.SelectionMgr
    
    Dim swBodies() As SldWorks.Body2
    
    Set swSelMgr = model.SelectionManager
    
    Dim i As Integer
    
    For i = 1 To swSelMgr.GetSelectedObjectCount2(-1)
        
        Dim swSelObj As Object
        Set swSelObj = swSelMgr.GetSelectedObject6(i, -1)
        
        Dim swBody As SldWorks.Body2
        
        If TypeOf swSelObj Is SldWorks.Body2 Then
            Set swBody = swSelObj
        ElseIf TypeOf swSelObj Is SldWorks.Feature Then
            Dim swFeat As SldWorks.Feature
            Set swFeat = swSelObj
            Dim swFeatFace As SldWorks.Face2
            Set swFeatFace = swFeat.GetFaces()(0)
            Set swBody = swFeatFace.GetBody
        ElseIf TypeOf swSelObj Is SldWorks.Face2 Then
            Dim swFace As SldWorks.Face2
            Set swFace = swSelObj
            Set swBody = swFace.GetBody
        ElseIf TypeOf swSelObj Is SldWorks.Edge Then
            Dim swEdge As SldWorks.Edge
            Set swEdge = swSelObj
            Set swBody = swEdge.GetBody
        ElseIf TypeOf swSelObj Is SldWorks.Vertex Then
            Dim swVertex As SldWorks.Vertex
            Set swVertex = swSelObj
            Dim swVertEdge As SldWorks.Edge
            Set swVertEdge = swVertex.GetEdges()(0)
            Set swBody = swVertEdge.GetBody
        Else
            Err.Raise vbError, "", "Cannot find body of the selected object " & i
        End If
        
        If Not Contains(swBodies, swBody) Then
            If (Not swBodies) = -1 Then
                ReDim swBodies(0)
            Else
                ReDim Preserve swBodies(UBound(swBodies) + 1)
            End If
            Set swBodies(UBound(swBodies)) = swBody
        End If
        
    Next
    
    CollectSelectedBodies = swBodies
    
End Function

Sub ExportBodies(filePath As String, vBodies As Variant)

    Dim swTempPart As SldWorks.ModelDoc2
    
    Dim swPartTemplate As String
    swPartTemplate = swApp.GetUserPreferenceStringValue(swUserPreferenceStringValue_e.swDefaultTemplatePart)
    
    If swPartTemplate = "" Then
        Err.Raise vbError, "", "No default part template found"
    End If
    
    Dim curErr As ErrObject
    
try_:
    
    On Error GoTo catch_
    
    Set swTempPart = swApp.NewDocument(swPartTemplate, swDwgPaperSizes_e.swDwgPapersUserDefined, 0, 0)
    
    Dim i As Integer
    
    For i = 0 To UBound(vBodies)
        
        Dim swBody As SldWorks.Body2
        Set swBody = vBodies(i)
        Set swBody = swBody.Copy
        
        Dim swBodyFeat As SldWorks.Feature
        Set swFeat = swTempPart.CreateFeatureFromBody3(swBody, False, swCreateFeatureBodyOpts_e.swCreateFeatureBodySimplify)
        
        If swFeat Is Nothing Then
            Err.Raise vbError, "", "Failed to create feature from body"
        End If
        
    Next
    
    Dim errs As Long
    Dim warns As Long
    
    If False = swTempPart.Extension.SaveAs(filePath, swSaveAsVersion_e.swSaveAsCurrentVersion, swSaveAsOptions_e.swSaveAsOptions_Silent, Nothing, errs, warns) Then
        Err.Raise vbError, "", "Failed to export file. Error code:" & errs
    End If
    
    GoTo finally_
    
catch_:
    Set curErr = Err
finally_:
    
    If Not swTempPart Is Nothing Then
        swApp.CloseDoc swTempPart.GetTitle
    End If
    
    If Not curErr Is Nothing Then
        Err.Raise curErr.Number, curErr.Source, curErr.Description
    End If

End Sub

Function Contains(vArr As Variant, item As Object) As Boolean
    
    Dim i As Integer
        
    If Not IsEmpty(vArr) Then
        
        For i = 0 To UBound(vArr)
            If vArr(i) Is item Then
                Contains = True
                Exit Function
            End If
        Next
    
    End If
    
    Contains = False
    
End Function

Product of Xarial Product of Xarial