10 Replies Latest reply on Feb 15, 2018 10:44 AM by Jacob Corder

    Making a Exposed COM DLL Macro Feature

    Cody Kirsch

      I am trying to create a macro feature a using VB.NET addin and am not having much luck. I have tried both the COM callbacks and .NET add-In callbacks methods described here as well as using some examples I found poking around the form. I am very familiar with making macro features as a VBA macro so I'm guessing there is something that I am unaware of when using .net so hopefully this is easy question.

       

      The code below is just what i have been using to just try and get a feature inserted so there shouldn't be anything else causing an issue. I have the following module and class in separate .vb files in a project called MyProject, which is also the Start Up Project in a Solution. I have actually tried using InsertMacroFeature3 from an addin but know luck with that either.

       

       

       

      In MyModule.vb

      Imports SolidWorks.Interop.sldworks

      Imports SolidWorks.Interop.swconst

       

      Public Module MyModule

       

          Public Sub Main()

              Dim _app As SldWorks = GetObject(, "SldWorks.Application")

              Dim _model As ModelDoc2 = _app.ActiveDoc

              Dim FeatMgr As FeatureManager = _model.FeatureManager

       

              Dim feat As Feature = FeatMgr.InsertMacroFeature3("TestFeature", "MyProject.MacroFeatureClass", Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, swMacroFeatureOptions_e.swMacroFeatureByDefault)

       

              If feat Is Nothing Then MsgBox("Macro Feature Failure")

       

          End Sub

       

      End Module

       

       

      In MacroFeatureClass.vb

      Imports SolidWorks.Interop.swpublished

      Imports SolidWorks.Interop.swconst

       

      <ComClass(MacroFeatureClass.ClassId, MacroFeatureClass.InterfaceId, MacroFeatureClass.EventsId)>

      Public Class MacroFeatureClass

          Implements ISwComFeature

       

          Public Const ClassId As String = "1FEC45A4-8300-4FD2-AFC4-ED4952A6F4F5"

          Public Const InterfaceId As String = "19DEA4FB-46F6-445D-B996-39BACD9B70CA"

          Public Const EventsId As String = "8AF8B870-7455-431C-B5F2-718CCCA1607C"

       

          Public Sub New()

                   MyBase.New()

          End Sub

       

          Public Function Rebuild(ByVal app As Object, ByVal model As Object, ByVal feat As Object) As Object Implements ISwComFeature.Regenerate

                   Return True

          End Function

       

          Public Function Edit(ByVal app As Object, ByVal model As Object, ByVal feat As Object) As Object Implements ISwComFeature.Edit

                   Return True

          End Function

       

          Public Function Security(ByVal app As Object, ByVal model As Object, ByVal feat As Object) As Object Implements ISwComFeature.Security

                   Return swMacroFeatureSecurityOptions_e.swMacroFeatureSecurityByDefault

          End Function

       

      End Class

        • Re: Making a Exposed COM DLL Macro Feature
          Jacob Corder

          another way to test it.

           

          write this

           

          Dim MyCServer as object = CreateObject("MyProject.MacroFeatureClass")

           

          if this works and mycserver is not nothing then your registry values should be good enough for solidworks to find your DLL.

          • Re: Making a Exposed COM DLL Macro Feature
            Artem Taturevych

            Did you run regasm utility with /tlb flag on your macro feature dll?

            • Re: Making a Exposed COM DLL Macro Feature
              Jacob Corder

              YAY Another person who wants to go nuts.

               

              ok to start. i would suggest making a separate project for the MacroFeature COMServer.  basically it should have all of the code in it to execute the regeneration. i do make mine get my addin and communicate to the addin during regeneration. so i violate my own rule.

               

               

              is the namespace of MacroFeatureClass myproject? if not then it needs to be as you are telling it that you want it to regenerate in namespace MyProject Class MacroFeatureClass.

               

              macrofeatureClass needs to have registry keys in HKCR\CLSID\{1FEC45A4-8300-4FD2-AFC4-ED4952A6F4F5}\InProcServer32\CodeBase

              Value should be file:///PathToYourDLL

              (Default) should be MSCOREE.DLL

               

              verify that these keys exist. i assume that they will because it is a COM Class

               

              weird that this was moved to a new topic.  

                • Re: Making a Exposed COM DLL Macro Feature
                  Cody Kirsch

                  Not sure if I'm glad that I'm not the only one who has lost it trying to get this to work or disappointed that its not as simple as it is in VBA. Good thing I went nuts making macros long ago!

                   

                  Anyway, not sure why it didn't occur to me before but i didn't have the dll registered so that is probably my issue.

                  This method seems like it might make it difficult to work out the bugs though. If its a registered dll I cant make changes to the dll without having to close SolidWorks once there is a macro feature in a part right? If so the .NET add-in callbacks method seems better for testing. But I am also unable to get that to work either using basically the same code but not using a COM Class. I get that the feature would have to be deleted and reinserted for changes to be applied but this is preferable to closing and reopening SolidWorks every time.

                    • Re: Making a Exposed COM DLL Macro Feature
                      Jacob Corder

                      not true.  i use visual studio 2017 and as long as you DO NOT embed interop Types, you can edit live code while running it.  you have to launch solidworks through the play button(Debug) in visual studio. then you can edit, it will recompile and continue on. its quite nice and i dont know when the capability became possible.  i only recently descovered it.

                      you cannot have Enable Optimizations set in Advanced Compile Options either.

                       

                      i add macrofeatures, edit the comserver, then add more,  edit some more.

                       

                      also the COM Server DOES NOT embed in the feature.  you can change the COM Server and the rebuild will behave as told to by the new comserver.

                       

                      i can update my com server to add new functionality, and every feature will obey these rules as it is not embedded.  one place to modify the code.

                       

                      it is howerver suggested i believe that different types of macrofeatures use a different comserver, or a different class in the COMServer project.

                       

                      like MyComServer.ThisFeature or

                      MyCOMServer.ThatFeature or

                      MYCOMServer.OtherFeature.

                       

                      i do not do this, i set a parameter in each feature that tells my comserver what the feature is. it enables my features to adapt and become any other type of feature.

                      here is something that is created by my comserver. every feature is a macrofeature.

                       

                      you can even redeploy your comserver and the rebuild will obey the new DLL File.  (read up on strong name versioning in the api help also)

                        • Re: Making a Exposed COM DLL Macro Feature
                          Cody Kirsch

                          Got it! Thanks for all the info Jacob!

                          After rereading the ISwComFeature info on the API help page I saw that I didn't have the COM class visible so was just missing <System.Runtime.InteropServices.ComVisibleAttribute(True)> when declaring the class.

                           

                          it is howerver suggested i believe that different types of macrofeatures use a different comserver, or a different class in the COMServer project.

                           

                          like MyComServer.ThisFeature or

                          MyCOMServer.ThatFeature or

                          MYCOMServer.OtherFeature.

                           

                          i do not do this, i set a parameter in each feature that tells my comserver what the feature is. it enables my features to adapt and become any other type of feature.

                          I thought of doing this as well. The only advantage I can think of to this approach is reducing the redundant Rebuild and Edit functions in feature classes as I just pass the feature object from these callbacks to the classes that handle the edit and rebuild anyway so all those function are essentially going to be the same. Have you found any other advantages/disadvantages to doing it this way?

                           

                           

                          Working Code:

                          MacroFeatureClass-

                          Imports SolidWorks.Interop.swpublished

                          Imports SolidWorks.Interop.swconst

                           

                          <System.Runtime.InteropServices.ComVisibleAttribute(True)>

                          <ComClass(MacroFeatureClass.ClassId, MacroFeatureClass.InterfaceId, MacroFeatureClass.EventsId)>

                          Public Class MacroFeatureClass

                              Implements ISwComFeature

                           

                              Public Const ClassId As String = "1FEC45A4-8300-4FD2-AFC4-ED4952A6F4F5"

                              Public Const InterfaceId As String = "19DEA4FB-46F6-445D-B996-39BACD9B70CA"

                              Public Const EventsId As String = "8AF8B870-7455-431C-B5F2-718CCCA1607C"

                           

                              Public Sub New()

                                  MyBase.New()

                              End Sub

                           

                              Function Rebuild(ByVal app As Object, ByVal model As Object, ByVal feat As Object) As Object Implements ISwComFeature.Regenerate

                                  Return True

                              End Function

                           

                              Function Edit(ByVal app As Object, ByVal model As Object, ByVal feat As Object) As Object Implements ISwComFeature.Edit

                                  Return True

                              End Function

                           

                              Function Security(ByVal app As Object, ByVal model As Object, ByVal feat As Object) As Object Implements ISwComFeature.Security

                                  Return swMacroFeatureSecurityOptions_e.swMacroFeatureSecurityByDefault

                              End Function

                           

                          End Class

                           

                          Inserting Example Modual

                          Public Module MyModule

                              Public Sub Main()

                                  Dim app As SldWorks = GetObject(, "SldWorks.Application")

                                  Dim _model As ModelDoc2 = app.ActiveDoc

                                  Dim FeatMgr As FeatureManager = _model.FeatureManager

                                  Dim feat As Feature = FeatMgr.InsertMacroFeature3("TestFeature", "MyProject.MacroFeatureClass",

                                      Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, swMacroFeatureOptions_e.swMacroFeatureByDefault)

                              End Sub

                          End Module

                            • Re: Making a Exposed COM DLL Macro Feature
                              Jacob Corder

                              I thought of doing this as well. The only advantage I can think of to this approach is reducing the redundant Rebuild and Edit functions in feature classes as I just pass the feature object from these callbacks to the classes that handle the edit and rebuild anyway so all those function are essentially going to be the same. Have you found any other advantages/disadvantages to doing it this way?

                               

                              i never found a reason to do this. mainly because i like all of my code in one spot and to be able to reuse code alot.

                              you can always reset the program id to something else later if you want.  just keep it in one project like i do.

                              Actually solidworks dLL SLDFUNCFEAT.DLL is their comserver for a few of their internal macrofeatures.

                               

                              Got it! Thanks for all the info Jacob!

                              After rereading the ISwComFeature info on the API help page I saw that I didn't have the COM class visible so was just missing <System.Runtime.InteropServices.ComVisibleAttribute(True)> when declaring the class.

                              i saw that but i assumed your project was set to COMVisible. i actually dont have COMVisible in my class now that i look at it.  my comserver project has it. it must inherit from the project? hmmm. in my defense, I'm not a programmer.

                               

                              read this also

                              2018 SOLIDWORKS API Help - Macro Features and Strong Name Versioning

                              at the bottom, if you add the registry key to the solidworks version you are running it will help sw find your comserver a little faster i think.  it does check this registry key i am certain.

                              I am not sure this is exactly what to do, but i do add this registry key like below, actually my comserver does this at runtime.

                              HCLM/SOFTWARE/SOLIDWORKS/SOLIDWORKS XXXX/MacroFeatures/SldFuncFeat.LipGrooveFeature/CurVer  = "MyProject.MacroFeatureClass" ( No need for strong name versioning if you dont

                              want)HCLM/SOFTWARE/SOLIDWORKS/SOLIDWORKS 2015/MacroFeatures/SldFuncFeat.LipGrooveFeature/CurVer = "MyProject.MacroFeatureClass"

                                • Re: Making a Exposed COM DLL Macro Feature
                                  Cody Kirsch

                                  Alright, so I have the macro feature inserting reliably now! Just to help others out, I was having a problem with the MacroFeatureClass being in its own project. I had to add a reference to MyProject in main add in so the DLL would get made, but that gave me a circular reference so I just put MacroFeatureClass under its own namespace in the main addin. But now there is another issue, it will not create a feature if the ParamNames, ParamTypes, and ParamValues parameters are anything but empty arrays of long/strings. I know that InsertMacroFeature3 will fail if all the lengths are not the same and the data types don't match up with the values but I cant even get one parameter value to work. Is there anything different from how InsertMacroFeature3 works from a VBA version besides the callbacks?

                                    • Re: Making a Exposed COM DLL Macro Feature
                                      Jacob Corder

                                      be careful with adding Class after any class because thats actually a thing in COM.  like a in the solidworks DLLs, Face2 also has a Face2Class which i believe is the non interface portion

                                       

                                      sorry i didnt notice that before

                                      • Re: Making a Exposed COM DLL Macro Feature
                                        Jacob Corder

                                                            Dim BaseName as string = "YOURBASENAME"

                                                            Dim ParamNames(1) As String

                                                            Dim ParamVals(1) As String

                                                            Dim ParamTypes(1) As Integer

                                                            Dim IconFiles(2) As String

                                                            Dim NameObj As Object = Nothing

                                                            Dim TypesObj As Object = Nothing

                                                            Dim ValsObj As Object = Nothing

                                                            Dim DimTypes As Object = Nothing

                                                            Dim DimVals As Object = Nothing

                                                            Dim opts As Integer = swMacroFeatureOptions_e.swMacroFeatureAlwaysAtEnd

                                         

                                         

                                                            ParamNames(0) = JEMFeatures.CFeatureType

                                                            ParamNames(1) = JEMFeatures.CFeatureVersion

                                                            ParamVals(0) = MacroFeatureType_e.Appearance

                                                            ParamVals(1) = VersionAppearanceFeature

                                                            ParamTypes(0) = swMacroFeatureParamType_e.swMacroFeatureParamTypeInteger

                                                            ParamTypes(1) = swMacroFeatureParamType_e.swMacroFeatureParamTypeInteger

                                                            TypesObj = ParamTypes

                                                            NameObj = ParamNames

                                                            ValsObj = ParamVals

                                         

                                         

                                                            Dim ProgID As String = "COMSERVERNAMESPACE.COMSERVERCLASS"

                                                            IconFiles(0) = "SOMETHING"

                                                            IconFiles(1) = "SOMETHING"

                                                            IconFiles(2) = "SOMETHING"

                                         

                                        FeatMgr.InsertMacroFeature3(BaseName, ProgID , Nothing, (NameObj), (TypesObj), (ValsObj), DimTypes, DimVals, Nothing, IconFiles, opts)

                                         

                                        you need to set the names types and vals as objects after the array has been set.