Need some philosophical advice on a macro process

Greetings all,

I’ve got a macro, written in VBA, that is usable in either a part or an assembly, and writes STL files to a subfolder.

The process is continent on there being a custom property named 3D_Print being toggled on.

If it’s a part, it just writes the part if 3D_Print is toggled on. If not, it does nothing.

If it’s an assembly, it will traverse the assembly tree and save all the parts with 3D_Print toggled on, and all the configuration variants. In other words if a part is inserted with 2 configurations, both will be saved with their filename-configuration if the 3D_Print property is toggled.

At present the process will not overwrite files in the output folder, and will attempt to save a part for as many times as it’s in an assembly.

So, ideally, I’d like the following:

  1. If a part, and file name exists, ask to overwrite. This I don’t need assistance with.
  2. If an assembly, if a part filename exists ask to overwrite, Similarly this I don’t need assistance with.
  3. If an assembly, don’t repeatedly save the same part. If a part name exists, ask to overwrite the first time. Once done, don’t repeat the process for duplicate parts. This I need some ideas for.

Dunno if this is the right place to post this or not.

thanks

For 3, you could add the file name to a list of “processed documents” and check that the file isn’t in that list before saving.

Rather than traverse the tree, why not get the file references? Each will show up only once and you avoid the issue entirely.

3 Likes

Interesting. How is that at done?

Thanks

I misspoke (slightly). The FindReferences functionality isn’t exactly available via the API (there is an Enhancement Request for it). I use PDM which does have this functionality. Without PDM, you have two options.

If you have an active SW subscription, you can get a DocumentManager API license key and you can use the GetExternalFeatureReferences3 function. The nice part about the document manager API is that you don’t have to open the document in SOLIDWORKS to get the reference information or to check the custom properties.

This simple example will get an array of names of the referenced documents for the file in the ‘path’ variable. The array elements are then put into a collection which will eliminate any duplicates. Then each element in the collection is checked to see if the Print_3D custom property is ‘Yes’.

Dim swApp As SldWorks.SldWorks
Dim factory As SwDMClassFactory
Dim dmApp As SwDMApplication4
Dim doc As SwDMDocument30
Const key = "your document manager license key"
Const path = "path to document"
Dim errors As SwDmDocumentOpenError
Dim refOption As SwDMExternalReferenceOption2
Dim searchOption As SwDMSearchOption
Dim refCount As Long
Dim refNames As Variant
Dim foundNames As New Collection
Sub main()
    Set swApp = Application.SldWorks
    Set factory = New SwDMClassFactory
    Set dmApp = factory.GetApplication(key)
    Set doc = dmApp.GetDocument(path, swDmDocumentAssembly, True, errors)
    Set refOption = dmApp.GetExternalReferenceOptionObject2
    refOption.NeedSuppress = True
    refOption.Configuration = "DEFAULT"
    Set searchOption = dmApp.GetSearchOptionObject
    searchOption.SearchFilters = SwDmSearchFilters.SwDmSearchExternalReference
    refOption.searchOption = searchOption
    refCount = doc.GetExternalFeatureReferences3(refOption)
    refNames = refOption.ExternalReferences
    For i = LBound(refNames) To UBound(refNames)
        If Not Contains(foundNames, refNames(i)) Then 'Prevent duplicates
            foundNames.Add refNames(i), refNames(i)
        End If
    Next i
    For Each foundName In foundNames
        Dim docPath As String
        docPath = foundName
        ProcessDocument docPath
    Next
End Sub

Sub ProcessDocument(docPath As String)
    Dim doc As SwDMDocument30
    Dim errors As SwDmDocumentOpenError
    Set doc = dmApp.GetDocument(docPath, GetDocType(docPath), True, errors)
    If doc.GetCustomPropertyCount = 0 Then
        Exit Sub
    End If
    Dim print3D As String
    Dim names() As String
    names = doc.GetCustomPropertyNames
    print3D = doc.GetCustomProperty2("3D_Print", swDmCustomInfoYesOrNo)
    If (print3D = "Yes") Then
        Debug.Print docPath & " has 3D_Print enabled"
    End If
End Sub

Function GetDocType(docPath As String) As SwDmDocumentType
    Dim fs As FileSystemObject
    Set fs = CreateObject("Scripting.FileSystemObject")
    
    Select Case fs.GetExtensionName(docPath)
    Case "sldprt"
        GetDocType = swDmDocumentPart
    Case "sldasm"
        GetDocType = swDmDocumentAssembly
    End Select
End Function

Function Contains(col As Collection, key As Variant) As Boolean
    Dim obj As Variant
    On Error GoTo err
        Contains = True
        obj = col(key)
        Exit Function
err:
    Contains = False
End Function

If you can’t use the document manager API, you can get the list of references from the IAdvancedSaveAsOptions object returned from the ModelDocExtension::GetAdvancedSaveAsOptions method. Something like this:

Dim swApp As SldWorks.SldWorks
Dim mDoc As ModelDoc2
Dim mExt As ModelDocExtension
Dim saveOptions As AdvancedSaveAsOptions

Sub main()
    Set swApp = Application.SldWorks
    Set mDoc = swApp.ActiveDoc
    Set mExt = mDoc.Extension
    Set saveOptions = mExt.GetAdvancedSaveAsOptions(0)
    Dim ids As Variant
    Dim names As Variant
    Dim paths As Variant
    saveOptions.GetItemsNameAndPath ids, names, paths
    For i = LBound(names) To UBound(names)
        If names(i) <> mDoc.GetTitle Then
            ProcessDocument (paths(i) & "\" & names(i))
        End If
    Next i
End Sub

Sub ProcessDocument(docPath As String)
    docPath = Replace(docPath, " [Not Open]", "")
    Dim doc As ModelDoc2
    Dim docExt As ModelDocExtension
    Dim retval As Long
    Dim propMgr As CustomPropertyManager
    Dim errors As Long
    Set doc = swApp.OpenDocSilent(docPath, GetDocType(docPath), errors)
    Set docExt = doc.Extension
    Set propMgr = docExt.CustomPropertyManager("")
    If propMgr.Count = 0 Then
        swApp.CloseDoc docPath
        Exit Sub
    End If
    Dim val As String
    Dim resolvedVal As String
    Dim wasResolved As Boolean
    retval = propMgr.Get6("3D_Print", False, val, resolvedVal, wasResolved, False)
    If (resolvedVal = "Yes") Then
        Debug.Print docPath & " has 3D_Print enabled"
    End If
    swApp.CloseDoc docPath
End Sub

Function GetDocType(docPath As String) As swDocumentTypes_e
    Dim fs As FileSystemObject
    Set fs = CreateObject("Scripting.FileSystemObject")
    
    Select Case LCase(fs.GetExtensionName(docPath))
    Case "sldprt"
        GetDocType = swDocPART
    Case "sldasm"
        GetDocType = swDocASSEMBLY
    End Select
End Function

I was able to get a DM key while my sub was still active.

Thanks, I’ll have a look at what you posted.

cheers

Here is another option using Collections

Option Explicit

Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swComp As SldWorks.Component2
Dim vComps As Variant
Dim i As Long
Dim PartFiles As New Collection

Sub Main()

Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc

swModel.ResolveAllLightWeightComponents (False)

vComps = swModel.GetComponents(False)

For i = 0 To UBound(vComps)

Set swComp = vComps(i)

If ExistsInCollection(PartFiles, swComp.GetPathName) = False Then
Debug.Print swComp.GetPathName
PartFiles.Add swComp.GetPathName, swComp.GetPathName
End If

Next i

End Sub

’ Function to check if an item exists in a collection
Public Function ExistsInCollection(col As Collection, key As Variant) As Boolean
On Error GoTo err
ExistsInCollection = True
IsObject (col.Item(key)) ’ Check if the item exists in the collection
Exit Function
err:
ExistsInCollection = False ’ Return false if the item does not exist
End Function

Thanks Gupta.

You and John have given me much to study.

Cheers

There is a way to get referenced documents without opening a file. The only issue is that it’s the last known location of that referenced file(s) from when the parent file was last saved. So it’s not guaranteed to exist in that location, especially if files are moved around a lot.

Each of the ways mentioned have their pros and cons, this is just another way to obtain that document list.

Does EnSuite Impact360 from CCE Technologies (www.cceintl.com) which claims to do automate tasks using CAD data in a no-code environment (ie. without CAD API programming) actually work?

Has anyone tried this? what is your experience?

Thanks

At first glance it looks like a RPA like system.
Honestly I think it is better to hire a coder in your org and make him document everything.