About return values in the SOLIDWORKS API (part 6)

The return values of methods/functions in SOLIDWORKS API can be strings, objects and arrays.

This can be confusing for programmers that are just starting out. Or even for experienced devs.

In this blog post, I’ll explain every possible return value in the API.

In this blog post, you’ll find

  1. Methods vs functions
  2. No return value: void
  3. Value types: booleans, strings, doubles and integers
    1. Integers vs longs
    2. Integers vs enums
    3. Very few APIs use enums directly
    4. A string with separators
    5. Wrap your primitives, please
  4. Objects
  5. SOLIDWORKS API methods returning null
  6. Value arrays
    1. Value array being null instead of an empty list
    2. Simple double arrays
    3. Complex double arrays
    4. Value type array inside an object
  7. Object arrays
    1. Object array being null instead of an empty list
  8. Variants in VBA
    1. A variant is not an array
    2. Subs and functions
    3. Converting a variant to an array
  9. Using Out parameters to create multiple return values
    1. 9.1 Ref vs out parameters
  10. All blog posts in this series

1. Methods vs functions

Methods and functions are often used interchangeably. In C#, they have different meanings, so I will use the term methods in this post. SOLIDWORKS does the same in their API documentation.

You call a method to change a property of an object. Many methods will return something, but not all of them do.

2. No return value: void

If you call for example ISldWorks.CloseDoc, it will not return anything. In C# we call this void, but it has no special name in VBA.

That also means you don’t know if that method ran successfully. Did it close the document as you requested? It’s up to you to figure that out, or you have to trust SOLIDWORKS that it all worked as expected.

3. Value types: booleans, strings, doubles and integers

Methods that return simple value types are the easiest to work with. But they can mean different things. A string can be a name, a filepath or a selection string. So read the docs.

A boolean true will usually mean that the method ran successfully, although it sometimes means the opposite (read the docs). To avoid confusion, I prefer returning an enum value “Success” or “Failed” instead of returning a boolean.

3.1. Integers vs longs

Most programming languages have both integers and longs. An integer is used for smaller numbers (small is relative, it goes from -2,147,483,648 to 2,147,483,647 in C# and VBA and it uses 32 bits). If you need larger whole numbers, you use a long with 64 bits.

95% of all SOLIDWORKS APIs that return whole numbers will return integers. But there are a few annoying exceptions like the sketch segment ID. This caused me to write the following strange helper to get two longs for a sketch segment ID:

This method tries to convert two integers to longs. If that fails, SOLIDWORKS apparently gave us longs already. It also uses LINQ.

In VBA, you will get an error when the method returns a long and you try to put it into an integer.

3.2. Integers vs enums

The SOLIDWORKS API uses mostly integers for enum values. Since enums are integers underwater in C#, casting them is very easy but you need an explicit cast between brackets:

In VBA, casting between enums and integers is implicit:

See IPartDoc.GetBodies2 in the docs.

3.3. Very few APIs use enums directly

There are some APIs that use enums and not integers. I have only seen them in the Document Manager API so far, for example in the method ISwDMApplication.GetDocument.

3.4. A string with separators

When you call ISldWorks.GetUserPreferenceStringValue, it returns a single string that represents multiple directory paths. The paths are separated by a semicolon ( ; ), but the documentation fails to mention that.

3.5. Wrap your primitives, please

It’s good practice to add meaning to your primitives (aka strings, integers etc) to combat primitive obsession. Nick Chapsas also has a good video on the subject.

Does a string represent a path? Then create a FilePath object and convert the string to a path as soon as possible. Does a set of two integers represent a sketch segment ID? Then create a SketchSegmentID object to avoid creating methods that require two integer arguments.

Now, you can pass around this new object in your code. A method that expects a FilePath argument has more context than a method that expects a string.

4. Objects

The opposite of a value type is a reference type and the basis of all reference types is the object. Booleans, string and integers are value types and these things are passed around directly. Objects are not passed around, we only pass a reference (also known as a pointer) to that object.

Objects are generally more complex and have an internal state. The most-used objects are the SOLIDWORKS and ModelDoc2 objects. We can request (and sometimes edit) that state by checking its properties and we can change the state by calling methods. You cannot compare two objects directly, because if you do, you are usually only checking if the two pointers are the same.

The SOLIDWORKS API has 445 object types, so you can’t avoid them.

An example of a property returning an object is the SldWorks.ActiveDoc property, which returns a ModelDoc2 object or null if you have no files open.

5. SOLIDWORKS API methods returning null

The hardest thing when learning the SOLIDWORKS API is that many methods lazily return null when the input is not as expected. No error message, no help, no exception, just null. You’re on your own, dude.

To solve these issues, I usually:

  1. Read the documentation a few times. Complex methods often have a list of notes at the bottom.
  2. Record a macro of me performing the same steps manually. The recorder does not record all steps, though, so it’s no silver bullet.
  3. Pass the simplest possible input parameters to see if I can get the method to work. Then, I work my way up to more complex inputs.

6. Value arrays

SOLIDWORKS often chooses to return an array of values, for example an array of doubles to describe a position (even though we have IMathPoint for that also). When you call IDimension.GetValue3 and are only interested in a single configuration, you receive an array with one value.

Here’s an example where I convert a double array that represents a bounding box of a feature into a rectangle struct. A rectangle has more context than an ordinary array.

6.1. Value array being null instead of an empty list

A value array is still a type of object, so it can be null.

I strongly prefer getting an empty list back, but SOLIDWORKS will never do that. Instead, it returns null. That means you cannot directly iterate over the values with a foreach, you have to check for null first. Here I use such

Generally, methods that return a 2D or 3D point (so a fixed-length array) will not return null but an array of zeroes instead. If the method returns a variable-length array, it can return null.

6.2. Simple double arrays

An example of a method returning an array of doubles is IAnnotation.GetPosition. You can cast it to a double array directly:

It’s a bit more work in VBA because variants are annoying:

6.3. Complex double arrays

My favorite method to hate is IView.GetPolylines6. It has been deprecated, but I still use it because GetPolylines7 is slow.

This method takes returning an array to a whole new level. It returns a double array, but:

  1. The length of the array is variable.
  2. The doubles can represent booleans, integers, colors, font info and points. It’s awful.
  3. It may include a whole bunch of zeroes at the end, in multiples of 17.
  4. You have to go through the whole array and check certain values to know how to interpret the values coming after it.

I have written an interpreter to be able to use the return values from this method, which I am not giving away 😉 But you bet it includes a whole bunch of unit tests.

6.4. Value type array inside an object

Every now and then, a method has a strange return type. IModelDocExtension.GetPersistReference3 returns a single object, but that object contains an array of bytes of unknown length. A persistent ID is at least 16 bytes long, but it’s often 20 bytes or 50+ bytes.

To convert this object in C#, I use the following helper method:

7. Object arrays

You treat object arrays similar to reference type arrays, but you have to make sure you cast the whole return object to an object array first. Only after that can you cast each item to its specific type.

7.1. Object array being null instead of an empty list

Just as I talked about before, SOLIDWORKS will return null and never an empty array. That’s why you always check for null first. In C#, lists are easier to work with than arrays so I convert them as soon as possible.

As an example, to get all annotations in a view:

Here, I return an empty list if the annotations object is null. If not, I cast the whole object to an object array, then I cast each item in it to an Annotation using LINQ. The final step is converting the resulting enumerable to a list.

You can make it even shorter by using the null-coalescing operator:

8. Variants in VBA

8.1. A variant is not an array

A variant is anything that is not defined. It only exists in VBA, and I hate it. It is not the same as an array, which you will notice when you try to foreach through a variant. Every item in a variant is also a variant.

This function will compile and it works, but if you want to do more with the body objects, you better cast them to a Body2 object first.

With implicit casting:

With an explicit cast:

8.2. Subs and functions

Every function in VBA has a return value. If you don’t define one, it will be a variant. See the two examples below.

If you don’t need a return value, the official route is to create a Sub, not a function. That being said, I usually create a function anyway because any sub can be used as a starting point of a macro. I prefer to only have the Main sub to avoid confusion. Having multiple subs has caused problems in the past because #TASK just picks a random sub when it has to run a macro on multiple files.

return values of a sub and a function in VBA

8.3. Converting a variant to an array

Since I prefer working with arrays over variants, I convert them as soon as possible. For fixed-length arrays like 3D points, you can set the array length when you define it. For variable-length arrays, this is a little harder.

Here’s my solution for converting a variant into a real object array. If you have a better solution, please let me know because this feels overly complex.

9. Using Out parameters to create multiple return values

A method can return nothing or one item. If you really need to return multiple values, you could use out parameters. You initialize these values as zero or null, then pass them as arguments into a method. The method then sets these parameters to a useful value.

SOLIDWORKS does this a lot. An example is the ActivateDoc3 method, where the first three parameters are in parameters and the last one is an out parameter that holds the error status. If you call this method and it returns null as the active model, you can use the out parameter to find out what went wrong.

In VBA:

In C#:

Out parameters are generally frowned upon since methods have one return value for a reason. And because out parameters aren’t used often, developers will have a harder time understanding what your code does.

If you need multiple return values, it usually means your method does two things, not one. A preferred solution is to return a custom object with multiple properties.

9.1 Ref vs out parameters

Technically, the last example isn’t even an out parameter in C#, even though the documentation says so. It is a ref parameter, which means it may have a useful value before the method is called. If it really was an out parameter, you could have called the method like this, without having to initialize the parameter:

10. All blog posts in this series

  1. The SOLIDWORKS Object Model + API explained
  2. SOLIDWORKS API: the basics – SldWorks, ModelDoc2
  3. How to work with Features 
  4. Persistent ID and sketch segment ID and more
  5. All identifiers in the SOLIDWORKS API
  6. (this post) About return values
  7. Entities and GetCorresponding
  8. Selections, math and custom properties
  9. How to create task panes and Property Manager Pages
  10. How to create your own SOLIDWORKS add-in
  11. Creating add-ins with SolidDna: the basics

Don't miss the next post. Get a free add-in.

Subscribe to our newsletter and get our TimeSavers add-in for free.