This video summarizes the contents of this post and demonstrates the examples listed below.
Ever wanted a macro so tightly integrated with a part or assembly that 1) the macro always ran as long as the model was open, 2) the macro traveled with the model wherever it went? Using a clever, undocumented trick involving equations and the Design Binder, both of these are possible with little initial setup. The result is what I call Equation-Triggered Macros.
Note: As of SolidWorks 2015, Equation-Triggered Macros do not appear to be working at all. They are also not supported by SolidWorks Corporation. Use at your own risk.
For our case study, let’s consider a problem I received from a friend a few weeks ago. His parts need to have their custom properties listed in alphabetical order. To reduce time and error, he could create an event notification macro that runs on SolidWorks startup and sorts the custom properties on every rebuild. Starting the macro with SolidWorks requires modifying the SolidWorks shortcut arguments on the user’s computer.
Two problems arise. First, you’ve now created a lot of administrative work for yourself because every user’s computer needs to be set up to automatically run this macro. Second, if the user doesn’t open SolidWorks through the modified shortcut then the macro will not run. Here’s how you can alleviate both problems without creating even more administrative work for yourself.
Step One : Write the Macro
Self-explanatory. In our case, we need to write a macro that sorts the custom properties alphabetically when it is run.
Step Two : Embed or Reference the Macro
Embedding versus referencing is essentially the same idea as embedding a design table within a document versus linking to it at an external location. If you embed, the macro travels with the document. No concerns about the macro getting lost or the link path becoming invalid. But if you need to change the macro code in lots of models? That could be a real chore (though you could write a macro that does this for you—more on that in the last section). If you think you’ll need to change the code regularly or simply want to remain in control of the code at all times, referencing is safer.
Embedding a macro in a document is pretty simple. While you have a part or assembly open, right click on the Design Binder (you might have to make it visible using Hide/Show Tree Items if it isn’t already) and choose Add Attachment. Browse for the .swp file, click OK, and you’re done!
Referencing a macro is also simple. Just put the macro in the desired hard-drive / network location and copy the path. We’ll use the path in the next step.
Step Three : Add An Equation That Calls The Macro
This is where it gets interesting. Josh Brady, a long-time SolidWorks API enthusiast, made an incredible discovery back in 2007. Noting that you could use the VBA “iif” function in SolidWorks equations, he decided to see if other VBA equations could be used as well. The answer? Any and all VBA functions can be used as long as you format them properly! He also discovered that the same is true for custom properties. If you want to learn all of the guidelines and caveats for using VBA in equations, you can watch his excellent SolidWorks World 2011 presentation titled “Advanced Equations Using VBA and API Code”. The presentation files can be downloaded here.
Without going into details about formatting, here are the equations you need for embedding and referencing a macro named “macro.swp” with a sub-procedure named “main” in a module named “mMain”. Once you add the appropriate equation, each time your part or assembly rebuilds, the macro will be run.
"Var1"= 1::swApp.RunAttachedMacro "macro.swp", "mMain", "main"
"Var2"= 1::Dim lngErr As Long::swApp.RunMacro2 "C:\macro.swp", "mMain", "main", swRunMacroDefault, lngErr
- The variable names are arbitrary and have no effect on the macro itself. If you already have a variable called “Var1” or “Var2”, then use another name.
- The arguments for ISldWorks::RunAttachedMacro and ISldWorks::RunMacro2 need to match your macro name/path, module, and entry point. See the API Help articles for more details. In other words, unless your macro is named “macro.swp” and contains a sub-procedure called “main” in a module called “mMain”, using the code above verbatim will not trigger your macro!
- Since SolidWorks 2012, the Equation Manager makes it difficult to add these equations due to the equation checker disliking the syntax of equations containing VBA code. To make sure you’ve added the equations properly, you should put the equation in a text file and then import that text file. As shown in the image below, the resulting equation may not successfully evaluate and the syntax may appear incorrect, but it should still work. If you struggle to get the Equation Manager to accept the equation, use Luke Malpass’ equation editor tool that lets you bypass the syntax checker. Please note that as long as the check next to the equation is gray, the equation has not been accepted and will not work.
Going To The Next Level
At this point you should see the unique flexibility and power offered by equation-triggered macros (ETMs), possibly in conjunction with the Design Binder. With the “vanilla” ETM setup I’ve just shown you, however, the macro always runs when the part rebuilds, and sometimes you need more control over when the macro runs. To give you that control, I’ve created a class called ETMUtil that you can add to a macro (whether embedded or referenced) that gives you the following options:
- Only allow your code to trigger once within a specific time period (e.g., 30 seconds).
- Only trigger your code once when the part is opened.
- Only trigger your code once the first time a part is opened, but never on subsequent openings. This might be used with part or assembly templates for example, to aid the initial configuration of the model.
- Delete the temporary macro files. When a macro is run from the Design Binder, a copy of the macro is created in C:\Users\
\AppData\Local\Temp and then run. Due to known bug (SPR 400218) SolidWorks never deletes these files, so they can build up over time. If you think this could become a problem over time and you don’t want to remember to delete them manually, ETMUtil can help. Obviously this problem is avoided entirely if you reference the macro instead of embedding it using the Design Binder.
Sound appealing? ETMUtil, and instructions on how to use it, is available to CADSharp.com premium members in the Macro Library under Automation / Tools. Watch the video at the beginning of this post to see ETMUtil in action or check out one of the examples below.
Note: As of SolidWorks 2014, ETMUtil no longer works, because the ability to suppress equations was removed. An alternative solution exists using event notifications, but I have not had time to implement it.
Here’s the finished version of the part from the original case study we discussed, along with three other examples.
Sort custom properties – Macro is embedded in a part. Every rebuild, the custom properties are sorted into alphabetical order.
Keep bodies renamed – Macro is embedded in a part. Every rebuild, the solid bodies are renamed Body1, Body2, Body3, etc.
Track part usage in assemblies – Macro is embedded in an assembly. Before the assembly is saved, the part level custom properties are updated to contain the number of times the part is used in an assembly. The custom property is named after the assembly. The code triggers before the assembly is saved instead of during each rebuild to improve performance.
Display user form on part open – (Premium members only) Macro is embedded in a part. When the part is opened, a user form is displayed that allows the user to easily change the part material and modify a custom property called “Edited By”. Uses ETMUtil to allow code to prevent any equation-triggers beyond the first one when the part opens.
Answers to Important Questions
[expand title=”Why can’t I use equation-triggered macros with drawings?”]
Because you can’t add equations to drawings.
[expand title=”Using equation-triggered macros it is possible run code on every rebuild. Is there any way I can listen for other events?”]
Yes. The macro you embed or reference simply needs to listen for that event using event notifications (see our Macro Library for examples). In fact, if you wanted to have your code run post-rebuild instead of when the equation recalculates, you could use ETMUtil to turn on a post-rebuild listener as soon as the part opens, prevent any additional equation-triggers, and use that listener to trigger your code.
[expand title=”My macros are in VB.NET / C#. Is there any way I can still use this technique?”]
Yes. You’ll need to always reference the macros from an external location because .NET macros cannot be run from the Design Binder.
[expand title=”When I edit a macro in the Design Binder and save it, the macro behaves as though I never edited it. Why?”]
You can’t truly edit a macro that’s in the Design Binder. You need to make edits to a macro that is on your hard-drive or network, then delete out the macro in the Design Binder, and add in the edited macro.
[expand title=”I can’t get the equation editor to accept my equation containing VBA code. What can I do?”]
First, did you try using Luke Malpass equation editor tool, which bypasses the Equation Manager’s syntax checker? Second, does part of the equation contain VBA keywords like “if”? For example, a macro called “modify fillet.swp” will confuse the Equation Manager because it thinks that the letters “if” in “modify” are the beginning of an if-then statement. Third, have you tried using the referencing equation rather than the embedding equation? In some instances I’ve seen the Equation Editor refuse to accept one but not the other.
[expand title=”SolidWorks is crashing when my equation-triggered macro runs. Why?”]
Does your macro edit features or perform any other task that might cause a rebuild? Keep in mind that ETMs run during a model’s rebuild. Causing another rebuild during this first rebuild will probably cause a crash. One way you can avoid this situation is by having your ETM start a post-rebuild listener that performs your task once the model rebuild is finished. The rebuild listener should be set to nothing after it has done its work (see example), otherwise that same task will keep running during every rebuild, even if you’re using ETMUtil (or your own code) to prevent subsequent triggerings of the code.
[expand title=”Using equation-triggered macros, couldn’t SolidWorks models carry viruses?”]
Yes, they could. For that reason you should only accept CAD files from trusted sources. Of course, a virus could be implemented in a macro feature as well, so it is not as though this is a new possibility.
[expand title=”How can equation-triggered macros improve .NET macro features?”]
Unlike VBA macro features, .NET macro features cannot have code that defines the macro feature embedded in the document. This means that if the path to the DLL is invalid, the macro feature will fail. This makes it tedious when sending files containing .NET macro features to other users, because you have to ensure that they have the defining macro and its supporting DLLs in the right path on their end. Using the equation + Design Binder technique, you can place the defining macro and its supporting DLLs in the Design Binder and a macro that verifies that the defining macro exists at the correct location. If it doesn’t, it saves the defining macro and its supporting DLLs to that location.
I hope you enjoyed learning about equation-triggered macros as much as I did. If you have ideas for ways you could use them, I’d love hear about it in the comments.
Onward into new automation frontiers,
Want to keep up with future CADSharp.com content, webinars, and special offers? Sign up for our newsletter.
Really nice article. I love the idea/concept of how it works and can immediately see many potential uses/applications. I like the “Track part usage in assemblies” example as this is useful for BOM-related functions.
This is a very useful article. I now aim to use equation triggered macros to automate my designs. Thanks Keith!
Awesome! I think this will help a lot with users who don’t always follow protocol.
Have you tried massive assemblies where every part has ETM? I think executing on open will cause the users the least delay.
What is the overhead on file size when you have a macro in the design binder? I never tested. I know some colleague’s found bugs in design binder before.
I have not tried using ETMs on such a large scale. Also, as far as I know, the ETM in a part will not run while you have the assembly open.
Concerning part size, I did a test just now. In 2013, a part that is 450 KB alone became 800 KB with a 180 KB macro.
Very interesting method of using macros!
Will be definitely thinking about where this could be used in the future.
Well done to all in figuring this method out.
Implementing a macro in a part looks pretty cool, because you don’t have to teach somebody, you just say: “Hey, if you write new properties, it will sort automatically.” (or what ever your macro have to do) And that’s the way we like it! Do nothing…get all!
This way you get the “intelligence” part without the extra steps involved. You don’t forget to run a macro or what else. I’ll use it for sure. Thanks a lot for this new advice.
Greetings from Germany,
In the last example where the form comes up on the 1st rebuild and then is suppress until it is saved. Would it not be simpler and easier to just have the form be triggered by the fileopennotify event, there for you would not need to suppress and unsuppresss the equation?
The part is already open by the time the equation triggers the macro, so I don’t think that notification would fire. Maybe swAppFileOpenPostNotify would work. Let me know if you test it out.
I can’t say I understand why but the part must open and rebuild before the events are triggered. I just did a test and DocumentLoadNotify, DocumentLoadNotify2, FileOpenNotify, FileOpenNotify2, and FileOpenNotify2 all fired after the part is opened and the macro is running.
I have this setup working in a sheet metal template file that has a user form to fill out the part parameters. This is only needed the 1st time the file is loaded and then never again so for my needs I suppress the equation as it is not needed anymore for that file but you can keep it unsuppressed and it will run only when the file is loaded. The only drawback I have found so far is I don’t know how to stop my NotificationClass after it is finished so any file opened after that triggers the userform. I have to add some code to set swApp to nothing after the form is finished to keep that from happening.
Thanks for doing those tests and pointing this out to me. I just tested it out myself, and “FileOpenNotfy2” does fire. So apparently whatever triggers doesn’t occur until after the equations are first calculated. Certainly, then, you could use this approach to run a macro only when the part loads. Of course, as you noted, if you want to prevent the macro from running on subsequent loads then you still need to suppress the equation using IEquationMgr::Suppression.
If you want to prevent the notifications from firing later then you need to set the listener class to Nothing. Declare the listener class as a Public variable. Do not auto-instantiate it. There’s an example of killing the listener class in the Macro Library. Check out the example “Determine whether new or existing file was opened”.
Thanks Keith. I finally had time to try this and it works better.
Thank you very much for the article, however, it seems that this method does not work in Solidworks 2015. I have tried to automate a macro that I need to run on all parts without success. If I create a Macro Button I get the results needed but when trying to register the macro to an equation to automatically run I get syntax related errors and the macro does not run. Would you be able to test SW2015 to see if it is possible to use the methods advised in this article.
That’s correct, it no longer works as of SolidWorks 2015.
I’m having trouble adding the equation. I followed all your steps and either Solidworks do not accept the equation or when it does, the macro is not running on rebuild! I have Solidworks 2015 SP4, do you know if the feature is still supposed to be working?
Unfortunately, this technique no longer works as of SolidWorks 2015.