4 Eng
4 Eng
1) PREFACE: ....................................................................................................................................................... 5
2) INTRODUCTION ............................................................................................................................................. 6
3) PROGRAMMING BEST PRACTICES ................................................................................................................. 7
A) SEPARATION OF CONCERNS ............................................................................................................................... 8
2
F) UPDATING ADD-INS ...................................................................................................................................... 30
G) ARCHITECTING ADD-INS ................................................................................................................................. 31
3
Revision History
Rev # Date Description
1.0 March 2020 Document created
Note
All SolidPractices are written as guidelines. You are recommended to use these documents only
after properly evaluating your requirements. Distribution of this document is limited to Dassault
Systèmes SolidWorks employees, VARs and customers that are on active subscription. This
document may not be posted on blogs or any internal or external forums without prior written
authorization from Dassault Systèmes SolidWorks Corporation.
This document was updated using SOLIDWORKS 2020 SP02. If you have questions or need
assistance in understanding the content, please get in touch with your designated reseller.
Acknowledgments
This document was authored by CADSharp LLC and reviewed by Dassault Systèmes SolidWorks
Corporation.
4
1) Preface:
The SOLIDWORKS Application Programming Interface (API) is a powerful capability of the
SOLIDWORKS software because it allows a user with knowledge of programming to
automate almost any part of the software and thereby use SOLIDWORKS in ways that are
not possible interactively.
This document provides you with the best practices of developers who have already invested
tens of thousands of hours into developing the SOLIDWORKS API, and thereby help you
avoiding many common mistakes.
5
2) Introduction
The SOLIDWORKS API is one of the most powerful “features” of the SOLIDWORKS
software. This is because it allows a user with knowledge of programming to automate
almost any part of the software and thereby use SOLIDWORKS in ways that are not possible
under normal circumstances. Of course, the drawback to the SOLIDWORKS API is that it is
also the most complex “feature” of the software. It is effectively the intersection of two
distinct disciplines: computer-aided design (CAD) and programming. Each of these
disciplines has multiple layers of complexity. This means that the depth to which a skilled
engineer and programmer can take the SOLIDWORKS API are beyond what most users
realize is possible. On one extreme, a user might use the macro recorder to create a macro
that shaves off a few minutes of effort each day. On the other extreme, a company might use
an add-in or stand-alone application to automate the entire design workflow of their company
from front to back, thus saving the company a significant amount of money each year.
The intention of this document is to teach users how to develop with the SOLIDWORKS
API, which is well beyond the scope. Instead, the purpose is to provide you with the best
practices of developers who have already invested tens of thousands of hours into the
SOLIDWORKS API development. These best practices can help you avoid mistakes that
make your development experience slow and frustrating for you and your company.
6
3) Programming Best Practices
SOLIDWORKS users often ask, “How much programming or software development
experience do I need before I can use the SOLIDWORKS API?” The answer is simple, the
more the better. Unfortunately, there are no shortcuts with using the SOLIDWORKS API. If
you do not know the fundamentals of good software design, then your program, no matter
how small, will reflect that. Because most SOLIDWORKS users are self-taught programmers
s with less time to invest in software development than they would like, the resulting code is
often of low quality even if it ultimately performs the desired task. Low quality code is hard
to understand, hard to modify, hard to debug, and hard to reuse.
Over time, a SOLIDWORKS API developer should invest sufficient time into understanding
best practices for programming in general. These practices apply to any object-oriented
programming (OOP), whether the task is CAD API programming or writing the latest
cutting-edge mobile app. The following six best practices are relevant for any
SOLIDWORKS API programmer:
1. Meaningful naming. Always take the time to give your classes, functions, and
variables meaningful names. Otherwise, your code is hard to understand. When in
doubt, be more descriptive. For example, compare the name “face1” to
“largestPlanarFace”. While it may be obvious at the time of writing that this variable
stores the pointer to the largest planar face in a body, will it be obvious six months
from now?
2. Good formatting. Failure to indent or nest statements properly makes code difficult
to read. Modern integrated development environments (IDEs) like Visual Studio
make this easier. However, flagrant violations of this practice still occur when writing
Visual Basic for Applications (VBA) macros in the Visual Basic Editor.
3. Good commenting. It is possible to have too many code comments. If your function
names are clear and descriptive, then comments can become redundant. Use
comments in situations when it is necessary to provide a detailed explanation of why
write code in a particular way. For example, you might write several paragraphs of
comments to explain your reasoning for using a particular algorithm and not another
algorithm, which actually contains a subtle pitfall.
4. Control constants from one location. If your code contains multiple instances of a
constant value, that value should be stored in a single constant with scope over all
classes and methods where it is used. That constant should be referenced every time
the constant is needed. If the constant’s value needs to be modified, you then only
need to change it in one location rather than finding and changing every instance in
your code.
7
5. Expose configurable constants. If the end user ever needs to modify a constant’s
value, then you should not hard-code that constant. Otherwise, the user must contact
the developer in order to do so. This creates a dangerous bottleneck if the developer is
unavailable. Only hard-code constants that you are certain will never change (such as
mathematical constants, physical constants, and industrial standards). Expose the
remaining constants to the user (or at least the administrator) through settings forms
or neutral (XML, JSON) data files.
a) Separation of Concerns
Separation of concerns is the idea that every individual variable, function, class, and interface
should (usually) have one single purpose. In other words, a function should be concerned
with accomplishing one particular task. A class should represent one single object, and so on.
The simplest way to understand separation of concerns is to begin by understanding what a
violation of the principle looks like.
As an example, imagine that you are creating a program that simulates a basketball game.
(Apologies to readers who are unfamiliar with basketball. Hopefully, this example will make
sense anyway.) In such a program, you need classes such as Player, Referee, Crowd, Court,
Ball, Hoop, ShotClock, and others. Each class has its own properties and methods, which
correspond to information and actions that relate to the class. For example, the Player class
might have the following properties and methods:
Class: Player
Properties
Name
Height
Weight
Speed
Methods
Run()
Dribble()
8
Shoot()
Pass()
Foul()
To demonstrate a simple violation of separation of concerns, imagine that instead of having a
method for Dribble() and Shoot(), you have a method called DribbleAndShoot(). The
advantage, it appears, is that you have fewer methods. Does this make your program simpler?
Not at all, because now you have no way to cause a player to only dribble or only shoot
without modifying the inner workings of the function to allow for such situations based on
what arguments are passed into the function. The fault of this example might seem obvious.
However, programmers of every skill level make this mistake. The solution to this problem is
to “refactor” the code. This is also known as “modularizing” or “decoupling”.
When you refactor your code, you are taking the time to ask, “What is the purpose of this
code?” It is easy to begin writing a piece of code thinking that it will be simple, only to watch
it balloon over time into a monster that makes your program’s code difficult to extend, debug,
and reuse. The obvious tie-in to this point is that you need to plan the architecture of your
program before you begin writing it. As the tongue-in-cheek saying goes, “Three days of
debugging can save you three hours of planning.”
9
4) Program Type and Language Comparison
Options Available
Programs written using the SOLIDWORKS API include macros, add-ins, and stand-alone
applications. Although you can use any language that supports COM to write these programs,
SOLIDWORKS primarily supports VBA, [Link], C#, and C++. This document focuses on
the VBA, [Link], and C# languages because they are by far the most common options. The
following chart depicts which languages you can use with a particular program type.
What program type and language should you use? The program type you use affects the level
of integration, ease of development, ease of administration, and performance. The language
you use affects the ease of development, security, and performance. What the program type
and language do not affect is how you use the SOLIDWORKS API calls themselves (with
rare exceptions, which are beyond the scope of this document). The API functionality is
available in all program types and languages.
Some SOLIDWORKS API developers rarely write macros except when testing a particular
API call. This is because small VBA macros are much faster to write and debug than stand-
alone applications or add-ins that accomplish the same thing. It is also faster and simpler to
set up a .NET stand-alone application than it is to use a .NET macro. Moreover, the benefits
of C++ are limited (usually as they relate to performance), so some developers never write
C++ software using the SOLIDWORKS API.
Where does this leave us in terms of recommendations? Assuming that you know VBA and
.NET, one recommendation is to always use a .NET add-in or stand-alone application unless
you need a quick program for personal use. Of course, not everyone is a professional
developer, which means that many people do not know or have time to learn the .NET
language. In that case, you can accomplish quite a bit with a VBA macro. However, be aware
that you are missing out on the tremendous power of the .NET language. Another
10
disadvantage of VBA macros is that you cannot write them as stand-alone applications. This
means that you will never have the flexibility that a stand-alone application offers.
When choosing between add-ins and stand-alone applications, here are some considerations:
11
5) The Macro Recorder
More people try using the macro recorder to avoid learning any programming. This is a
mistake for those who try to use the SOLIDWORKS API because:
The macro recorder cannot know your intentions. The code that the macro recorder
creates has not indentation and often contains unnecessary calls.
You cannot record many parts of SOLIDWORKS, such as using custom properties.
You cannot record a macro that obtains user input.
You cannot record a macro that handles conditional logic. What you record is literally
all that happens when you run it.
With this in mind, the macro recorder still has value.. For example, if you struggle to find an
API in the Help, the macro recorder might be revelatory. Another example is in cases where
you do not want to take the time to add in the arguments for an API call with a huge number
of arguments manually, such as [Link].
12
6) The SOLIDWORKS API Help
Critical to your success as a SOLIDWORKS API programmer is a good understanding about
how to use the API. Here are several tips with regard to using the API:
1. The local API Help is arguably more useful than the online API Help because the
local API Help provides an Index that you can use to search by topic. To access the
local API help (assuming it is installed), first deactivate the Help > Use
SOLIDWORKS Web Help option, and then go to Help > API Help. This opens the
API Help compiled help (CHM) file.
2. When researching API calls, know whether you are on a member page or an interface
page. Interfaces, which you can think of as programmable objects, begin with the
letter “I”. These interfaces always have the word “Interface” after their name.
Members, on the other hand, always have the word “Method” or “Property” after their
names, followed by the owner interface in parentheses.
3. Occasionally, you will see methods and properties that have the letter “I” as a prefix.
These methods are for use with unmanaged C++ code and you should ignore these
methods in every other context.
4. At the bottom of most member pages is a sentence that states when the member was
added to the SOLIDWORKS API. If there is no availability section, then that means
the member was added before the year 2000. The following example shows that the
member was added in version 23.0, which corresponds to SOLIDWORKS 2015 SP0.
13
5. When using VBA, be aware that the VBA syntax does not appear after the
parameters, unlike the .NET syntax, which appears before the parameters. The
topmost syntax is for [Link], not VBA. Because there are slight differences
between the data types in VBA and [Link], using the incorrect guide can confuse
novice programmers.
6. Many parameters and arguments in the SOLIDWORKS API are useful to return data
and not receive data. These are effectively additional return values in an API call.
You can tell that a parameter returns values to you because the [Link] and VBA
syntax uses the “ByRef” keyword before the parameter. The C# and C++ languages
use the “out” keyword before the parameter as shown in the following examples.
7. It is not necessary to use the latest version of an API if one exists. Even though the
SOLIDWORKS API might indicate that earlier versions are “obsolete”, this does not
mean that they will not work. It is sometimes useful to use obsolete versions if the
newer versions contain arguments that are irrelevant to your software’s needs. On rare
occasion, a SOLIDWORKS API call or interface is actually deprecated, that is, it no
longer works in newer versions of the SOLIDWORKS software. If this is the case,
then the API Help makes it obvious. For example, see IBomTable.
14
7) The SOLIDWORKS API Object Model
The API Object Model, also known as the SOLIDWORKS API Object Hierarchy, describes
the relationship between interfaces in the SOLIDWORKS API. Without an understanding of
the API Object Model, programming with the API is a mystery, and using the API to write
many programs will generally be a slow and frustrating experience.
For example, imagine that you want to select the largest face in a part programmatically.
How would you even begin writing a macro like this from scratch? One suggestion is as
follows:
1. In the API Help, find the API call that you are trying to reach. In this case,
[Link].
3. Your program needs to use the correct accessor to get to IFace2. The list of accessors
for IFace2 is very large and the API calls appear in the format [interface]::[member
name]. Based on how your program works, most of these accessors are not relevant.
Because you want to get the largest face in a part, and because a part consists of
bodies, it makes sense that [Link] is the accessor you need. Click into this
API call.
4. Now that you are in the API Help page for [Link], you start the process
over again of finding the appropriate accessor for IBody2, which is
IPartDoc.GetBodies2. There is no accessor for IPartDoc. Instead, you cast the
IModelDoc2 pointer to IPartDoc, which means that you need to find the correct
accessor for IModelDoc2.
15
8) General SOLIDWORKS API Usage Advice
a) Version Interoperability
Unlike SOLIDWORKS models, SOLIDWORKS API calls are forward and backward
compatible as long as they exist in the APIs of the target version. It is rare that a program
“breaks” for this reason, because most commonly used API calls have been available in the
API for decades. If you do run into a situation where an API call is not available in your
target version, there may be an obsolete version of the call available. If no obsolete version
exists, then it is likely that another workaround is possible through a variety of other API
calls.
When using VBA, it is standard to use the Hungarian notation naming convention, in which
a prefix identifying the variable’s data type begins the variable name. For SOLIDWORKS
variables, a recommendation is to use the “sw” prefix, which is standard across the
SOLIDWORKS API Help. .NET does not use the Hungarian notation naming convention
except in form control variables. Regardless of what notation you choose, what is most
important is that you remain consistent throughout your project.
When you declare a SOLIDWORKS object variable, you should declare it using its specific
interface and not simply as Object, which is the default declaration when you open a new
macro or when you use the macro recorder. For example, a new macro uses the following:
Because this variable is actually a declaration for ISldWorks, the declaration should be:
By declaring the variable as its specific object type, Visual Studio IntelliSense is available in
the Integrated Development Environment (IDE). This can greatly increase your efficiency
while developing.
16
d) Optional Arguments
There are no optional arguments in the SOLIDWORKS API. However, you can effectively
“ignore” an argument by simply passing in its default value.
VBA default values are Nothing for objects and Empty for non-objects.
Although the default value for a data type might correspond to 0 (zero) or a zero-length
string, consider using the actual words Empty, Nothing, or null to clarify that you
intentionally “ignored” that argument.
e) Common Pitfalls
Assuming feature and entity names. For example, assuming that the XZ plane has
the name “Top" or contains the word "Top". If the plane was renamed, or if the
localization is not set as English, the code fails because it cannot find the XZ plane.
Using [Link] to get a model’s name. This API call only returns the
file extension if the Show file extensions for known file types option is active in the
Windows® folder settings. Parsing the file name from the string returned by
[Link] is much safer.
Traversing feature trees without considering order. Sometimes it is desirable to
traverse a feature tree in the order of feature creation. In this case, you can use
[Link] along with [Link]. If you need to return
the feature tree in the exact order that it appears, you can use the ITreeControlItem
interface.
Using IModelDocExtension.SelectByID2 to make selections in the display area.
This API call is notoriously unreliable for selecting items in the display area,
particularly entities such as faces. While the call does select items in the feature tree if
the feature names are known, relying on the XYZ coordinates alone can result in
wrong selections.
Adding sketch entities to a sketch without turning off snapping. Many parts of the
API mimic manual usage of SOLIDWORKS. An example of this is adding sketch
entities. When you create a point using the API, the point snaps to the nearest
reference point. This can result in inaccurate results if the model is not zoomed in
enough. The solution is to use [Link] to add sketch entities
directly to the SOLIDWORKS sketch database.
17
Inserting components using IAssemblyDoc.AddComponent5. There are two
important caveats to this method that you will miss without carefully reading the
remarks. First, the component you are adding must already be open. Second, the XYZ
location specified is where the component’s bounding box center is placed, not its
origin.
Misunderstanding or neglecting transforms. Transforms are necessary when
converting points and vectors from sketch space to part space, component space to
assembly space, drawing view space to drawing space, or the opposite of any of these.
This topic is complex and requires a solid understanding of vector algebra. Studying
API Help examples is a good place to start, though online learning resources are
available. In particular, know that IComponent2.Transform2 returns the transform of
the component relative to the top-level assembly and not the component’s immediate
parent.
Misunderstanding casting and interface inheritance. While the SOLIDWORKS
API does not support object inheritance, it does support interface inheritance, which
behaves in a similar way. Practically, this means that you can cast a higher-level
interface variable to a lower-level interface variable, and vice versa. Here is the
official list of all interface inheritance in the SOLIDWORKS API. Without using
interface inheritance, you face many insurmountable obstacles. Therefore, it is crucial
that you keep this list handy.
f) Troubleshooting API Calls
If an API call does not behave the way you expect, several options are available to help you
troubleshoot the problem:
1. Know what the API call actually does. Sometimes the names of API calls are vague
or do not reflect exactly what the API does, therefore it is essential to closely read the
description to make sure that your expectation of the call’s behavior matches the
actual behavior.
2. Look at examples. Search the SOLIDWORKS API Help, Google, or websites that
specialize in SOLIDWORKS API for examples of an API call in use in a working
program.
3. Try writing a simpler macro. Trying to understand why an API call does not work
is much easier in the context of a simple macro that demonstrates only the usage of
that API call and nothing more. This technique of isolating the problem at hand is
common in all forms of debugging.
4. Review the remarks in the SOLIDWORKS API Help. The remarks section
contains many helpful bits of information, including exceptions to the normal
behavior of the API call.
18
5. Look in the SOLIDWORKS API forums. It is unlikely that you are experiencing a
problem that no one has ever seen before. Quite often, there is already an answer to
the question in the API section of the official SOLIDWORKS API forum.
6. Search the Knowledge Base. The official SOLIDWORKS Knowledge Base, which
you can access from the customer portal, includes bug reports (SPRs) for all parts of
the SOLIDWORKS software, including the API. The API call that you are using
might be misbehaving because of an actual bug. If SOLIDWORKS API Technical
Support is already aware of the bug, then you can find information about the issue in
the Knowledge Base.
7. Email SOLIDWORKS API Technical Support. If you have exhausted all other
options, you might be experiencing an unreported bug that you should report to API
Technical Support. At the very least, they will try to solve your problem and update
the documentation as necessary. You can send an email message to
apisupport@[Link].
19
9) General Best Practices for .NET Development
a) Installers
Although many installer options are available for the .NET software, a very useful utility is
the Installer Projects extension that you can download as a free plugin for Visual Studio.
Make sure that the version you download works with your version of Visual Studio. When
you use this plugin to create a Microsoft Installation (MSI) package for an add-in:
In the add-in DLL properties, be sure to define the Register field as vsdraCOM.
Otherwise, the add-in does not register with COM on the user’s machine.
The installer package does not use [Link] to register the DLL with COM.
Therefore, it is necessary to use the Windows Registry Editor in the installer project
to specify what keys you need to create in HKEY_LOCAL_MACHINE.
A downside of using this extension is that it is not possible to link the File Version field in
the project’s Assembly Information to the Version field in the setup project’s properties.
This means that you need to increment the version in both places and ensure that their
versions match. Otherwise, the installation could fail. When you increment the installer
project version, you receive a prompt to change the installer’s GUID, which you should
accept.
Lastly, a recommendation is that you install programs in C:\Program Files rather than in the
user’s AppData folder. The former requires administrative rights because this is the intended
Windows location for program installations. The AppData folder does not require such rights
because this folder is the intended Windows location for files that programs create and
modify. While Windows allows program installations in the AppData folder, this effectively
circumvents the settings established by the systems administrator. Users may also have a hard
time finding the installation folder for programs in the AppData folder because they expect to
find the programs under Program Files.
b) Versioning
Every change to the code produces a new binary or binaries, which should be assigned a new
version. This way, every deliverable to your users will have its own version and there is no
confusion on the part of the user or the developer regarding the installed version. This is
particularly important because users may fail to update their software properly despite
thinking that the update was successful. If this happens, users might report the same bug that
you thought you had already fixed, and you will then put in extra effort investigating an issue
that you actually already resolved.
You can change the file version for a .NET binary in Project > Properties > Assembly >
Assembly Information. This dialog box provides four values that you can change. A best
20
practice is to use the first three values with this scheme: [Link]. Some
developers do not use the last value, which is the Build number. If you use the Build number,
you can set it up to auto-increment with every new build. If you use the shorter versioning
scheme, consider treating each number as follows:
Major: Increment this number when you add new features that break compatibility
with previous versions. For example, configuration files that can load into earlier
versions of the software that cannot load into the new version.
Minor: Increment this number when you add new features that do not break
compatibility with previous versions.
Patch: Increment this number when you fix bugs or make insignificant
improvements, such as changing text on a form or adding comments.
c) Assembly Information
As mentioned in the Versioning section, you can use the Assembly Information dialog box in
the project settings to specify the file version. Consider also using this dialog box to specify
the program name, description, and developer (under Company). Any time you need to use
these values in your program, you can access them using the .NET FileVersionInfo class.
Examples of when you might need these values include:
To use the SOLIDWORKS API, PropertyManager pages, ISwAddin, and other resources, a
class library project requires references to the SOLIDWORKS Primary Interop Assemblies
(PIAs).You can find these PIAs, which are simply DLLs, in the api\redist folder of the
SOLIDWORKS installation folder. Instead of referencing the files from this location directly,
you should copy them into a third-party folder that you create in your project, and reference
the files from there. This way, if you create a ZIP archive of your project and send it to
someone else, or if you reinstall SOLIDWORKS in a new directory, the references will not
become broken.
e) Source Control
Source control is a deep topic but worth discussing briefly in this document. In short: any
serious .NET developer should use source control. The two most common source control
systems, also known as version control systems, are Git and Mercurial. Source control
systems provide developers with many of the same advantages that Product Data
21
Management (PDM) provides for CAD users: better organization, collaboration, and security.
In this context, “security” not only refers to the ability to assign repository permissions to
users (much like the assignment of vault permissions in PDM), but also security from errors.
If you make significant modifications to a program and then realize that you must scrap the
modifications, you can easily revert to an earlier version of the software.
An example organization uses Git for the source control system, Sourcetree for the Git
graphical user interface (GUI), and BitBucket for online repositories and collaboration.
GitHub offers similar options that should work equally well for SOLIDWORKS API
developers. If you are in an industry that requires certain security compliance, you might
need to set up a remote server that hosts your organization’s repositories.
After referencing the SOLIDWORKS PIAs in your project, you can specify that Visual
Studio embed the used portions of the PIAs into your binary by setting the Embed Interop
Types property to True as shown in the following image. This has a number of benefits:
It can cause cast exceptions involving API calls that pass an array of structures. This
is true in the SOLIDWORKS PDM API. It might also apply to the SOLIDWORKS
API.
It can cause other cast exceptions and prevent the building of certain libraries,
although there are no known examples that are easy to reproduce.
You cannot edit add-ins while debugging them. Because there is a limited number of
kinds of code that you can edit during debugging in the first place, this downside is
negligible if you never edit add-ins during debug mode. For more information, see the
Debugging Add-ins section.
22
The safest course of action is to define the Embed Interop Types option as False. However,
if you are confident that you can identify when this property is causing problems and want to
reap the benefits until then, you can set the option to True. A strong recommendation is for
novice SOLIDWORKS API developers to define the option as False.
The program runs successfully. If it is not obvious to the user, then the user should
receive notification that the program has finished running, without errors.
The program runs successfully, but with warnings. A warning occurs when
processing is successful but the output might not be desirable. As a simple example, a
custom property used in processing might be missing from a model. This property is
not critical to the completion of the processing, but the user should be aware that it
was missing.
The program fails to run. This can occur for at least two reasons.
o A bug in the program produces an unhandled exception. In this case, the user
should receive notification of the failure and receive advice to provide the log
file and any associated files that the developer might need for debugging.
23
o The user-provided input is not sufficient for allowing the program to run. With
reference to the previous example, perhaps the user wants processing to stop
immediately if the program finds a model without custom properties.
h) Logging
Add-ins and stand-alone applications that contain lengthy processing operations should
contain logging capabilities. This helps the developer quickly reproduce and fix bugs. Best
practices include:
The log file is primarily for the developer, not for the end user. For example, when a
program throws and exception in a program you write, the user receives a message
(usually as a message box) that says, “Unhandled exception occurred. Please send the
log file and models to technical support.”
Your log file should contain the three types of information discussed in the last
section: information, warnings, and errors. It should be obvious in the log file which
line corresponds to which type of information.
o Information: A general term for any information that is not a warning or
error.
o Warning: Something is amiss, but the program continues to run.
o Error: The program cannot continue for this reason.
To avoid permissions issues, tour program should place the log files in the user’s
AppData folder, not in the installation folder. Likewise, the program should be
installed in the Program Files folder, not in AppData.
Your program should allow users to access the log file folder easily, or at least an
easy way to package the log files to send to the developer. It is helpful to include a
function somewhere in the main form or in a settings form that says Open Log
Folder.
Use a professionally written logging class. Use this class to create and then close a
new text stream every time there is a modification to the log file. Otherwise, if your
program crashes, the text stream never closes properly, which can result in write
errors. Many excellent loggers such as NLog, log4net, and Serilog are available free
from the NuGet Gallery website.
Name each log file after the date and time. That way, the file name is always unique
and you never inadvertently rewrite to an existing log file on the next processing
attempt. For example: “log 08-15-19 18_48_46.txt”
Regardless of what logger you use, your log files should contain the following
information:
o The time the program runs and, optionally, the time of every single log entry.
o The program name and version. Use this information to determine if the user
is running the correct version of your software.
24
o User inputs. This includes the fields of every single user control and the values
of any configuration value in use.
o Optionally, the SOLIDWORKS version. Sometimes it is not feasible to obtain
this value using [Link]. However, this is a
recommendation if you have access to the ISldWorks pointer when logging
begins.
o The sequence of every notable operation that occurs during processing. For
example, if your program batch processes all drawings in a folder by changing
outdated title block information, your log file should make it clear what file is
processing at any given point and what the last major operation occurred
before the failure. Use indentation and extra lines to make text readable.
Here is an example log file from an add-in called Acme Tools:
If user inputs must persist in the UI, it is a best practice to use the Windows Application
Settings feature, which allows users to input specifications in the project settings for an add-
in or stand-alone application. When using the Application Settings feature, Windows stores
25
the user settings in the user’s AppData folder. Otherwise, it is necessary to create a custom
settings storage and retrieval class to handle the same tasks effectively. If for some reason
you do create your own custom class, then you should store the settings in the user’s
AppData folder and not in the registry or the Program Files folder, because the latter
locations might require administrative rights that could prevent your class from functioning
properly.
Have every program provide the end user with the following information, typically in the
form of an About box:
XML comments allow the developer to create custom IntelliSense text that appears in Visual
Studio. This document does not cover how to use the comments, however there is no reason
not to use them if you are developing a framework or library for frequent reuse in other
programs. Furthermore, use of third-party tools like Sandcastle make it possible to create a
Help file from the XML comments in a project.
26
10) Add-in Development Best Practices
Using the SOLIDWORKS API SDK versus writing an add-in from scratch
The SOLIDWORKS API SDK is a sample add-in in the form of a template that demonstrates
registration, event handling, and user interfaces. Typically when using the SDK as the basis
of an add-in, the developer first pares down the SDK code to use only the code that is
necessary for the add-in. While this is a satisfactory place to start for someone with little add-
in development experience, more experienced developers can create their add-in from scratch
or start with a template that contains the minimum of what they need. This results in cleaner
code, and promotes a deeper understanding of the inner workings of add-ins. Instead of using
the SDK as a starting point for your add-in, consider using the SDK only for reference and
learning purposes.
The ISwAdd-in interface provides a method called ConnectToSW that passes the pointer to
ISldWorks into the add-in so that you can use the SOLIDWORKS API. The recommendation
is that you assign this reference to a variable with public or internal / friend access so that the
entire project can use it. Because the pointer value never changes as long as the add-in is
running, this type of “global” access is perfectly safe and removes the need for the developer
to pass the pointer around the add-in via arguments.
b) COM Visibility
Only make a class COM-visible if it actually needs to be COM visible. You can do this by
adding the <ComVisible> tag to the class name. Do not activate the Make assembly COM-
visible option in Project > Properties > Application > Assembly Information. This makes
all classes in your add-in COM-visible, which is unnecessary. In a typical add-in, the only
classes that need to be COM-visible are those that implement ISwAddin and
IPropertyManagerPage2Handler8 (when using a PropertyManager page). The following
image shows an example of this tag, used in the entry class of an add-in.
c) Add-in Registration
SOLIDWORKS add-ins require registering the DLL in two places in the registry:
27
HKEY_LOCAL_MACHINE\Software\SolidWorks\AddIns – This is where
the add-in registers with SOLIDWORKS. When SOLIDWORKS runs, it correlates
the GUID found here with the GUID found in the COM-registration location. That
way, SOLIDWORKS knows the location of your DLL.
Typically, a developer registers an add-in during development using the [Link] tool that
comes with the .NET framework. The purpose of this tool is to register DLLs written in .NET
with COM. Although [Link] only registers the DLL with COM, it can also initiate the
registration and unregistration of the DLL with SOLIDWORKS. This is true as long as you
use the <ComRegisterFunction> and <ComUnregisterFunction> tags with functions that
programmatically create and remove the registry gets in HKEY_LOCAL_MACHINE. Because
there is no downside to using this approach, the recommendation is that every developer
include such functions in their add-in because it greatly speeds up development. For
examples, see the SOLIDWORKS SDK.
Because it is tedious to run [Link] from a command prompt, developers typically run
the tool it one of two ways:
Using the “Register for COM interop” option. Taking after the SOLIDWORKS
API SDK, the Register for COM interop option is activated in Project > Properties
> Build > Output. Registration occurs when the project builds. Unregistration occurs
when the project is cleaned. If Target CPU = AnyCPU then additional post-build
event code is required to ensure use of the 64-bit version of [Link].
Using batch (BAT) files. In this approach, the developer creates two BAT files, one
for registration and the other for unregistration. These BAT files run [Link]
directly with the appropriate flags. For example, if the DLL has the name
[Link], then you can place the aforementioned BAT files in the add-in’s
project folder with this code:
C:\Windows\[Link]\Framework64\v4.0.30319\[Link]
/codebase "%~dp0\bin\Debug\[Link]"
pause
The superiority of one method over the other is debatable. This author favors the second
approach. The main reason is that using BAT files permits registration and unregistration of
an add-in without opening Visual Studio. This allows consideration of separation of concerns
with respect to registration. That is, using Visual Studio to work with code, and using the
BAT files to handle registration. Moreover, there are at least two downsides to the first
approach. First, use of the Register for Com interop option requires that you create a post-
build event in every project to ensure proper registration. This is rather tedious. Second, that
option requires building or cleaning the code to register or unregister the DLL respectively.
This might not be desirable.
28
d) Tools Suite Add-ins
If you have numerous programs that the users at your company need to access, the
recommendation is to create a single “tools suite” add-in that contains all of these programs.
This allows for a single installation and easier administration, rather than numerous add-ins.
This is especially useful for companies that use numerous macros use and wish to bundle
them into a single package. Users typically access these programs from a drop-down list or
via command button. The drop-down list of four tools created for a company called “Acme”
might look like this:
Tools
o Acme Tools
Assembly Creator
Assembly Analyzer
Drawing Creator
BOM Exporter
A recommendation is that you create each of these programs as its own project inside the
solution, with one of the projects being the actual add-in that references the other projects.
That solution structure looks like this:
e) Debugging Add-ins
It is not as easy to debug running add-ins as it is to debug VBA macros. If the Embed
Interop Types property is set as False, it is possible to make some changes unrelated to
declarations, which can then run without restarting the add-in. For more complex code
adjustments, it is necessary to stop debugging SOLIDWORKS, modify the code, and then
restart SOLIDWORKS. For certain test procedures, this is a very time-consuming process.
To speed up testing, one option is to create a stand-alone application that allows the
developer to test the add-in code without actually loading the add-in into SOLIDWORKS.
This “tester” stand-alone application has the following requirements:
29
1. The tester needs to receive the correct inputs because the add-in UI is not available for
use. You can often handle this by creating a simple Windows user form that mimics
the core functionality of the add-in UI.
2. The tester must connect to the active SOLIDWORKS session, in which the add-in is
not loaded.
3. The tester must reference the add-in project or DLL, which has the appropriate classes
and methods exposed as public.
After setting up this, you should be able to keep SOLIDWORKS and any associated models
for testing open while you debug the add-in code.
f) Updating Add-ins
For any organization that relies heavily on a custom add-in, it is important to know how to
update add-ins with minimal administrative effort. Remember that an add-in should be
installed locally because local registration is always required. It might be possible to store the
add-in binaries on a network drive (as can be done with a VBA macro), which are replaceable
as necessary. However, this is fruitless if it is not possible to register the DLL in that location.
Therefore, assuming a local installation with the master version of the binaries stores on the
server, here is a simple recommended workflow:
1. Have users start SOLIDWORKS from a custom launcher that always copies the
binaries stored on the server over to the local machine (if the versions are different)
before running the SOLIDWORKS executable file. This is a simple solution but fails
entirely if the user does not use the aforementioned custom launcher.
2. To mitigate the problem of a user forgetting to use the launcher, the add-in can still
run a version when loads. This means that it checks the current version against the
server version. If the versions differ, the user receives notification that they should
close SOLIDWORKS and then restart the application by using the custom
SOLIDWORKS launcher. If you include this step, the developer can allow the user to
store the server path to the binaries in an external settings file rather than by hard
coding the path in the program.
30
g) Architecting Add-ins
While add-ins come in many shapes and sizes, a generic and common form of add-in follows
this workflow:
1. The user opens the add-in UI. Usually this occurs from a drop-down list, command
button, task pane, or by hooking into an existing SOLIDWORKS command.
2. The user enters information and clicks a “Process” button (or something similar).
For an add-in such as this, a recommendation is to have the following classes, although the
exact number and names are not critical. For example, it is possible that the UI and processor
will have several classes each.
Main – This is the COM-visible class that should implement ISwAddin, expose a
pointer to ISldWorks to the rest of the project, handle registration, and contain the UI
callbacks.
UserInterface – This class builds the UI and contains code that relates to handling the
UI.
Inputs – This class contains the user inputs and passes from the UserInterface into the
Processor so that processing occurs according to the user’s specifications.
Processor – The class that contains or initiates the code that executes the main tasks
of the add-in. This is where most SOLIDWORKS API calls are made.
Logger – The class that handles logging.
If you are not sure if the final form of your program should be a stand-alone application or an
add-in, consider creating an add-in with public access given to the methods that receive
inputs and begin program execution. This creates a public API that you can use from a stand-
alone application. This does not require the add-in to be running, and you should use
[Link] to increase performance. If you want a stand-alone
application to control a running add-in, then you need to use [Link]. In
testing, controlling the add-in directly does not improve performance; therefore, the author
does not recommend this approach over a public API.
31
11) Stand-Alone Development Best Practices
In an add-in, there is only one-way to get access to ISldWorks, and that is through the
ThisApp parameter passed by ConnectToSolidWorks(). However, in stand-alone
applications, the developer has several options, two of which include:
In professional experience, SOLIDWORKS crashes during the running of an add-in not due
to instability in SOLIDWORKS itself, but because you can push the limits of software after
the creation of hundreds of thousands of COM objects (Runtime Callable Wrappers). While
COM objects can be released after their use of [Link], sometimes this is
not a good option for architectural reasons. Regardless of why SOLIDWORKS might crash,
you can determine if a crash occurred by looking at the exception message when an exception
occurs. If the COM server (SOLIDWORKS) is no longer available, then you can get
exceptions that contain the following strings:
32
c) Calling An Add-in From a Stand-Alone Application
As mentioned in Architecting Add-ins, you can call a running add-in from a stand-alone
application by using [Link]. However, there may be no performance
benefit over creating the add-in DLL with a public API and using
[Link]. Therefore, it is not a recommendation to use
[Link] unless the add-in DLL does not grant the public access you need.
33
12) Add-in User Interfaces
This section distinguishes between the types of GUI that are available to the SOLIDWORKS
developer, and the different means by which these you can launch these interfaces.
a) User Interfaces
Windows Forms. This is the simplest option, but it has the least integrated look.
PropertyManager pages. Also known as “PMPs”, this is a classic option when you
want the user to experience a native SOLIDWORKS look and feel while using your
add-in. For more information, see “IPropertyManagerPage2”.
FeatureManager page. This creates a custom FeatureManager tab by using
IModelViewManager.CreateFeatureMgrWindowFromHandlex64. The main
advantage of this approach over IPropertyManagerPageWindowFromHandle (which
is a type of PMP control) is that you can create multiple tabs simultaneously, whereas
you cannot create multiple PMPs simultaneously.
Task Panes. Another common option that is useful when you want to integrate with a
system or server outside of SOLIDWORKS.
None. An add-in does not require a GUI. Consider creating a GUI only if the add-in
requires user input or user verification of certain parameters before running.
b) Launching User Interfaces
Event notifications. This option is necessary not only when you want to extend the
functionality of SOLIDWORKS (such as reminding a user to deactivate a license
before closing SOLIDWORKS) but also to override existing functionality. An
example of the latter is overriding the normal Edit Materials dialog box with a
custom material picker.
Drop-down lists.
o Use [Link] and [Link].
o This list the add-in under the Tools menu.
o Developers can specify in which document types the list appears.
o Developers can specify an icon for each command.
o End users can create keyboard shortcuts for each command.
o It is much easier to code than CommandManager tabs. The recommendation is
to use drop-down lists instead of CommandManager tabs if the end user has
no preference.
34
Toolbars.
o This lists the add-in under the Tools menu by using [Link]
and [Link]. Because CommandManager tabs have
largely superseded toolbars, this rarely used. For more information, see the
API Help.
Context menu items.
o You can add menu and sub-menu items to specific context and shortcut menus
by using ISldWorks.AddMenuPopupItem4. For more information, see the API
Help.
CommandManager tabs.
o You can use ICommandManager to create drop-down lists, toolbars, and
CommandManager tabs. Because this interface can be tedious to use, consider
using [Link] or AddMenuItemX if you only need to create a
drop-down list.
Task Pane button.
o Used to launch a task pane UI.
35
13) Stand-Alone User Interfaces
Because the entire purpose of a stand-alone application is to avoid integrating with
SOLIDWORKS, it is a recommendation that developers only use Windows Forms, Windows
Presentation Foundation (WPF) controls, or a console as the interface. As a best practice, use
a console application when there is no requirement for a graphical interface. With console
applications, the entry function can receive parameters sent through from a command prompt,
thereby allowing other programs or CAD admins to hook it up with their existing workflow.
36