This tutorial is about writing your own addin. There are other tutorials out there. This tutorial is not about doing it the most simple way. There are Visual Studio templates out there that will set up most stuff for you (https://ekinssolutions.com/nifty_addin_template/). In this tutorial, we will set up everything manually. I want to show you all the settings. That has the advantage that you are not limited to specific settings, Inventor/Visual Studio versions or programming language.

I wanted you to have a functional and useful addin at the end of the tutorial. Also, I want you to be able to change the functionality easily. However, I did not want to spend too much time explaining the functionalities and code of what the addin does. Therefore I have chosen to change my iLogic rule “One Rule to Search Them All” (http://www.hjalte.nl/22-one-rule-to-search-them-all) into an addin. If you want to know more about this function you can just read about it in the blog post. Here I will only focus on creating an addin. To be fair you probably should never turn an iLogic rule into an addin so you have a button. Autodesk made that possible as a default option for iLogic rules.

Then why should you create addins? Most of the time I create addins in the following cases:

  • The codebase for what I want is too big/complicated for an iLogic rule
  • You need to present a cool-looking window to the user. (At least looking better than the windows we can make with iLogic)
  • You need Inventor to react to events (other than the user pushing a button or the built-in events from iLogic).

In this tutorial, I show you how/where to write all your code. If you want to follow along but you get lost (or if you just want to look a the completed code.) Then you can find the entire project on my git hub page. (Download)

This isn’t a programming tutorial. So I expect that you have some programming experience. For example from creating iLogic rules.

Create a Visual Studio project

I assume that you have installed Visual Studio 2022. (Be aware that Visual Code is another programming IDE from Microsoft but you can't create addons with it.) This is not a tutorial on how to install Visual Studio. But some tips if you did not install it jet: you can download it here: https://visualstudio.microsoft.com/downloads/ Make sure you install everything to create .Net desktop applications. Also, include the .Net Core 8 runtimes.

Start Visual Studio (2022) and create a new project.

Make sure that you pick a project that targets the .Net core 8. Besides that, you have a couple of options.

First of all, you can select your language C# or VB.net. C# is the most commonly used .Net language. Therefore most information on the internet is about C#. That can be an advantage if you are looking for a solution to a programming problem. But if you have a problem with the inventor API then most answers/examples are written in VB.net (or VBA which is very similar) In this tutorial I will focus on VB.net because you can find more relevant information.

Your second choice is what kind of technologies you want to use in your forms. You have the following options: Winforms, WPF or none. Winform is the oldest technology but you will find a lot of information about it. (If you create/use custom controls in Winforms then you might run into trouble when you need your application to be 64bits. This is for example the case if you also start working with the vault API)  With WPF forms you can do more (it’s more flexible) but they are more complicated to create. If you don’t want to create any forms then you can create a “Class Library”. Which is the most simple to set up. In this tutorial, I create a class library with WPF technology.

Setup the project

Delete the file “Class1.vb. (That probably means deleting all files in your solution explorer.)

Go to the “Add Project Reference...” screen.

Browse and select the following files:
C:\Program Files\Autodesk\Inventor [VERSION]\Bin\Autodesk.Inventor.Interop.dll

The following iLogic dll’s are only needed if you are going to use the iLogic function.
C:\Program Files\Autodesk\Inventor [VERSION]\Bin\Autodesk.iLogic.Interfaces.dll
C:\Program Files\Autodesk\Inventor [VERSION]\Bin\Autodesk.iLogic.Runtime.dll

For the Autodesk.Inventor.Interop.dll reference you need to set the properties “Embed Interop Types” to "False", “Copy Local” to "True".

For almost all addins you need the package "System.Drawing.Common". (The only situation I can think of that you don't need it, is when you don't use any icons or forms in your addin...) Therefore select "Tools", "NuGet package manager" and "Manage NuGet packages for solution..."

Search for the package "System.Drawing.Common" and install it for the projects in your solution.

Set compile events

When your addin is compiled then in needs to be installed so Inventor can use it. Go to the “Project Properties”.

Most likely the following settings are set correctly but it’s good to double-check the following settings. 

Next, we need to make sure that the addin files are copied to the correct location. Addin files can go in a couple of places.

  • All Users, Version Independent
    • %ALLUSERSPROFILE%\Autodesk\Inventor Addins\
  • All Users, Version Dependent
    • %PROGRAMFILES%\Autodesk\Inventor 20xx\Bin\Addins\
      • I noticed that you need local admin rights on your computer to write to this folder. If you don't have those "rights" then Visual Studio will stop the building process when you try to debug your addin!
  • Per User, Version Dependent
    • %APPDATA%\Autodesk\Inventor 20xx\Addins\
  • Per User, Version Independent
    • %APPDATA%\Autodesk\ApplicationPlugins

You need to copy at least the *.addin file and your addin dll file to one of these locations. You can do that by adding the following lines to the "Post-build events".

XCopy "$(TargetPath)" "[TARGET LOCATION]\$(TargetName)\" /Y /R
XCopy "$(ProjectDir)[YOUR ADDIN NAME].addin" "[TARGET LOCATION]\$(TargetName)\" /Y /R

Make sure you change the information between the [square brackets].

Set compile events (alternative)

There is an alternative for setting the “Compile events”. You can also set the “Output path”. That has the advantage that all files are copied automatically. (Instead of adding a line in the compile events for each file you want to copy.) The disadvantage is that Visual Studio will always create an extra folder named "net8.0-windows". In the GUI there is no setting to disable that behaviour. But you can disable that behaviour by editing the project file directly.

Now add the following lines after the first PropertyGroup

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
	<OutputPath>[TARGET LOCATION]\[YOUR ADDIN NAME]\</OutputPath>
	<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
	<OutputPath>[TARGET LOCATION]\[YOUR ADDIN NAME]\</OutputPath>
	<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>

Make sure you change the information between the [square brackets].

Set Inventor as a startup program for debugging

Select "Debug" and then "[YOUR PROJECT] Debug Properties". (Or do some clicking)

Delete the existing profile.

After that, you will need to add a new “Executable debug profile”.

In this new profile, you can add the path to Inventor.

GUID

For the next files, you will need a GUID. This is an identification string used by Inventor. Multiple sites and tools can generate it for you. I usually use this site: https://www.guidgenerator.com/

Save the string for later use.

Addin file

For an addin you minimum need 2 files. The first one is the .addin file. With that file, you tell Inventor that you want it to load an addin. The information in that file are presented in the addin screen within Inventor.

Add a new file to the project. The name is not important as long the extension is “.addin”. Usually, you give it the same name as your addin. I will use “MyILogicAddin.addin”

Change the file properties of the addin file. It needs to be copied to the output path when the project is compiled.

Add the following (XML) code to the file:

<Addin Type="Standard">
	<ClassId>{[GUID here]}</ClassId>
	<ClientId>{[GUID here]}</ClientId>
	<DisplayName>[Name]</DisplayName>
	<Description>[Description]</Description>
	<Assembly>[File name of the dll]</Assembly>	
	<SupportedSoftwareVersionGreaterThan>29..</SupportedSoftwareVersionGreaterThan>
</Addin>

 The .addin file is a XML file. XML files are simple text files often used to save settings. All settings are saved in nested tags. A tag always has the form

<[TagName] [Properties]>[TagValue]</ [TagName]>

In the XML replace the text between the square brackets (also remove the square brackets). Most tags are self-explanatory but the following tags need a bit more attention.

In the “ClassId” and “ClientId” tags you need to put the GUID that we create earlier. Make sure that you remove the square brackets but leave the curly brackets.

In the “Assembly” tag put the file name of your addin dll. (You can find the name in your Visual Studio project settings. Don’t forget to add the extension “.dll”)

Here I left out a lot of tags that are not needed. For the full list have a look here: https://help.autodesk.com/view/INVNTOR/2025/ENU/?guid=GUID-52422162-1784-4E8F-B495-CDB7BE9987AB

Create the class StandardAddInServer

The second file each addin needs is the DLL (Dynamic-link library). This is the file with the compiled code. In this file, there should at least be 1 class, the "StandardAddInServer". This class is the entry point for Inventor. That means that when Inventor starts it reads your .addin file. Then it will load your dll and start looking for this class. When it has been found it will start calling functions in this class.

Add a Class to your project and call it “StandardAddInServer”

Add the following code to the file and change the GUID:

Imports System.Runtime.InteropServices
Imports Inventor

' Change the GUID here and use the same as in the addin file!
<GuidAttribute("[GUID here]"), ComVisible(True)>
Public Class StandardAddInServer
    Implements Inventor.ApplicationAddInServer

    Private _myButton As MyButton

    ''' <summary>
    '''     Invoked by Autodesk Inventor after creating the AddIn. 
    '''     AddIn should initialize within this call.
    ''' </summary>
    ''' <param name="AddInSiteObject">
    '''     Input argument that specifies the object, which provides 
    '''     access to the Autodesk Inventor Application object.
    ''' </param>
    ''' <param name="FirstTime">
    '''     The FirstTime flag, if True, indicates to the Addin that this is the 
    '''     first time it is being loaded and to take some specific action.
    ''' </param>
    Public Sub Activate(AddInSiteObject As ApplicationAddInSite, FirstTime As Boolean) Implements ApplicationAddInServer.Activate
        Try

            ' initialize the rule class
            _myButton = New MyButton(AddInSiteObject.Application)

        Catch ex As Exception

            ' Show a message if any thing goes wrong.
            MessageBox.Show(ex.Message)

        End Try
    End Sub

    ''' <summary>
    '''     Invoked by Autodesk Inventor to shut down the AddIn. 
    '''     AddIn should complete shutdown within this call.
    ''' </summary>
    Public Sub Deactivate() Implements ApplicationAddInServer.Deactivate

    End Sub

    ''' <summary>
    '''     Invoked by Autodesk Inventor in response to user requesting the execution 
    '''     of an AddIn-supplied command. AddIn must perform the command within this call.
    ''' </summary>
    Public Sub ExecuteCommand(CommandID As Integer) Implements ApplicationAddInServer.ExecuteCommand

    End Sub

    ''' <summary>
    '''     Gets the IUnknown of the object implemented inside the AddIn that supports AddIn-specific API.
    ''' </summary>
    Public ReadOnly Property Automation As Object Implements ApplicationAddInServer.Automation
        Get
            Throw New NotImplementedException()
        End Get
    End Property
End Class

You see 4 functions/subs here (Activate(…), Deactivate(), ExecuteCommand(…), Automation()). We will only be using the “Activate” function. The others need to be there but don’t need to do anything.

In the “Activate” function we initialize the button class. Also, notice the try/catch block. By default, Inventor will not warn you if anything goes wrong while loading your addin. Therefore the try/catch block is needed to catch any exceptions that your code might throw and handle the exception. Here I just show the user a message box with the most basic information from the exception. (In production code, you might consider writing all the exception info to a log.) This will help you when something goes wrong and you need to find the problem. (And yes there will always be something wrong and then you need all the information that you can get!)

Button class

The button class creates a button in Inventor. Here we also write the code that is executed when the button is clicked. I called the class “MyButton” but you are free to call it anything. Just make sure you use the same name in the function “StandardAddInServer.Activate(…)”

Create a class “MyButton” and add the following code:

Imports Inventor
Public Class MyButton
    Private _inventor As Inventor.Application
    Private _settingsButton As ButtonDefinition
    Public Sub New(inventor As Inventor.Application)
        _inventor = inventor

        SetupButtonDefinition()
        AddButtonDefinitionToRibbon()
    End Sub

    Private Sub SetupButtonDefinition()

        Dim conDefs As ControlDefinitions = _inventor.CommandManager.ControlDefinitions
        _settingsButton = conDefs.AddButtonDefinition(
            "MyButton DisplayName",
            "MyButton InternalName",
            CommandTypesEnum.kEditMaskCmdType,
            Guid.NewGuid().ToString(),
            "MyButton DescriptionText",
            "MyButton ToolTipText")
        AddHandler _settingsButton.OnExecute, AddressOf MyButton_OnExecute

    End Sub

    Private Sub AddButtonDefinitionToRibbon()

        Dim ribbon As Ribbon = _inventor.UserInterfaceManager.Ribbons.Item("Assembly")
        Dim ribbonTab As RibbonTab = ribbon.RibbonTabs.Item("id_TabManage")
        Dim ribbonPanel As RibbonPanel = ribbonTab.RibbonPanels.Item("iLogic.RibbonPanel")
        ribbonPanel.CommandControls.AddButton(_settingsButton)

    End Sub

    Private Sub MyButton_OnExecute(Context As NameValueMap)

        Try

            Dim rule As New ThisRule()
            rule.ThisApplication = _inventor
            rule.Main()

        Catch ex As Exception

            MsgBox("Something went wrong while runing rule. Message: " & ex.Message)

        End Try
    End Sub
End Class

When the button class is initialized the function “new” is called automatically. Here we call 2 other functions. You probably noticed that those functions are very short. They are so short that I could have added them to the “new” function. One of the problems of creating large programs is reading the code later again. Creating small functions with good descriptive names makes understanding the code later much easier. Also, it increases the chance that you can reuse the same code again for other purposes.

In the “SetupButtonDefinition” function you can change “DisplayName”, “InternalName”, “DescriptionText” and “ToolTipText” of the button that we are creating. There we also define which function should get called “MyButton_OnExecute”.

In the “AddButtonDefinitionToRibbon” we define where the button needs to go. We start by selecting the “Ribbon”. I have chosen the “Part” ribbon but you can choose 1 of the following options: ZeroDoc, Part, Assembly, Drawing,  Presentation, iFeatures and UnknownDocument. Then we need to specify the internal name of the “RibbonTab” and “RibbonPanel”. There are too many options to print here but the following illogic rule will print them in the ilogic log.

For Each ribbon As Ribbon In ThisApplication.UserInterfaceManager.Ribbons
    Logger.Info(vbTab & Ribbon.InternalName)
    For Each ribbonTab As RibbonTab In Ribbon.RibbonTabs
        Logger.Info(vbTab & vbTab & RibbonTab.DisplayName & " - " & RibbonTab.InternalName)
        For Each ribbonPanel As RibbonPanel In RibbonTab.RibbonPanels
            Logger.Info(vbTab & vbTab & vbTab & RibbonPanel.DisplayName & " - " & RibbonPanel.InternalName)
        Next
    Next
Next
Dim loggerWindow = ThisApplication.UserInterfaceManager.
	DockableWindows.
	Cast(Of DockableWindow).
	Where(Function(d) d.InternalName.Equals("ilogic.logwindow")).
	First()
loggerWindow.Visible = True

 In my case, my button is only visible in the assembly environment. The button is on the “Manage” tap in the “iLogic” panel.

As managed the function “MyButton_OnExecute” is called when the button is clicked. Here we initialize the class “ThisRule” that does the real work.  

Abstract rule class

We are going to emulate iLogic. This means that we need some default illogic functions at our disposal in the rule class. If you at any point want to create a second button then you probably don’t want to implement the same logic twice. (At least I would not like it, maybe I'm a bit lazy…) Also, I want to be able to copy iLogic code as is to my addin. Therefore I chose to create an abstract class and inherit all functions in the base class in the rule class. For now, this base class is very small and there are only 2 properties. In most cases, it is sufficient to only have access to the iLogic property “ThisApplication” and “ThisDoc”

Create a class “AbstractRule” and add the following code:

Imports Autodesk.iLogic.Interfaces
Imports Autodesk.iLogic.Runtime
Imports Inventor

Public MustInherit Class AbstractRule

    Public Property ThisApplication As Inventor.Application
    Public ReadOnly Property ThisDoc As ICadDoc
        Get
            Return New CadDoc(ThisApplication.ActiveDocument)
        End Get
    End Property

End Class

Rule class

This is the class that will hold the iLogic rule. In this example, I will be able to copy/paste an iLogic rule from Inventor to the class.  (Just remember we did not implement all iLogic functions/properties. Your code might not work if you copy one of your rules. In that case, you need to implement your functions to emulate the iLogic functions)

Create a class “ThisRule” and add the following code:

Imports Inventor

Public Class ThisRule
    Inherits AbstractRule

    Public Sub Main()

        ' Your iLogic code goes here.

    End Sub

End Class

Notice line 4, this is where we tell the compiler to inherit the base class. In the more complicated rules, you will have more functions or even a whole class. Then you might need to add also code outside of the main function.

To end this tutorial with a functional/working addin we will replace the class code with the rule “One Rule to Search Them All”. The class “ThisRule” will then look like this.

Imports Inventor

Public Class ThisRule
    Inherits AbstractRule

    Private searchText As String
    Private iLogicAddinGuid As String = "{3BDD8D79-2179-4B11-8A5A-257B1C0263AC}"
    Private iLogicAddin As ApplicationAddIn = Nothing
    Private iLogicAutomation = Nothing
    Private outputFile As String = "c:\TEMP\seachedRules.txt"

    Sub Main()
        If (IO.File.Exists(outputFile)) Then
            IO.File.Delete(outputFile)
        End If
        searchText = InputBox("Text to search for", "Search")

        iLogicAddin = ThisApplication.ApplicationAddIns.ItemById(
            "{3bdd8d79-2179-4b11-8a5a-257b1c0263ac}")
        iLogicAutomation = iLogicAddin.Automation
        Dim doc As AssemblyDocument = ThisDoc.Document

        searchDoc(doc)
        For Each refDoc As Document In doc.AllReferencedDocuments
            searchDoc(refDoc)
        Next

        Process.Start("notepad.exe", outputFile)
    End Sub

    Private Sub searchDoc(doc As Document)
        Dim rules = iLogicAutomation.Rules(doc)
        If (rules Is Nothing) Then Return
        For Each rule In rules
            Dim strReader As IO.StringReader = New IO.StringReader(rule.Text)
            Dim i As Integer = 1

            Do While (True)
                Dim line As String
                line = strReader.ReadLine()
                If line Is Nothing Then Exit Do
                If (line.ToUpper().Contains(searchText.ToUpper())) Then
                    Dim nl = System.Environment.NewLine
                    IO.File.AppendAllText(outputFile,
                        "Doc name : " & doc.DisplayName & nl &
                        "Rule name: " & rule.Name & nl &
                        "line " & i & "  : " & line.Trim() & nl & nl)
                End If
                i = i + 1
            Loop
        Next
    End Sub
End Class

Now press "Run" (or press F5)  in Visual Studio and try your addin!

 

 

 

 

Skills:

Autodesk Inventor, Vault, Git, C#, vb, .net, php HTML, css, js

Education:

University computer science.
HBO Mechanical engineer.
MBO Fine mechanics.

Experience:

Programmer and Mechanical engineer at Kelvion
(2016 - 20..)

Mechanical engineer at Strukton
(2009 - 2016)

Mechanical engineer at RDG-engineering
(2007 - 2009)

CNC Programmer at VMC
(2005 - 2007)

volunteer at Taizé
(2007)

Certifications:

Objectgeoriënteerd analyseren en ontwerpen, Objectgeoriënteerd programmeren in Java, Webapplicaties: de clientkant, Databases, Security Aware Programmer, Web Security Specialist