Converting VBA Auto Macros to an Add-In

This posting assumes you have a VBA auto macro and want to quit using the auto macro functionality and convert it to an add-in. See the previous posting VBA Document Projects as to why you might want to do this.  Without a lot of explanation, here are the prerequisites and the steps required to create the add-in.

Here is an example of an automatic macro that exists within a drawing document. It automatically writes out dwf and pdf files of the drawing whenever the drawing is saved.  The rest of this post looks at the process to create an add-in to replace this auto macro.

Public Sub AutoSave()
    ' Get the filename minus the extension.
    Dim strFilename As String
    strFilename = ThisDocument.FullFileName
    strFilename = Left(strFilename, Len(strFilename) – 4)

    ' Save the current SilentOperation and then turn it on.
    ' This will suppress the dwf viewer from being displayed.

    Dim currentSetting As Boolean
    currentSetting = ThisApplication.SilentOperation
    ThisApplication.SilentOperation = True

    ' Save the file as dwf.
    Call ThisDocument.SaveAs(strFilename & ".dwf", True)

    ' Reset SilentOperation back to its previous value.
    ThisApplication.SilentOperation = currentSetting

    ' Save the file as pdf.
    Call ThisDocument.SaveAs(strFilename & ".pdf", True)
End Sub

What You'll Need

A Programming Language – To write an add-in you need to use a language that supports creating COM components. For this example I'll illustrate the process using both Visual Basic 2008 and C# 2008. Microsoft provides free Express versions of both of these languages. You can install them from the Microsoft web site. Microsoft also provides online training resources for learning these languages. If this is all new to you and you don't know which one to get I would recommend Visual Basic, but it really is a personal preference.

Inventor SDK Developer Tools – You'll also need some Inventor specific development tools.  This is delivered when you install Inventor but you need to run its setup to install it. Assuming you're using Inventor 2009, locate the following file in Explorer and run it:

C:\Program Files\Autodesk\Inventor 2009\SDK\DeveloperTools.msi

Inventor 2009 was released when Visual Studio 2005 was the current development platform. Because of that the Add-In wizard provided with it does not get installed for use with Visual Studio 2008.  To work around this you can copy the files below to the specified directories.  Don't unzip the files but just copy the file as-is.

VB 2008
Copy VBInventorAddInTemplate.zip to 
"My Documents\Visual Studio 2008\Templates\ProjectTemplates"

C# 2008
Copy VCSInventorAddInTemplate.zip to 
"My Documents\Visual Studio 2008\Templates\ProjectTemplates"

Creating the Add-In

The add-in is created using the add-in template. Start VB or C# and choose to create a new project. For the template choose "Autodesk Inventor AddIn", as shown below. You can also specify the name of the add-in at this point, ("AutoSaveAddIn" in the example below).

 New add-in project.

In the Visual Studio Solution Explorer you'll see the various files listed that were created for the project. For a Visual Basic add-in, most of the code is in the StandardAddInServer.vb file and for a C# add-in it is in the StandardAddInServer.cs file. Double-click on this file to open it in the code editor. You should see something very similar to one of the pictures below. Your GuidAttribute value will be different than those shown below since that is unique for every add-in.

AddInStartVB 
Visual Basic Code Window

AddInStartCS
Visual C# Code Window

Editing the Name and Description of the Add-In

One common thing you'll want to do when creating an add-in is to define the name and description of the add-in as it will be seen in the Add-In Manager. You do this by editing the code in the "COM Registration" block of the code. Click on the "+" next to this region to expand it. The code in red is the portion I've changed to modify the name and the description. The code below is from the VB add-in but the C# code is almost identical and it will be obvious what to edit.

Public Shared Sub Register(ByVal t As Type)
   Dim clssRoot As RegistryKey = Registry.ClassesRoot
   Dim clsid As RegistryKey = Nothing
   Dim subKey As RegistryKey = Nothing
   Try
      clsid = clssRoot.CreateSubKey("CLSID\" + AddInGuid(t))
      clsid.SetValue(Nothing, "Automated DWF and PDF Save")
      subKey = clsid.CreateSubKey( _  
    "Implemented Categories\{39AD2B5C-7A29-11D6-8E0A-0010B541CAA8}")
      subKey.Close()       subKey = clsid.CreateSubKey("Settings")
      subKey.SetValue("AddInType", "Standard")
      subKey.SetValue("LoadOnStartUp", "1")
      'subKey.SetValue("SupportedSoftwareVersionLessThan", "")
      subKey.SetValue("SupportedSoftwareVersionGreaterThan", "12..")
      'subKey.SetValue("SupportedSoftwareVersionEqualTo", "")
      'subKey.SetValue("SupportedSoftwareVersionNotEqualTo", "")
      'subKey.SetValue("Hidden", "0")
      'subKey.SetValue("UserUnloadable", "1")
      subKey.SetValue("Version", 0)
      subKey.Close()
      subKey = clsid.CreateSubKey("Description")
      subKey.SetValue(Nothing, "Saves drawings as DWF and PDF.")
   Catch ex As Exception
      System.Diagnostics.Trace.Assert(False)
   Finally
      If Not subKey Is Nothing Then subKey.Close()
      If Not clsid Is Nothing Then clsid.Close()
      If Not clssRoot Is Nothing Then clssRoot.Close()
   End Try
End Sub

Reacting to Events in Visual Basic

Now we can add the code that will react anytime a document is saved. For a VB add-in, add the code below that's shown in red. The second line is in the "ApplicationAddInServer Members" code region so you'll need to expand that region to see the code.  The code consists of a declaration and an assignment.

Public Class StandardAddInServer
   Implements Inventor.ApplicationAddInServer
   ' Inventor application object.
   Private m_inventorApplication As Inventor.Application
   Private WithEvents m_appEvents As Inventor.ApplicationEvents

#Region "ApplicationAddInServer Members"
   Public Sub Activate( _
          ByVal addInSiteObject As Inventor.ApplicationAddInSite, _ 
          ByVal firstTime As Boolean) _
               Implements Inventor.ApplicationAddInServer.Activate
       ' Initialize AddIn members.
       m_inventorApplication = addInSiteObject.Application
       m_appEvents = m_inventorApplication.ApplicationEvents
   End Sub

At the top of the code window are two combo boxes. The one on the left displays a list of classes and the one on the right displays a list of methods for the selected class. Choose "m_appEvents" on the left and "OnSaveDocument" on the right, as shown below. This will insert the sub m_appEvents_OnsaveDocument as shown below. This is the event handler for the OnSaveDocument event will be called whenever a document is saved in Inventor.

OnSaveEventVB

 

Here's code that's equivalent to the original AutoSave macro. This performs a couple of additional checks that the original automatic macro didn't need to do. First, the OnSaveDocument is fired before and after the document is actually saved.  This listens for when the event is fired after the Inventor save. The event is also fired whenever any document is saved. This looks for and only handles drawing documents.

Private Sub m_appEvents_OnSaveDocument( _                  
               ByVal DocumentObject As Inventor._Document, _  
               ByVal BeforeOrAfter As Inventor.EventTimingEnum, _  
               ByVal Context As Inventor.NameValueMap, _  
               ByRef HandlingCode As Inventor.HandlingCodeEnum) _  
                                  Handles m_appEvents.OnSaveDocument 
  If BeforeOrAfter = EventTimingEnum.kAfter Then 
    If DocumentObject.DocumentType = DocumentTypeEnum.kDrawingDocumentObject Then 
      ' Get the filename minus the extension. 
      Dim filename As String 
      filename = DocumentObject.FullFileName 
      filename = Left(filename, Len(filename) – 4) 

      ' Save the current SilentOperation and then turn it on.  
      ' This will suppress the dwf viewer from being displayed.  
      Dim currentSetting As Boolean  
      currentSetting = m_inventorApplication.SilentOperation  
      m_inventorApplication.SilentOperation = True 

      ' Save the file as dwf.  
      DocumentObject.SaveAs(filename & ".dwf", True)  

      ' Save the file as pdf.  
      DocumentObject.SaveAs(filename & ".pdf", True)  

      ' Reset SilentOperation back to its previous value.  
      m_inventorApplication.SilentOperation = currentSetting 
    End If  
  End If
End Sub

Reacting to Events in C#

The code highlighted in red below was added to support handling the save event in C#.  The last two lines are in the "ApplicationAddInServer Members" code region so you'll need to expand that region to see the code.  The line where the delegate is created to handle the event is mostly created by using Intellisense.  Go slowly as you type and you'll see options pop up that allow you to press the tab key to create much of the code.

private Inventor.Application m_inventorApplication;
private Inventor.ApplicationEvents m_appEvents = null;

public StandardAddInServer()
{
}
#region ApplicationAddInServer Members

public void Activate(

               Inventor.ApplicationAddInSite addInSiteObject,
               bool firstTime)
{
   // Initialize AddIn members.
   m_inventorApplication = addInSiteObject.Application;
   m_appEvents = m_inventorApplication.ApplicationEvents;

   // Create the delegate object to handle the event.
   m_appEvents.OnSaveDocument += new 
        ApplicationEventsSink_OnSaveDocumentEventHandler(
                                     m_appEvents_OnSaveDocument);
}

Intellisense can also create the event implementation code as you're typing the line above.  Below is the code it created with the additional code in red that I added to save the dwf and pdf files.

void m_appEvents_OnSaveDocument(_Document DocumentObject,
                EventTimingEnum BeforeOrAfter,
                NameValueMap Context,
                out HandlingCodeEnum HandlingCode)
{
   // A value has to be returned for the handling code.
   HandlingCode = HandlingCodeEnum.kEventNotHandled;

   if (BeforeOrAfter == EventTimingEnum.kAfter)
   {
      if (DocumentObject.DocumentType == DocumentTypeEnum.kDrawingDocumentObject)
      {
         // Get the filename minus the extension.
         String filename = DocumentObject.FullFileName;
         filename = filename.Substring(0, filename.Length – 4);

         // Save the current SilentOperation and then turn it on.
         // This will suppress the dwf viewer from being displayed.

         Boolean currentSetting = m_inventorApplication.SilentOperation;
         m_inventorApplication.SilentOperation = true;

         // Save the file as dwf.
         DocumentObject.SaveAs(filename + ".dwf", true); 

         // Save the file as pdf.
         DocumentObject.SaveAs(filename + ".pdf", true);

         // Reset SilentOperation back to its previous value.
         m_inventorApplication.SilentOperation = currentSetting; 
      }
   }
}


Cleaning Up

Finally, just a bit of code to clean up everything when the add-in is unloaded.  This is in the Deactivate method of the add-in.  The code I added is in red.

Public Sub Deactivate() Implements Inventor.ApplicationAddInServer.Deactivate
   ' Release objects.
   Marshal.ReleaseComObject(m_appEvents)
   m_appEvents = Nothing

   Marshal.ReleaseComObject(m_inventorApplication)
   m_inventorApplication = Nothing

   System.GC.WaitForPendingFinalizers()
   System.GC.Collect()
End Sub

Here's the equivalent code for C#.

public void Deactivate()
{
   // Disconnect the event delegate.
   m_appEvents.OnSaveDocument -= new
       ApplicationEventsSink_OnSaveDocumentEventHandler(
                                m_appEvents_OnSaveDocument);

   // Release objects.
   Marshal.ReleaseComObject(m_appEvents);
   m_appEvents = null;
   Marshal.ReleaseComObject(m_inventorApplication);
   m_inventorApplication = null;

   GC.WaitForPendingFinalizers();
   GC.Collect();
}


Using the Add-In

Now all you need to do is build the add-in.   Building the add-in creates the dll and also registers it.  When you run Inventor you should see the add-in in the Add-In Manager and when you save a drawing document the corresponding pdf and dwf files will also be created.

To use the add-in on another computer you need to copy the add-in dll to that computer and register it.  Below are some commands you can use within .bat files to both register and unregister the add-in for 32 and 64-bit installations.

Register on 32-bit

@echo off
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe /codebase AutoSaveAddIn.dll
PAUSE


Unregister on 32-bit

@echo off
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe /unregister AutoSaveAddIn.dll
PAUSE

Register on 64-bit

@echo off
C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\RegAsm.exe /codebase AutoSaveAddIn.dll
PAUSE


Unregister on 64-bit

@echo off
C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\RegAsm.exe /unregister AutoSaveAddIn.dll
PAUSE

When you test the add-in you can't just open an existing drawing, immediately save it, and expect to see the dwf and pdf files.  The reason is because the drawing hasn't changed so clicking the save button doesn't do anything.  If you make any change to the drawing, i.e. edit an iProperty or move a view or dimension, the OnSaveDocument event is fired and the additional files will be created.


Comments

17 responses to “Converting VBA Auto Macros to an Add-In”

  1. Jon Brabbs Avatar
    Jon Brabbs

    Man I’ve been doing this the hard way, I’ve got about 100 lines to do this!
    Thanks for the post Brian. I will have a play and see what happens.
    Cheers
    Jon

  2. Hi,
    I realise I’m a little late joining the party on this, but I was wondering if the template you’ve created can be used with the Express 2008 versions of both C# and VB.NET?
    Cheers,
    Alex.

  3. Bob Collins Avatar
    Bob Collins

    Brian,
    I ran thru this example using C# and it builds successfully, but I have to manually register the dll to get Inventor to see it. I am running Vista64 / Inventor 2009 64 bit. Do I need to do anything different for the 64 bit vs the 32?
    Just got back from AU – had a great time!
    Thanks,
    Bob

  4. Brian,
    Great code. This will come in handy. A question though, is there a way to generated a pdf\dwf of all the sheets in the IDW file. I noticed that it only publishes the current sheet.
    Thanks,

    Dan

    See the posting http://modthemachine.typepad.com/my_weblog/2009/01/translating-files-with-the-api.html
    -Brian

  5. Hi Brian,
    Thank you for posting this and all the other great tips. Is it possible to see the conversion of a VBA form to a VB Add-in?
    Thanks,
    Tim

  6. Peter Bosse Avatar
    Peter Bosse

    Hi Brian,
    (AutoSave DWF/PDF)
    If I want to place the DWF/PDF in a particular folder fx. T:\InvDrw.. How do i do that..?

  7. The full filename of the file to create is being defined in the program. You set this to anything you would like. In the sample it’s getting the full filename of the document being saved and modifying the extension.
    Dim filename As String
    filename = DocumentObject.FullFileName
    filename = Left(filename, Len(filename) – 4)
    It could be changed to something like this:
    Dim filename As String
    filename = “T:\InvDrw\Myfile.dwf”

  8. Is it necessary for me to register (using RegAsm) any custom assemblies that my add-in class references?
    Here is the problem I am having:
    I am have created an add-in to Inventor 2009(in C#) and I am in the process of debugging it. My add-in uses classes that are defined in other custom assemblies that I have created to be used with the add-in. When I register the add-in, run Inventor, and click on my created add-in button, I sometimes get exceptions stating that my add-in cannot find the custom assemblies that are needed in order for it to run, although the assemblies are in the same directory as the add-in .dll and are of the correct version.

  9. Randy Avatar
    Randy

    I have the expresss version of visual basic. I build a project in 32 bit and it works. I build it on a 64 bit machine and it doesn’t show in the addins. I tried to manually registering it per your bat setup, got a successful register and it still does not show. What am I missing.

  10. Randy Avatar
    Randy

    What I was missing was the name it was published with. It is there and works great.
    Thanks

  11. Enrico Lucchetti Avatar
    Enrico Lucchetti

    Hi Brian, I built the project and I regoster i on 32 bit, but it does not work in Inventor (I’m using 2008 version). What am I missing? Is it right if the dll is not in the bin directory of Inventor?
    thanks
    Enrico

  12. Jon Holler Avatar
    Jon Holler

    Hi Brian,
    The “StandardAddInServer” gives me errors when I open the the template in vb2008. Any idea what’s happening here?
    Jon

  13. M.S.R Avatar
    M.S.R

    Hi Brain,
    I have created an Addin for Inventor using VB.Net in VisualStudio 2008, I have created it as a model-less dialog but when I press tab key the cursor is not moving to next tool.
    I have also checked the TabStop and TabIndex those are perfect and when I create the same as model then the tab order is working…Is there any possible ways that I can make the tab order working for model less dialog also…

  14. My add-in uses classes that are defined in other custom assemblies that I have created to be used with the add-in. When I register the add-in, run Inventor, and click on my created add-in button.

  15. Dear Brian,
    Can I please ask you if you have the source code (either Visual Basic or “C”) for the above project (AutoSave.dll) that I can download?
    Can you make the source code public domain?
    Kindest Regards
    Darren Smith

  16. I am newbie to all this and for some odd reason doesn’t recognize the add in i’ve created thru VS2010. I’ve read alot about implementing regasm.exe to register your add in, but don’t have clue how to do or what that means. Can anyone advise of how to get around this issue or have any reference material they can provide.
    thanks

  17. What would I have to do to impliment this Add In on a Win7 64 Bit system?

Leave a Reply to Enrico LucchettiCancel reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading