My question is whether or not this is a good practice, and/or if there is a more efficient way to do it.
I have to access this Solidworks interop object and wait for it to return some value. The return is a string. In early testing I found I ran into issues if I didn't wait for the return, so I added a "DoEvents" wait loop using
While len(strProp)=0 to wait for the string to populate so I would know the call had executed and returned something.
The issue I then ran into was that when there is no value in the interop object's property, the return IS a zero-length string. So it would just loop forever, even though the call had completed.
Normally I would just use a "time-out" value - e.g. get the current time, and have an exit loop statement when a certain amount of time has passed. However, in testing I found sometimes the call could actually take over a minute to complete. Since I'm processing thousands of properties at a time, I thought I would be wasting a TON of time waiting for empty ones. So I came up with the idea of setting the string to a "nonsense" value before the call to the interop object, and then checking for when it changes to know that the call has completed.
Private Function GetModelProps(ByRef swCustPropMgr As SldWorks.CustomPropertyManager, Optional ByVal dicInput As Scripting.Dictionary) As Scripting.Dictionary 'This procedure gets the properties from a custom property manager object that is passed by the calling procedure. It returns a dictionary object containing the properties found. 'Declare constants Const strNonsense As String = "SKDjf09sf!@&#(@#$&!(*^)_!@0-12-849uj0394jfIODJS(G_3r5902-129381203892193018" 'This is just a nonsense string that will never be entered in a custom property 'Declare variables Dim lngX As Long Dim strProps() As String Dim strProp As String Dim strPropStatement As String Dim strPropVal As String Dim dicProps As Scripting.Dictionary On Error GoTo CleanExit 'Initialize dictionary object Set dicProps = New Scripting.Dictionary 'Pass values from the input dictionary if one was provided If Not dicInput Is Nothing Then If Not IsArrayEmpty(dicInput.Keys) Then For lngX = LBound(dicInput.Keys) To UBound(dicInput.Keys) DicMergeOnKey dicProps, dicInput, (dicInput.Keys(lngX)) Next End If End If 'Attempt to get the names of all the custom properties. If there are no custom properties the array will not be initialized and populated. On Error Resume Next strProps = swCustPropMgr.GetNames On Error GoTo CleanExit 'Check to see if the array is empty - if it is, then there are no custom properties to get If Not IsArrayEmpty(strProps) Then 'Loop through all the custom properties For lngX = 0 To UBound(strProps) 'Get the custom property name strProp = strProps(lngX) 'Set initial value to a string that will never be found strPropVal = strNonsense 'The Get2 method takes one input and returns 2 strings: Input: Property name, Output1: Property statment, Output2: Evalutated property value swCustPropMgr.Get2 strProp, strPropStatement, strPropVal 'Sometimes this can take a while to execute, so we use the loop below to wait until the system is done processing all other events While strPropVal = strNonsense DoEvents Wend 'Make the property uppercase so we don't accidentally add multiple properties due to difference in case between documents strProp = UCase(strProp) 'Verify item numbers before adding If strProp Like "PARTNO" Then strPropVal = ValidateLokItem(Trim(strPropVal)) End If 'Add the returned value to the dictionary. If Len(strPropVal) > 0 Then If Not dicProps.Exists(strProp) Then dicProps.Add strProp, strPropVal Else dicProps.ITEM(strProp) = strPropVal End If End If Next End If 'Return the dictionary to the calling procedure Set GetModelProps = dicProps CleanExit: Set dicProps = Nothing Set dicInput = Nothing Erase strProps End Function