Custom Addin Error on Re-Load

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
I've been working on an add-in for a bit now and came to a strange issue. My add-in loads and operates as excepted on initial start up, but when I manually unload and the load the add-in I get an error when my code attempts to add my button to the annotate ribbon panel. See my code below:
I read that it could be an issue with an object not being released properly, but I feel like I've gone through and released everything, unless I missed something. When I comment out :
' Add a button. textPanel.CommandControls.AddButton(m_Button, True)
Everything works fine (except that I can't use the add-in since there is no button created. The error I recieve is this:
An exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll but was not handled in user code
Additional information: Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL))
Thanks in advance for your time!
Imports Inventor Imports System.Runtime.InteropServices Imports Microsoft.Win32 Namespace TBF_Kova <ProgIdAttribute("TBF_Kova.StandardAddInServer"), GuidAttribute("baa6d8eb-24b9-444d-affa-bb9235933b56")> Public Class StandardAddInServer Implements Inventor.ApplicationAddInServer Private WithEvents m_uiEvents As UserInterfaceEvents = Nothing Private WithEvents m_Button As ButtonDefinition = Nothing Dim WithEvents m_AppEvents As ApplicationEvents = Nothing Dim WithEvents m_DocEvents As DocumentEvents = Nothing #Region "ApplicationAddInServer Members" ' 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. However, with the introduction of the ribbon this argument is always true. Public Sub Activate(ByVal addInSiteObject As Inventor.ApplicationAddInSite, ByVal firstTime As Boolean) Implements Inventor.ApplicationAddInServer.Activate ' Initialize AddIn members. g_inventorApplication = addInSiteObject.Application ' Connect to the user-interface events to handle a ribbon reset. m_uiEvents = g_inventorApplication.UserInterfaceManager.UserInterfaceEvents m_AppEvents = g_inventorApplication.ApplicationEvents ' TODO: Add button definitions. ' Sample to illustrate creating a button definition. Dim largeIcon As stdole.IPictureDisp = PictureDispConverter.ToIPictureDisp(My.Resources.pencilBig) Dim smallIcon As stdole.IPictureDisp = PictureDispConverter.ToIPictureDisp(My.Resources.pencilSmall) Dim controlDefs As Inventor.ControlDefinitions = g_inventorApplication.CommandManager.ControlDefinitions m_Button = controlDefs.AddButtonDefinition("Title Block" & vbCrLf & "Filler", "TBF", CommandTypesEnum.kShapeEditCmdType, AddInClientID,,, smallIcon, largeIcon) ' Add to the user interface, if it's the first time. If firstTime Then AddToUserInterface() End If End Sub ' This method is called by Inventor when the AddIn is unloaded. The AddIn will be ' unloaded either manually by the user or when the Inventor session is terminated. Public Sub Deactivate() Implements Inventor.ApplicationAddInServer.Deactivate ' TODO: Add ApplicationAddInServer.Deactivate implementation Debug.Print("TBF has been unloaded.") ' Release objects. m_uiEvents = Nothing m_AppEvents = Nothing m_DocEvents = Nothing m_Button = Nothing uiForm = Nothing g_inventorApplication = Nothing System.GC.Collect() System.GC.WaitForPendingFinalizers() End Sub ' This property is provided to allow the AddIn to expose an API of its own to other ' programs. Typically, this would be done by implementing the AddIn's API ' interface in a class and returning that class object through this property. Public ReadOnly Property Automation() As Object Implements Inventor.ApplicationAddInServer.Automation Get Return Nothing End Get End Property ' Note:this method is now obsolete, you should use the ' ControlDefinition functionality for implementing commands. Public Sub ExecuteCommand(ByVal commandID As Integer) Implements Inventor.ApplicationAddInServer.ExecuteCommand End Sub #End Region #Region "User interface definition" ' Sub where the user-interface creation is done. This is called when ' the add-in loaded and also if the user interface is reset. Private Sub AddToUserInterface() ' This is where you'll add code to add buttons to the ribbon. '** Sample to illustrate creating a button on a new panel of the Tools tab of the Part ribbon. ' Get the Drawing ribbon. Dim drawRibbon As Ribbon = g_inventorApplication.UserInterfaceManager.Ribbons.Item("Drawing") ' Get the "Annotate" tab. Dim annotateTab As RibbonTab = drawRibbon.RibbonTabs.Item("id_TabAnnotate") ' Create a new panel. 'Dim customPanel As RibbonPanel = toolsTab.RibbonPanels.Add("Kova Engineering", "Kova_Panel", AddInClientID) ' Get Annotate Text Panel Dim textPanel As RibbonPanel = annotateTab.RibbonPanels.Item("id_PanelD_AnnotateText") ' Add a button. textPanel.CommandControls.AddButton(m_Button, True) End Sub Private Sub m_uiEvents_OnResetRibbonInterface(Context As NameValueMap) Handles m_uiEvents.OnResetRibbonInterface ' The ribbon was reset, so add back the add-ins user-interface. AddToUserInterface() End Sub ' Sample handler for the button. Private Sub m_Button_OnExecute(Context As NameValueMap) Handles m_Button.OnExecute If uiForm Is Nothing Then uiForm = New Form1() End If uiForm.Show() uiForm.Activate() End Sub Private Sub m_AppEvents_OnActivateDocument(DocumentObject As _Document, BeforeOrAfter As EventTimingEnum, Context As NameValueMap, ByRef HandlingCode As HandlingCodeEnum) Handles m_AppEvents.OnActivateDocument m_DocEvents = g_inventorApplication.ActiveDocument.DocumentEvents End Sub Private Sub m_DocEvents_OnChange(ReasonsForChange As CommandTypesEnum, BeforeOrAfter As EventTimingEnum, Context As NameValueMap, ByRef HandlingCode As HandlingCodeEnum) Handles m_DocEvents.OnChange If BeforeOrAfter = EventTimingEnum.kBefore Then Debug.Print("Reason for change - " & Context.Item(1)) End If If ReasonsForChange = CommandTypesEnum.kQueryOnlyCmdType Then Dim sheetB As String = "" Dim sheetA As String = "" If BeforeOrAfter = EventTimingEnum.kBefore Then sheetB = g_inventorApplication.ActiveDocument.ActiveSheet.name Else sheetA = g_inventorApplication.ActiveDocument.ActiveSheet.name If sheetA <> sheetB Then 'update subjects to be ordered correctly uiForm.method End If End If End If End Sub #End Region End Class End Namespace Public Module Globals ' Inventor application object. Public g_inventorApplication As Inventor.Application = Nothing Public uiForm As Form1 = Nothing #Region "Function to get the add-in client ID." ' This function uses reflection to get the GuidAttribute associated with the add-in. Public Function AddInClientID() As String Dim guid As String = "" Try Dim t As Type = GetType(TBF_Kova.StandardAddInServer) Dim customAttributes() As Object = t.GetCustomAttributes(GetType(GuidAttribute), False) Dim guidAttribute As GuidAttribute = CType(customAttributes(0), GuidAttribute) guid = "{" + guidAttribute.Value.ToString() + "}" Catch End Try Return guid End Function #End Region #Region "hWnd Wrapper Class" ' This class is used to wrap a Win32 hWnd as a .Net IWind32Window class. ' This is primarily used for parenting a dialog to the Inventor window. ' ' For example: ' myForm.Show(New WindowWrapper(g_inventorApplication.MainFrameHWND)) ' Public Class WindowWrapper Implements System.Windows.Forms.IWin32Window Public Sub New(ByVal handle As IntPtr) _hwnd = handle End Sub Public ReadOnly Property Handle() As IntPtr _ Implements System.Windows.Forms.IWin32Window.Handle Get Return _hwnd End Get End Property Private _hwnd As IntPtr End Class #End Region #Region "Image Converter" ' Class used to convert bitmaps and icons from their .Net native types into ' an IPictureDisp object which is what the Inventor API requires. A typical ' usage is shown below where MyIcon is a bitmap or icon that's available ' as a resource of the project. ' ' Dim smallIcon As stdole.IPictureDisp = PictureDispConverter.ToIPictureDisp(My.Resources.MyIcon) Public NotInheritable Class PictureDispConverter <DllImport("OleAut32.dll", EntryPoint:="OleCreatePictureIndirect", ExactSpelling:=True, PreserveSig:=False)> _ Private Shared Function OleCreatePictureIndirect( _ <MarshalAs(UnmanagedType.AsAny)> ByVal picdesc As Object, _ ByRef iid As Guid, _ <MarshalAs(UnmanagedType.Bool)> ByVal fOwn As Boolean) As stdole.IPictureDisp End Function Shared iPictureDispGuid As Guid = GetType(stdole.IPictureDisp).GUID Private NotInheritable Class PICTDESC Private Sub New() End Sub 'Picture Types Public Const PICTYPE_BITMAP As Short = 1 Public Const PICTYPE_ICON As Short = 3 <StructLayout(LayoutKind.Sequential)> _ Public Class Icon Friend cbSizeOfStruct As Integer = Marshal.SizeOf(GetType(PICTDESC.Icon)) Friend picType As Integer = PICTDESC.PICTYPE_ICON Friend hicon As IntPtr = IntPtr.Zero Friend unused1 As Integer Friend unused2 As Integer Friend Sub New(ByVal icon As System.Drawing.Icon) Me.hicon = icon.ToBitmap().GetHicon() End Sub End Class <StructLayout(LayoutKind.Sequential)> _ Public Class Bitmap Friend cbSizeOfStruct As Integer = Marshal.SizeOf(GetType(PICTDESC.Bitmap)) Friend picType As Integer = PICTDESC.PICTYPE_BITMAP Friend hbitmap As IntPtr = IntPtr.Zero Friend hpal As IntPtr = IntPtr.Zero Friend unused As Integer Friend Sub New(ByVal bitmap As System.Drawing.Bitmap) Me.hbitmap = bitmap.GetHbitmap() End Sub End Class End Class Public Shared Function ToIPictureDisp(ByVal icon As System.Drawing.Icon) As stdole.IPictureDisp Dim pictIcon As New PICTDESC.Icon(icon) Return OleCreatePictureIndirect(pictIcon, iPictureDispGuid, True) End Function Public Shared Function ToIPictureDisp(ByVal bmp As System.Drawing.Bitmap) As stdole.IPictureDisp Dim pictBmp As New PICTDESC.Bitmap(bmp) Return OleCreatePictureIndirect(pictBmp, iPictureDispGuid, True) End Function End Class #End Region End Module