Getting Inventor Application object in AddIns

awatt
Advocate
Advocate

Getting Inventor Application object in AddIns

awatt
Advocate
Advocate

A question regarding best practices.

 

When coding methods for an Inventor addin, which is preferred, passing m_inventorApplication from StandardAddInServer.CS (or .VB) to any class methods or getting the inventor object in each class / method with Marshal.GetActiveObject("InventorApplication") ?

 

I also ask because .Net CORE doesn't play nicely with Marshal, and if things go in that direction, the C# DllImport workaround is painful.

0 Likes
Reply
Accepted solutions (1)
772 Views
11 Replies
Replies (11)

Frederick_Law
Mentor
Mentor

Don't understand what you're asking.

 

In VB addin template:

#Region "Data"
    ' Inventor application object.
    Private m_inventorApplication As Application
#End Region
#Region "ApplicationAddInServer Members"
    Public Sub Activate(ByVal addInSiteObject As ApplicationAddInSite, ByVal firstTime As Boolean
                        ) Implements ApplicationAddInServer.Activate
      Try
        ' This method is called by Inventor when it loads the AddIn.
        ' The AddInSiteObject provides access to the Inventor Application object.
        ' The FirstTime flag indicates if the AddIn is loaded for the first time.
        ' Initialize AddIn members.
        m_inventorApplication = addInSiteObject.Application
      Catch ex As Exception
        Windows.Forms.MessageBox.Show(ex.ToString())
      End Try
    End Sub

#End Region

 

0 Likes

awatt
Advocate
Advocate

If I have other classes/methods in the same project but in other .vb files that require the application object is it best practice to pass the Inventor Application object to them as a parameter (m_inventorApplication) or have them get the object themselves?

 

0 Likes

Frederick_Law
Mentor
Mentor

I passed m_inventorApplication to another module.

 

Used oApp = addInSiteObject.Application in the class with Window Form for dialog.

 

They're converted from VBA macro to VB.Net.

 

Now I'm thinking, could I make m_inventorApplication public for both?

0 Likes

awatt
Advocate
Advocate

A good idea.  I just added a method to the StandardAddInServer class that will return the object.  It should be pretty stable. I'll start some testing.

(c#)

public Inventor.Application inventorAppObj(Inventor.ApplicationAddInSite addInSiteObject)
{
return addInSiteObject.Application;
}

awatt
Advocate
Advocate

Thinking further on this, it's not going to work.

 

The Activate method recieves the ApplicationAddInSite from inventor when it loads.

The method I just made won't get it from anywhere. I don't know what I was thinking.

 

I believe the most stable solution is to rewrite all my custom methods to accept an application object and pass it to them from within the activate method where it's available.

 

0 Likes

etaCAD
Advocate
Advocate

I use the Inventor object than comes from the Activate methode of your addin and store it in a global variable.

 

If you use Marshal to get Inventor you don't know which one you get when several Inventor windows are open.

Andreas
etaCAD

Michael.Navara
Advisor
Advisor
Accepted solution

The best practice is to pass the Inventor application instance to constructor of your class which needs to do something with inventor. Below is the minimalistic sample of inventor addin implementation

 

class StandardAddInServer : ApplicationAddInServer
{
    Inventor.Application inventor;
    MyCommand myCommand;


    public void Activate(ApplicationAddInSite AddInSiteObject, bool FirstTime)
    {
        //Get inventor app instance
        inventor = AddInSiteObject.Application;

        //Pass the inventor app to the command class
        myCommand = new MyCommand(inventor);

        //Create buttons in ribbon
        inventor.UserInterfaceManager.Ribbons["ZeroDoc"].RibbonTabs["id_TabTools"].RibbonPanels["id_PanelP_ToolsOptions"].CommandControls.AddButton(myCommand.ButtonDefinition);
        inventor.UserInterfaceManager.Ribbons["Part"].RibbonTabs["id_TabModel"].RibbonPanels["id_PanelP_Model2DSketchCreate"].CommandControls.AddButton(myCommand.ButtonDefinition);
    }

    public void Deactivate()
    {
        //Clear all buttons from ribbon
        CommandControlsEnumerator myCommandControls = inventor.UserInterfaceManager.AllReferencedControls(myCommand.ButtonDefinition as ControlDefinition);
        foreach (CommandControl cmdCtrl in myCommandControls)
        {
            try { cmdCtrl.Delete(); }
            catch { }
        }

        //Clear button definition
        myCommand.ButtonDefinition.Delete();

        //Finalize the addin
        inventor = null;
    }

    // Obsolete
    public void ExecuteCommand(int CommandID) { }

    // Not implemented
    public object Automation => null;
}


class MyCommand
{
    private readonly Inventor.Application inventor;
    private ButtonDefinition buttonDef;
    public ButtonDefinition ButtonDefinition => buttonDef;

    public MyCommand(Inventor.Application inventor)
    {
        this.inventor = inventor;
        buttonDef = inventor.CommandManager.ControlDefinitions.AddButtonDefinition(
            "My command", "MyCommandInternalName", CommandTypesEnum.kQueryOnlyCmdType /* etc. */);
        buttonDef.OnExecute += MyCommand_OnExecute;
    }


    private void MyCommand_OnExecute(NameValueMap Context)
    {
        MessageBox.Show(inventor.ActiveDocument.DisplayName, "My command");
    }

}

awatt
Advocate
Advocate

Thank you. This helps loads. Just wrapping my brain around it. . .

So the _OnExecute method has access to the Inventor object because 'inventor' is given the inventor object when an instance of MyCommand is created? 

My methods in the past have all been static, so it's a new concept.

0 Likes

Michael.Navara
Advisor
Advisor

Here is modified version with renamed variables of Inventor application for better understanding.

If you pass the inventor using constructor you don't need to use them static.

 

 

class StandardAddInServer : ApplicationAddInServer
{
    Inventor.Application inventorAtAddInLevel;
    MyCommand myCommand;


    public void Activate(ApplicationAddInSite AddInSiteObject, bool FirstTime)
    {
        //Get inventor app instance
        inventorAtAddInLevel = AddInSiteObject.Application;

        //Pass the inventor app to the command class
        myCommand = new MyCommand(inventorAtAddInLevel);

        //Create buttons in ribbon
        inventorAtAddInLevel.UserInterfaceManager
            .Ribbons["ZeroDoc"]
            .RibbonTabs["id_TabTools"]
            .RibbonPanels["id_PanelP_ToolsOptions"]
            .CommandControls.AddButton(myCommand.ButtonDefinition);

        inventorAtAddInLevel.UserInterfaceManager
            .Ribbons["Part"]
            .RibbonTabs["id_TabModel"]
            .RibbonPanels["id_PanelP_Model2DSketchCreate"]
            .CommandControls.AddButton(myCommand.ButtonDefinition);
    }

    public void Deactivate()
    {
        //Clear all buttons from ribbon
        var myCommandButtonAsControlDef = myCommand.ButtonDefinition as ControlDefinition;
        var myCommandControls = 
            inventorAtAddInLevel.UserInterfaceManager.AllReferencedControls(myCommandButtonAsControlDef);

        foreach (CommandControl cmdCtrl in myCommandControls)
        {
            try { cmdCtrl.Delete(); }
            catch { /* IGNORE ALL ERRORS*/ }
        }

        //Clear button definition
        myCommand.ButtonDefinition.Delete();

        //Finalize the addin
        inventorAtAddInLevel = null;
    }

    // Obsolete
    public void ExecuteCommand(int CommandID) { }

    // Not implemented
    public object Automation => null;
}


class MyCommand
{
    private readonly Inventor.Application inventorAtMyCommandLevel;
    private ButtonDefinition buttonDef;
    public ButtonDefinition ButtonDefinition => buttonDef;

    public MyCommand(Inventor.Application inventorAsArgument)
    {
        inventorAtMyCommandLevel = inventorAsArgument;
        buttonDef = inventorAtMyCommandLevel.CommandManager.ControlDefinitions.AddButtonDefinition(
            "My command", "MyCommandInternalName", CommandTypesEnum.kQueryOnlyCmdType /* etc. */);
        buttonDef.OnExecute += MyCommand_OnExecute;
    }


    private void MyCommand_OnExecute(NameValueMap Context)
    {
        MessageBox.Show(inventorAtMyCommandLevel.ActiveDocument.DisplayName, "My command");
    }

}

 

awatt
Advocate
Advocate

A million thanks. And a Like or two.

0 Likes

awatt
Advocate
Advocate

I've implemented the above successfully, and would like to add I found a way to get the Application object from the Document object:

DOCUMENT.DOCUMENTINTERESTS.APPLICATION

It's not exactly well-advertised.  I tend to think of my methods as recieving only the document object, not both the application and document objects.

 

0 Likes