VBA workaround for ChangeCustomPropertyNotify bug?

It seems that since 2018, the ChangeCustomPropertyNotify event will not be fired if the user changes a custom property, vs it being done through code. CodeStack has an article about this and a C# work around.

https://www.codestack.net/solidworks-api/data-storage/custom-properties/handle-events/

I’m wondering if anyone has a workaround that will work in VBA? This is galaxies away from my coding abilities to create.

Thank You

Have you tested this with your SW version? There is an SPR (SOLIDWORKS API: Events AddCustomPropertyNotify, ChangeCustomPropertyNotify and DeleteCustomPropertyNotifyin in SOLIDWORKS 2018 API do not work) that is listed as fixed in SW 2021.

Thanks for the hint about the SPR. I’m trying it on 2023SP5. I’m probably doing something wrong. I’m new to event handlers (as you know) and find the API help to be a bit anemic on implementation tips.

Instead of a new class module, I implemented the code in the Form Code. At the top I have

Dim WithEvents swApp        As SldWorks.SldWorks
Dim WithEvents pDoc         As PartDoc
Dim WithEvents aDoc         As AssemblyDoc
Dim WithEvents dDoc         As DrawingDoc

which I got from you. And, here are my prototype event handlers

Private Function aDoc_ChangeCustomPropertyNotifyEventHandler( _
    ByVal propName As String, _
    ByVal Configuration As String, _
    ByVal oldValue As String, _
    ByVal NewValue As String, _
    ByVal valueType As Integer) As Long
    Debug.Print "****** aDoc_ChangeCustomPropertyNotifyEventHandler"
End Function

Private Function dDoc_ChangeCustomPropertyNotifyEventHandler( _
    ByVal propName As String, _
    ByVal Configuration As String, _
    ByVal oldValue As String, _
    ByVal NewValue As String, _
    ByVal valueType As Integer) As Long
    Debug.Print "****** dDoc_ChangeCustomPropertyNotifyEventHandler"
End Function

Private Function pDoc_DpDocEvents_ChangeCustomPropertyNotifyEventHandler( _
    ByVal propName As String, _
    ByVal Configuration As String, _
    ByVal oldValue As String, _
    ByVal NewValue As String, _
    ByVal valueType As Integer) As Long
    Debug.Print "****** pDoc_DpDocEvents_ChangeCustomPropertyNotifyEventHandler"
End Function

The other handlers that you gave me work well (for the most part. Behavior seems inconsistent.), but these new ones do nothing.

I just discovered that i can get the programming interface to write my functions’ first lines. Using the drop downs for “object” and for “procedure”, I got the following (that still does not work)

Private Function aDoc_ChangeCustomPropertyNotify(ByVal propName As String, ByVal Configuration As String, ByVal oldValue As String, ByVal NewValue As String, ByVal valueType As Long) As Long
    Debug.Print "aDoc_ChangeCustomPropertyNotify"
End Function

Private Function dDoc_ChangeCustomPropertyNotify(ByVal propName As String, ByVal Configuration As String, ByVal oldValue As String, ByVal NewValue As String, ByVal valueType As Long) As Long
    Debug.Print "dDoc_ChangeCustomPropertyNotify"
End Function

Private Function pDoc_ChangeCustomPropertyNotify(ByVal propName As String, ByVal Configuration As String, ByVal oldValue As String, ByVal NewValue As String, ByVal valueType As Long) As Long
    Debug.Print "pDoc_ChangeCustomPropertyNotify"
End Function

Most likely what you are missing is the fact that you are responsible for keeping track of the active document (all documents really). Your aDoc, pDoc and dDoc variables do not magically point at the active document. At a minimum, you need to listen to the ActiveDocChangeNotify event and then assign pDoc, aDoc or dDoc to the newly active document. But there are a lot of other cases you need to handle as well, such as getting the already active document if something was open when the macro is run.

For creating SOLIDWORKS add-ins, there is a Visual Studio template that is provided and there is quite a bit of boilerplate code included with it for this aspect of event handling. Essentially tracking all the documents that get opened/closed and adding/removing event handlers accordingly.

I did a quick test (with SW2025) and can verify that the CustomProperty event handlers do work correctly when pDoc, aDoc or dDoc actually points at the active document.

Jim, thank you for your feedback. I understand what you are saying. I have never really paid attention to what swApp and swModel are set to. I always just set them to Application.SolidWorks and to swApp.ActiveDoc without thinking about it. Looks like I need to pay better attention to that.

You mentioned a Visual Studio template. I looked around, but really don’t know what I am looking for. Where is that?

Also, I find that the API help sometimes mentions tutorial examples, but have never found them as well.

Thank you again for responding to all my questions. This has helped a lot!

The Visual Studio templates are part of the SW API SDK:

Keep in mind that the templates are only for creating add-ins with C++/.NET using Visual Studio. They aren’t meant for macros, but the EventHandling.vb file does show the typical level of ‘bookkeeping’ required to manage multiple documents and their events.

Thanks, Jim. I got my code working for the most part. Unfortunately, DestroyNotify2 is a prenotification of when a file is closing. I haven’t been able to figure out how to determine if all docs have been close yet.

Check the number of open documents in your DestroyNotify event handler. If the count is one, then you know that this is the last document.

I tried that, but if the last doc is a drawing or assembly, the number is greater than 1 :frowning:

Yup. Sorry about that. You can write a function to check for the number of documents that are open and visible. If that value is 1 in your DestroyNotify handlers for an assembly or a drawing, then the last document is closing:

Function getVisibleDocCount() As Integer
    Dim openDocs As Variant
    Dim nextDoc As ModelDoc2
    openDocs = swApp.GetDocuments
    For i = 0 To UBound(openDocs)
        Set nextDoc = openDocs(i)
        If nextDoc.Visible Then
            getVisibleDocCount = getVisibleDocCount + 1
        End If
    Next i
End Function
Private Function aDoc_DestroyNotify2(ByVal DestroyType As Long) As Long
    If getVisibleDocCount = 1 Then
        myForm.docTitle = "No active document"
        Set pDoc = Nothing
        Set aDoc = Nothing
        Set dDoc = Nothing
    End If
End Function

That worked GREAT! Thanks for the pointer!