Okay, I've done quite a bit of digging on this topic and not found a definitive answer. I've managed to do this, creating code that load's dll's at runtime and adds them to the menu for the add-in.
Some info to begin with:
I have a 'loader' assembly that is used by solidworks as the Addin. This loader assembly includes the callback function for the addin
As solidworks is loading, my code looks through a folder to find dll files that represent buttons that I want to add to my menu
Every button dll file contains that button's callback sub as well as a link to a bmp file to use for the button image
Each button dll must be coded to meet a strict format that I rely on in my loader dll
I fire an event every time a button is pressed in solidworks that returns the button id of the pressed button
The name of the button dll and the name of the class inside the button dll must be exactly the same
Here's the code for the loader:
Imports System
Imports System.Collections
Imports System.Reflection
Imports System.Runtime.InteropServices
'Imports System.Runtime.InteropServices.DispatchWrapper
Imports System.Messaging
Imports SolidWorks.Interop.sldworks
Imports SolidWorks.Interop.swconst
Imports SolidWorks.Interop.swpublished
Imports SolidWorksTools
Imports SolidWorksTools.File
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.Data.SqlClient
Imports System.Collections.ObjectModel
Imports System.Drawing
Title:="TDS Addin Manager", _
LoadAtStartup:=True _
)> _
Public Class TDSTools
Implements SolidWorks.Interop.swpublished.SwAddin
#Region "Local Variables"
Dim WithEvents iSwApp As SldWorks
Dim iCmdMgr As ICommandManager
Dim addinID As Integer
Dim dllLoc As String = My.Application.Info.DirectoryPath & "\Buttons"
Dim objList(0) As Object
Dim commandID As Integer
Dim buttonNum As Integer
Public Const mainCmdGroupID As Integer = 1
#End Region
#Region "Properties"
ReadOnly Property SwApp() As SldWorks
Get
Return iSwApp
End Get
End Property
ReadOnly Property CmdMgr() As ICommandManager
Get
Return iCmdMgr
End Get
End Property
#End Region
' Get Custom Attribute: SwAddinAttribute
Dim attributes() As Object
Dim SWattr As SwAddinAttribute = Nothing
attributes = System.Attribute.GetCustomAttributes(GetType(TDSTools), GetType(SwAddinAttribute))
If attributes.Length > 0 Then
SWattr = DirectCast(attributes(0), SwAddinAttribute)
End If
Try
Dim hklm As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.LocalMachine
Dim hkcu As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.CurrentUser
Dim keyname As String = "SOFTWARE\SolidWorks\Addins\{" + t.GUID.ToString() + "}"
Dim addinkey As Microsoft.Win32.RegistryKey = hklm.CreateSubKey(keyname)
addinkey.SetValue(Nothing, 0)
addinkey.SetValue("Description", SWattr.Description)
addinkey.SetValue("Title", SWattr.Title)
keyname = "Software\SolidWorks\AddInsStartup\{" + t.GUID.ToString() + "}"
addinkey = hkcu.CreateSubKey(keyname)
addinkey.SetValue(Nothing, SWattr.LoadAtStartup, Microsoft.Win32.RegistryValueKind.DWord)
Catch nl As System.NullReferenceException
Console.WriteLine("There was a problem registering this dll: SWattr is null.\n " & nl.Message)
System.Windows.Forms.MessageBox.Show("There was a problem registering this dll: SWattr is null.\n" & nl.Message)
Catch e As System.Exception
Console.WriteLine("There was a problem registering this dll: " & e.Message)
System.Windows.Forms.MessageBox.Show("There was a problem registering this dll: " & e.Message)
End Try
End Sub
Try
Dim hklm As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.LocalMachine
Dim hkcu As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.CurrentUser
Dim keyname As String = "SOFTWARE\SolidWorks\Addins\{" + t.GUID.ToString() + "}"
hklm.DeleteSubKey(keyname)
keyname = "Software\SolidWorks\AddInsStartup\{" + t.GUID.ToString() + "}"
hkcu.DeleteSubKey(keyname)
Catch nl As System.NullReferenceException
Console.WriteLine("There was a problem unregistering this dll: SWattr is null.\n " & nl.Message)
System.Windows.Forms.MessageBox.Show("There was a problem unregistering this dll: SWattr is null.\n" & nl.Message)
Catch e As System.Exception
Console.WriteLine("There was a problem unregistering this dll: " & e.Message)
System.Windows.Forms.MessageBox.Show("There was a problem unregistering this dll: " & e.Message)
End Try
End Sub
#Region "ISwAddin Implementation"
Function ConnectToSW(ByVal ThisSW As Object, ByVal Cookie As Integer) As Boolean Implements SolidWorks.Interop.swpublished.SwAddin.ConnectToSW
iSwApp = ThisSW
addinID = Cookie
'loop through the dll files and add the ones that are named the same as the class inside to this assembly
For Each name As String In My.Computer.FileSystem.GetFiles(dllLoc, FileIO.SearchOption.SearchTopLevelOnly, "*.dll")
Dim assemblyType As System.Type
Dim dllName As String = IO.Path.GetFileNameWithoutExtension(name)
'loop through the types in the assembly to find the one with the right name, then add it
For Each assemblyType In Assembly.LoadFrom(name).GetExportedTypes
If dllName.ToUpper = assemblyType.Name.ToUpper Then
'add a slot to the array and create an object of the reference
If objList(objList.Length - 1) IsNot Nothing Then
Array.Resize(objList, objList.Length + 1)
End If
objList(objList.Length - 1) = DirectCast(Activator.CreateInstance(assemblyType), Object)
Exit For
End If
Next
Next name
'set the callback object to this assembly
iSwApp.SetAddinCallbackInfo(0, Me, addinID)
' Setup the Command Manager
iCmdMgr = iSwApp.GetCommandManager(Cookie)
AddCommandMgr()
AttachEventHandlers()
ConnectToSW = True
End Function
Function DisconnectFromSW() As Boolean Implements SolidWorks.Interop.swpublished.SwAddin.DisconnectFromSW
System.Runtime.InteropServices.Marshal.ReleaseComObject(iCmdMgr)
iCmdMgr = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(iSwApp)
iSwApp = Nothing
'The addin _must_ call GC.Collect() here in order to retrieve all managed code pointers
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
DisconnectFromSW = True
End Function
#End Region
#Region "UI Methods"
Public Sub AddCommandMgr()
Dim cmdGroup As CommandGroup = iCmdMgr.CreateCommandGroup(mainCmdGroupID, "TDS Tools", "Tools Developed by TDS", "", -1)
Dim menuToolbarOption As Integer = swCommandItemType_e.swMenuItem Or swCommandItemType_e.swToolbarItem
Dim id As Integer
Dim ImageList As New Bitmap((objList.Length) * 16, 16)
Dim g As Graphics = Graphics.FromImage(ImageList)
Dim picLoc As String = My.Application.Info.DirectoryPath & "\ImageList.bmp"
Dim buttonImage As Bitmap
Dim buttonAdder As Integer = 0
cmdGroup.HasToolbar = True
cmdGroup.HasMenu = True
'loop through the button objects, set the properties and run it's 'addCommand() sub to add the button to the command group
For i = 0 To objList.Length - 1
If i <> 0 Then
buttonAdder = 1
End If
With objList(i)
buttonImage = .ButtonPicture
g.DrawImage(buttonImage, New Point(i * 16, 0))
buttonImage = Nothing
.ButtonPosition = -1
.Commandgroup = cmdGroup
.SwApp = iSwApp
.ToolBarOption = menuToolbarOption
.BtnUserID = i + 1000
.ButtonImageListIndex = i
.AddCommand()
End With
Next
'save the new imagelist bitmap
ImageList.Save(picLoc)
'set the command group icon list to the new imageList bitmap
cmdGroup.LargeIconList = picLoc
cmdGroup.SmallIconList = picLoc
cmdGroup.LargeMainIcon = picLoc
cmdGroup.SmallMainIcon = picLoc
'active the command group
cmdGroup.Activate()
'loop through the command group and get the commandID's assigned by solidworks. add the id's to the button objects so we can reference them later
For i = 0 To cmdGroup.NumberOfGroupItems - 1
id = cmdGroup.CommandID(i)
objList(i).commandID = id
Next
End Sub
Public Sub RemoveCommandMgr()
Try
iCmdMgr.RemoveCommandGroup(mainCmdGroupID)
Catch e As Exception
End Try
End Sub
Function CompareIDs(ByVal storedIDs() As Integer, ByVal addinIDs() As Integer) As Boolean
Dim storeList As New List(Of Integer)(storedIDs)
Dim addinList As New List(Of Integer)(addinIDs)
addinList.Sort()
storeList.Sort()
If Not addinList.Count = storeList.Count Then
Return False
Else
For i As Integer = 0 To addinList.Count - 1
If Not addinList(i) = storeList(i) Then
Return False
End If
Next
End If
Return True
End Function
#End Region
#Region "UI Callbacks"
'this is the sub that is run when any addin button is pressed
Sub callback()
'loop through the button objects and find the one that has a command id that matches the id of the button that was just pressed
For i = 0 To objList.Length - 1
If objList(i).commandID = commandID Then
'once the object is found run it's buttonCallback() sub
objList(i).ButtonCallBack()
Exit For
End If
Next
End Sub
#End Region
#Region "Event Methods"
Sub AttachEventHandlers()
AttachSWEvents()
End Sub
Sub AttachSWEvents()
Try
'This event will fire every time a solidworks button is pressed
AddHandler iSwApp.CommandOpenPreNotify, AddressOf Me.SldWorks_CommandOpenPreNotify
Catch e As Exception
Console.WriteLine(e.Message)
End Try
End Sub
Sub DetachSWEvents()
Try
RemoveHandler iSwApp.CommandOpenPreNotify, AddressOf Me.SldWorks_CommandOpenPreNotify
Catch e As Exception
Console.WriteLine(e.Message)
End Try
End Sub
Function SldWorks_CommandOpenPreNotify(ByVal command As Integer, ByVal userCommand As Integer) As Integer
'This is how I determine what button has been pressed
commandID = userCommand
End Function
#End Region
End Class
Here's the code for the button template:
'Created by JVC 9/12.
'Once this class is finished, compile it to the button folder located in the addIn manager folder
'current location is C:\SolidWorks Data\TDS\Add-Ins\TDS AddIn Manager\Buttons
Imports System
Imports System.Drawing
Imports SolidWorks.Interop.sldworks
Imports SolidWorksTools
Imports SolidWorks.Interop.swconst
Imports SolidWorks.Interop.swpublished
'Change the name of the class to something meaningful to your new button. You must also change the Assembly Name in Project>Properties, the name of your project (in solution explorer),
'and the name of the .vb file to be EXACTLY the same as the name of your class. Otherwise, this will not be loaded by the addin manager. You must also rename the .bmp file
'in the solution explorer to the same name as the class
Public Class AddInButton
#Region "Required Variables"
'all of these variables are required by the AddIn Manager, do not remove any of them
Dim WithEvents iSwApp As SldWorks
Dim cmdGroup As CommandGroup
Dim menuToolbarOption As Integer
Dim cmdIndex As Integer
Dim userID As String
Dim cmdID As Integer
Dim imageIndex As Integer
Dim callbackName As String = "callback"
#End Region
#Region "Required Properties"
'All of these properties are required by the addin manager, do not remove any of them
WriteOnly Property BtnUserID As String
Set(value As String)
userID = value
End Set
End Property
WriteOnly Property ButtonPosition As Integer
Set(value As Integer)
cmdIndex = value
End Set
End Property
WriteOnly Property ToolBarOption As Integer
Set(value As Integer)
menuToolbarOption = value
End Set
End Property
WriteOnly Property Commandgroup() As CommandGroup
Set(value As CommandGroup)
cmdGroup = value
End Set
End Property
Property SwApp() As SldWorks
Get
Return iSwApp
End Get
Set(value As SldWorks)
iSwApp = value
End Set
End Property
Property CommandID As Integer
Get
Return cmdID
End Get
Set(value As Integer)
cmdID = value
End Set
End Property
WriteOnly Property ButtonImageListIndex As Integer
Set(value As Integer)
imageIndex = value
End Set
End Property
#End Region
'this property is also required but must be updated to locate your new button image bmp
Public ReadOnly Property ButtonPicture As Bitmap
Get
'don't forget to change the name of the bmp here
Dim picture As New Bitmap(My.Application.Info.DirectoryPath & "\AddInButton.bmp")
Return picture
End Get
End Property
'this is the sub that is called by the addin manager to add this button to the toolbar. Update the text strings to be something meaningful
'don't change anything else
Public Sub AddCommand()
cmdGroup.AddCommandItem2("Addin Button Template Name", cmdIndex, "Addin button template hint", "addin button template tooltip", imageIndex, callbackName, "", userID, menuToolbarOption)
End Sub
#Region "Executed Callbacks"
Public Sub ButtonCallBack()
'this is where you put your code to make your button do something
End Sub
#End Region
End Class
Enjoy!
Jason
SolidworksApi macros