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 programing 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 easy. But 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. I have created an addin for you that can create buttons for iLogic rules and you don’t have to write a line of code for it. Even better if you are using Inventor 2023 or later this is a built-in functionality.

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 on a button or the build-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. (Be aware that Visual Code is another programming IDE from Microsoft but you cant 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 4.8 framework. (Depending on your Inventor version you will need it.)

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

Make sure that you pick a project type that targets the .Net 4.8 framework. 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”. Wich is the most simple to set up. In this tutorial, I create a class library with WPF technology.

Setup the project

Delete the files “app.config”, “MainWindow.xaml” and “Application.xaml” (That probably means delete all files in your solution explorer)

Go to the “Project Properties”.

Set the “Application type” to “Class Library”.
Also, note the “Assembly name” somewhere. You will need it later in the .addin file.

Set the “Build output path”. The following 4 locations are supported. You can choose any one of them. depending on the needs of your add-in.

Your addin is for all Users, Version Independent
Windows 7/8.1/10 - %ALLUSERSPROFILE%\Autodesk\Inventor Addins\

Your addin is for all Users, Version Dependent
Windows 7/8.1/10 - %ALLUSERSPROFILE%\Autodesk\Inventor 20xx\Addins\

Your addin is user-specific, Version Dependent
In Window 7/8.1/10 - %APPDATA%\Autodesk\Inventor 20xx\Addins\

Your addin is user-specific, Version Independent
In Window 7/8.1/10 - %APPDATA%\Autodesk\ApplicationPlugins

 

Chang the start action to start Inventor.

Go to the “Add reference” screen.

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

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

By default the property “Embeding Interop Types” of the referenced Inventor Interop is set to True. Thas is may lead to unexpected results. You need to set this to False.

 

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>16..</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/2022/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 and it did read your .addin file. Then it will load your dll and starts 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("a7558ed7-8d2d-41bb-9295-4f3c9fe5d902"), 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 go 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!

Edit

2022-06-19: Changed the rule to find the names of the ribbons, ribbonTabs and ribbonPanels. All data was (and still is) written to the iLogic log, but now the log window is also automatically opened. (Credits go to Curtis Waguespack for posting this extension in this form post)

Extra's

All the above is what you need for a basic addin. But you might want to know more. Here are some other topics that I will cover in later (extension) tutorials.

(If you know more topics that I should cover then drop me a line)

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