/// <summary>
        /// Runs an function and catches any exceptions thrown
        /// wrapping and rethrowing them as a <see cref="SolidDnaException"/>
        /// </summary>
        /// <param name="func">The function to run</param>
        /// <param name="errorTypeCode">The <see cref="SolidDnaErrorTypeCode"/> to wrap the exception in</param>
        /// <param name="errorCode">The <see cref="SolidDnaErrorCode"/> to wrap the exception in</param>
        /// <param name="errorDescription">The description of the error if thrown</param>
        public static T Wrap <T>(Func <T> func, SolidDnaErrorTypeCode errorTypeCode, SolidDnaErrorCode errorCode, string errorDescription)
        {
            try
            {
                return(func());
            }
            catch (Exception ex)
            {
                // Create the SolidDNA exception
                var error = new SolidDnaException(SolidDnaErrors.CreateError(
                                                      errorTypeCode,
                                                      errorCode,
                                                      errorDescription), ex);

                // If it should just be logged and ignored, log it
                if (SolidDnaEnvironment.LogAndIgnoreUncaughtExceptions)
                {
                    // Log the error
                    Logger.Log($"SolidDNA Exception created. {error.SolidDnaError?.ToString()}");
                    if (error.InnerException != null)
                    {
                        Logger.Log($"Inner Exception: { error.InnerException.GetErrorMessage()}");
                    }

                    return(default(T));
                }
                // Otherwise, throw
                else
                {
                    throw error;
                }
            }
        }
Example #2
0
        /// <summary>
        /// Sets the material for the model
        /// </summary>
        /// <param name="material">The material</param>
        /// <param name="configuration">The configuration to set the material on, null for the default</param>
        ///
        public void SetMaterial(Material material, string configuration = null)
        {
            // Wrap any error
            SolidDnaErrors.Wrap(() =>
            {
                // Make sure we are a part
                if (!this.IsPart)
                {
                    throw new InvalidOperationException(Localization.GetString("SolidWorksModelSetMaterialModelNotPartError"));
                }

                // If the material is null, remove the material
                if (material == null || !material.DatabaseFileFound)
                {
                    this.AsPart().SetMaterialPropertyName2(string.Empty, string.Empty, string.Empty);
                }
                // Otherwise set the material
                else
                {
                    this.AsPart().SetMaterialPropertyName2(configuration, material.Database, material.Name);
                }
            },
                                SolidDnaErrorTypeCode.SolidWorksModel,
                                SolidDnaErrorCode.SolidWorksModelSetMaterialError,
                                Localization.GetString("SolidWorksModelSetMaterialError"));
        }
        /// <summary>
        /// Called after a file has finished opening
        /// </summary>
        /// <param name="filename">The filename to the file being opened</param>
        /// <returns></returns>
        private int FileOpenPostNotify(string filename)
        {
            // Wrap any error
            SolidDnaErrors.Wrap(() =>
            {
                // If this is the file we were opening...
                if (string.Equals(filename, mFileLoading, StringComparison.OrdinalIgnoreCase))
                {
                    // File has been loaded
                    // So clear loading flag
                    mFileLoading = null;

                    // And update all properties and models
                    this.ReloadActiveModelInformation();

                    // Inform listeners
                    this.FileOpened(filename, mActiveModel);
                }
            },
                                SolidDnaErrorTypeCode.SolidWorksApplication,
                                SolidDnaErrorCode.SolidWorksApplicationFilePostOpenError,
                                Localization.GetString("SolidWorksApplicationFilePostOpenError"));

            // NOTE: 0 is OK, anything else is an error
            return(0);
        }
        /// <summary>
        /// Called when the active model has changed
        /// </summary>
        /// <returns></returns>
        private int ActiveModelChanged()
        {
            // Wrap any error
            SolidDnaErrors.Wrap(() =>
            {
                // If we are currently loading a file...
                if (mFileLoading != null)
                {
                    // Chcek the active document
                    using (var activeDoc = new Model((ModelDoc2)mBaseObject.ActiveDoc))
                    {
                        // If this is the same file that is currently being loaded, ignore this event
                        if (activeDoc != null && string.Equals(mFileLoading, activeDoc.FilePath, StringComparison.OrdinalIgnoreCase))
                        {
                            return;
                        }
                    }
                }

                // If we got here, it isn't the current document so reload the data
                this.ReloadActiveModelInformation();
            },
                                SolidDnaErrorTypeCode.SolidWorksApplication,
                                SolidDnaErrorCode.SolidWorksApplicationActiveModelChangedError,
                                Localization.GetString("SolidWorksApplicationActiveModelChangedError"));

            // NOTE: 0 is OK, anything else is an error
            return(0);
        }
        /// <summary>
        /// Create a command group from a list of <see cref="CommandManagerItem"/> items
        /// </summary>
        /// <param name="title">Name of the CommandGroup to create (see Remarks)</param>
        /// <param name="items">The command items to add</param>
        /// <param name="iconListsPath">The icon list absolute path based on a string format of the absolute path to the icon list images, replacing {0} with the size.
        ///     For example C:\Folder\myiconlist{0}.png</param>
        /// <param name="tooltip">Tool tip for the CommandGroup</param>
        /// <param name="hint">Text displayed in SOLIDWORKS status bar when a user's mouse pointer is over the CommandGroup</param>
        /// <param name="position">Position of the CommandGroup in the CommandManager for all document templates.
        /// NOTE: Specify 0 to add the CommandGroup to the beginning of the CommandManager, or specify -1 to add it to the end of the CommandManager.
        /// NOTE: You can also use ICommandGroup::MenuPosition to control the position of the CommandGroup in specific document templates.</param>
        /// <param name="ignorePreviousVersion">True to remove all previously saved customization and toolbar information before creating a new CommandGroup, false to not.
        /// Call CommandManager.GetGroupDataFromRegistry before calling this method to determine how to set IgnorePreviousVersion. Set IgnorePreviousVersion to true to prevent SOLIDWORKS from saving the current toolbar setting to the registry, even if there is no previous version.</param>
        /// <param name="hasMenu">Whether the CommandGroup should appear in the Tools dropdown menu.</param>
        /// <param name="hasToolbar">Whether the CommandGroup should appear in the Command Manager and as a separate toolbar.</param>
        /// <returns></returns>
        public CommandManagerGroup CreateCommands(string title, List <CommandManagerItem> items, string iconListsPath = "", string tooltip = "", string hint = "", int position = -1, bool ignorePreviousVersion = true, bool hasMenu = true, bool hasToolbar = true)
        {
            // Wrap any error creating the taskpane in a SolidDna exception
            return(SolidDnaErrors.Wrap(() =>
            {
                // Lock the list
                lock (mCommandGroups)
                {
                    // Create the command group
                    var group = CreateCommandGroup(title, items, tooltip, hint, position, ignorePreviousVersion, hasMenu, hasToolbar);

                    // Set icon list
                    group.SetIconLists(iconListsPath);

                    // Create the group
                    group.Create(this);

                    // Add this group to the list
                    mCommandGroups.Add(group);

                    // Return the group
                    return group;
                }
            },
                                       SolidDnaErrorTypeCode.SolidWorksCommandManager,
                                       SolidDnaErrorCode.SolidWorksCommandGroupCreateError,
                                       Localization.GetString("ErrorSolidWorksCommandGroupAddError")));
        }
        /// <summary>
        /// Gets the current SolidWorks version information
        /// </summary>
        /// <returns></returns>
        protected SolidWorksVersion GetSolidWorksVersion()
        {
            // Wrap any error
            return(SolidDnaErrors.Wrap(() =>
            {
                // Get version string (such as 23.2.0 for 2015 SP2.0)
                var revisionNumber = mBaseObject.RevisionNumber();

                // Get revision string (such as sw2015_SP20)
                string revisionString;

                // Get build number (such as d150130.002)
                string buildNumber;

                // Get the hotfix string
                string hotfixString;

                mBaseObject.GetBuildNumbers2(out revisionString, out buildNumber, out hotfixString);

                return new SolidWorksVersion
                {
                    RevisionNumber = revisionNumber,
                    Revision = revisionString,
                    BuildNumber = buildNumber,
                    Hotfix = hotfixString
                };
            },
                                       SolidDnaErrorTypeCode.SolidWorksApplication,
                                       SolidDnaErrorCode.SolidWorksApplicationVersionError,
                                       Localization.GetString("SolidWorksApplicationVersionError")));
        }
        /// <summary>
        /// Set's all icon lists based on a string format of the absolute path to the icon list images, replacing {0} with the size.
        /// For example C:\Folder\myiconlist{0}.png would look for all sizes such as
        /// C:\Folder\myiconlist20.png
        /// C:\Folder\myiconlist32.png
        /// C:\Folder\myiconlist40.png
        /// ... and so on
        /// </summary>
        /// <param name="pathFormat">The absolute path, with {0} used to replace with the icon size</param>
        public void SetIconLists(string pathFormat)
        {
            // Make sure we have something
            if (string.IsNullOrWhiteSpace(pathFormat))
            {
                return;
            }

            // Make sure the path format contains "{0}"
            if (!pathFormat.Contains("{0}"))
            {
                throw new SolidDnaException(SolidDnaErrors.CreateError(
                                                SolidDnaErrorTypeCode.SolidWorksCommandManager,
                                                SolidDnaErrorCode.SolidWorksCommandGroupIvalidPathFormatError,
                                                Localization.GetString("ErrorSolidWorksCommandGroupIconListInvalidPathError")));
            }

            // Find 20 image
            var result = string.Format(pathFormat, 20);

            if (File.Exists(result))
            {
                IconList20Path = result;
            }

            // Find 32 image
            result = string.Format(pathFormat, 32);
            if (File.Exists(result))
            {
                IconList32Path = result;
            }

            // Find 40 image
            result = string.Format(pathFormat, 40);
            if (File.Exists(result))
            {
                IconList40Path = result;
            }

            // Find 64 image
            result = string.Format(pathFormat, 64);
            if (File.Exists(result))
            {
                IconList64Path = result;
            }

            // Find 96 image
            result = string.Format(pathFormat, 96);
            if (File.Exists(result))
            {
                IconList96Path = result;
            }

            // Find 128 image
            result = string.Format(pathFormat, 128);
            if (File.Exists(result))
            {
                IconList128Path = result;
            }
        }
Example #8
0
        /// <summary>
        /// Create a command group flyout containing a list of <see cref="CommandManagerItem"/> items
        /// </summary>
        /// <param name="title">Name of the flyout to create</param>
        /// <param name="items">The command items to add</param>
        /// <param name="pathFormat">The icon list absolute path based on a string format of the absolute path to the icon list images, replacing {0} with the size.
        ///     For example C:\Folder\myiconlist{0}.png</param>
        /// <param name="tooltip">Tool tip for the new flyout</param>
        /// <param name="hint">Text displayed in SOLIDWORKS status bar when a user's mouse pointer is over the flyout</param>
        /// <returns></returns>
        public CommandManagerFlyout CreateFlyoutGroup(string title, List <CommandManagerItem> items, string pathFormat, string tooltip = "", string hint = "")
        {
            #region Icons

            // Make sure the path format contains "{0}"
            if (pathFormat == null || !pathFormat.Contains("{0}"))
            {
                throw new SolidDnaException(SolidDnaErrors.CreateError(
                                                SolidDnaErrorTypeCode.SolidWorksCommandManager,
                                                SolidDnaErrorCode.SolidWorksCommandGroupInvalidPathFormatError,
                                                Localization.GetString("ErrorSolidWorksCommandGroupIconListInvalidPathError")));
            }

            var iconListPaths = new Dictionary <int, string>();

            // Fill the dictionary with all paths that exist
            foreach (var iconSize in mIconSizes)
            {
                var path = string.Format(pathFormat, iconSize);
                if (File.Exists(path))
                {
                    iconListPaths.Add(iconSize, path);
                }
            }

            // Get icon paths
            var icons = iconListPaths.Values.ToArray();

            #endregion

            // Create unique callback Id
            var callbackId = Guid.NewGuid().ToString("N");

            // Attempt to create the command flyout
            var unsafeCommandFlyout = BaseObject.CreateFlyoutGroup2(
                mFlyoutIdCount,
                title,
                tooltip,
                hint,
                icons,
                icons,
                $"Callback({callbackId})",
                null);

            // Create managed object
            var flyout = new CommandManagerFlyout(
                unsafeCommandFlyout,
                mFlyoutIdCount++,
                callbackId,
                items,
                title,
                hint, tooltip);

            // Return it
            return(flyout);
        }
Example #9
0
        /// <summary>
        /// Read the material from the model
        /// </summary>
        /// <returns></returns>
        public Material GetMaterial()
        {
            // Wrap any error
            return(SolidDnaErrors.Wrap(() =>
            {
                // Get the Id's
                var idString = mBaseObject.MaterialIdName;

                // Make sure we have some data
                if (idString == null || !idString.Contains("|"))
                {
                    return null;
                }

                // The Id string is split by pipes |
                var ids = idString.Split('|');

                // We need at least the first and second
                // (first is database file name, second is material name)
                if (ids.Length < 2)
                {
                    throw new ArgumentOutOfRangeException(Localization.GetString("SolidWorksModelGetMaterialIdMissingError"));
                }

                // Extract data
                var databaseName = ids[0];
                var materialName = ids[1];

                // See if we have a database file with the same name
                var fullPath = Dna.Application.GetMaterials()?.FirstOrDefault(f => string.Equals(databaseName, Path.GetFileNameWithoutExtension(f.Database), StringComparison.InvariantCultureIgnoreCase));
                var found = fullPath != null;

                // Now we have the file, try and find the material from it
                if (found)
                {
                    var foundMaterial = Dna.Application.FindMaterial(fullPath.Database, materialName);
                    if (foundMaterial != null)
                    {
                        return foundMaterial;
                    }
                }

                // If we got here, the material was not found
                // So fill in as much information as we have
                return new Material
                {
                    Database = databaseName,
                    Name = materialName
                };
            },
                                       SolidDnaErrorTypeCode.SolidWorksModel,
                                       SolidDnaErrorCode.SolidWorksModelGetMaterialError,
                                       Localization.GetString("SolidWorksModelGetMaterialError")));
        }
Example #10
0
 /// <summary>
 /// Adds a control (Windows <see cref="System.Windows.Forms.UserControl"/>) to the taskpane
 /// that has been exposed to COM and has a given ProgId
 /// </summary>
 /// <typeparam name="T">The type of UserControl being created</typeparam>
 /// <param name="progId">The [ProgId()] attribute value adorned on the UserControl class</param>
 /// <param name="licenseKey">The license key (for specific SolidWorks add-in types)</param>
 /// <returns></returns>
 public async Task <T> AddControlAsync <T>(string progId, string licenseKey)
 {
     // Wrap any error creating the taskpane in a SolidDna exception
     return(SolidDnaErrors.Wrap <T>(() =>
     {
         // Attempt to create the taskpane
         return (T)BaseObject.AddControl(progId, licenseKey);
     },
                                    SolidDnaErrorTypeCode.SolidWorksTaskpane,
                                    SolidDnaErrorCode.SolidWorksTaskpaneAddControlError,
                                    await Localization.GetStringAsync("ErrorSolidWorksTaskpaneAddControlError")));
 }
Example #11
0
        /// <summary>
        /// Saves a file to the specified path, with the specified options
        /// </summary>
        /// <param name="savePath">The path of the file to save as</param>
        /// <param name="version">The version</param>
        /// <param name="options">Any save as options</param>
        /// <param name="pdfExportData">The PDF Export data if the save as type is a PDF</param>
        /// <returns></returns>
        public ModelSaveResult SaveAs(string savePath, SaveAsVersion version = SaveAsVersion.CurrentVersion, SaveAsOptions options = SaveAsOptions.None, PdfExportData pdfExportData = null)
        {
            // Start with a successful result
            var results = new ModelSaveResult();

            // Set errors and warnings to none to start with
            var errors   = 0;
            var warnings = 0;

            // Wrap any error
            return(SolidDnaErrors.Wrap(() =>
            {
                // Try and save the model using the SaveAs method
                BaseObject.Extension.SaveAs(savePath, (int)version, (int)options, pdfExportData?.ExportData, ref errors, ref warnings);

                // If this fails, try another way
                if (errors != 0)
                {
                    BaseObject.SaveAs4(savePath, (int)version, (int)options, ref errors, ref warnings);
                }

                // Add any warnings
                results.Warnings = (SaveAsWarnings)warnings;

                // Add any errors
                results.Errors = (SaveAsErrors)errors;

                // If successful, and this is not a new file
                // (otherwise the RCW changes and SolidWorksApplication has to reload ActiveModel)...
                if (results.Successful && HasBeenSaved)
                {
                    // Reload model data
                    ReloadModelData();
                }

                // If we have not been saved, SolidWorks never fires any FileSave events at all
                // so request a refresh of the ActiveModel. That is the best we can do
                // as this RCW is now invalid. If this model is not active when saved then
                // it will simply reload the active models information
                if (!HasBeenSaved)
                {
                    SolidWorksEnvironment.Application.RequestActiveModelChanged();
                }

                // Return result
                return results;
            },
                                       SolidDnaErrorTypeCode.SolidWorksModel,
                                       SolidDnaErrorCode.SolidWorksModelSaveAsError,
                                       Localization.GetString("SolidWorksModelGetMaterialError")));
        }
        /// <summary>
        ///  Called when SolidWorks is idle
        /// </summary>
        /// <returns></returns>
        private int OnIdleNotify()
        {
            // Wrap any error
            SolidDnaErrors.Wrap(() =>
            {
                // Inform listeners
                Idle();
            },
                                SolidDnaErrorTypeCode.SolidWorksApplication,
                                SolidDnaErrorCode.SolidWorksApplicationError,
                                Localization.GetString("SolidWorksApplicationOnIdleNotificationError"));

            // NOTE: 0 is OK, anything else is an error
            return(0);
        }
        /// <summary>
        /// Attempts to find the material from a SolidWorks material database file (sldmat)
        /// If found, returns the full information about the material
        /// </summary>
        /// <param name="database">The full path to the database</param>
        /// <param name="materialName">The material name to find</param>
        /// <returns></returns>
        public Material FindMaterial(string database, string materialName)
        {
            // Wrap any error
            return(SolidDnaErrors.Wrap(() =>
            {
                // Get all materials from the database
                var materials = GetMaterials(database);

                // Return if found the material with the same name
                return materials?.FirstOrDefault(f => string.Equals(f.Name, materialName, StringComparison.InvariantCultureIgnoreCase));
            },
                                       SolidDnaErrorTypeCode.SolidWorksApplication,
                                       SolidDnaErrorCode.SolidWorksApplicationFindMaterialsError,
                                       Localization.GetString("SolidWorksApplicationFindMaterialsError")));
        }
 /// <summary>
 /// Casts the object to a <see cref="ModelDisplayDimension"/>
 /// Check with <see cref="IsDimension"/> first to assure that it is this type
 /// </summary>
 /// <param name="action">The Dimension is passed into this action to be used within it</param>
 public void AsDimension(Action <ModelDisplayDimension> action)
 {
     // Wrap any error
     SolidDnaErrors.Wrap(() =>
     {
         // Create feature
         using (var model = new ModelDisplayDimension((IDisplayDimension)mBaseObject))
         {
             // Run action
             action(model);
         }
     },
                         SolidDnaErrorTypeCode.SolidWorksModel,
                         SolidDnaErrorCode.SolidWorksModelSelectedObjectCastError,
                         Localization.GetString("SolidWorksModelSelectedObjectCastError"));
 }
Example #15
0
 /// <summary>
 /// Gets the <see cref="ModelFeature"/> of the item in the feature tree based on its name
 /// </summary>
 /// <param name="featureName">Name of the feature</param>
 /// <returns>The <see cref="ModelFeature"/> for the named feature</returns>
 public void GetFeatureByName(string featureName, Action <ModelFeature> action)
 {
     // Wrap any error
     SolidDnaErrors.Wrap(() =>
     {
         // Create feature
         using (var model = new ModelFeature((Feature)mBaseObject.FeatureByName(featureName)))
         {
             // Run action
             action(model);
         }
     },
                         SolidDnaErrorTypeCode.SolidWorksModel,
                         SolidDnaErrorCode.SolidWorksModelAssemblyGetFeatureByNameError,
                         Localization.GetString(nameof(SolidDnaErrorCode.SolidWorksModelAssemblyGetFeatureByNameError)));
 }
Example #16
0
        /// <summary>
        /// Get's the command tab for this
        /// </summary>
        /// <param name="type">The type of document to get the tab for. Use only Part, Assembly or Drawing one at a time, otherwise the first found tab gets returned</param>
        /// <param name="title">The title of the command tab to get</param>
        /// <param name="createIfNotExist">True to create the tab if it does not exist</param>
        /// <param name="clearExistingItems">Removes any existing items on the tab if true</param>
        /// <returns></returns>
        public CommandManagerTab GetCommandTab(ModelType type, string title, bool createIfNotExist = true, bool clearExistingItems = true)
        {
            // Try and get the tab
            var unsafeTab = mBaseObject.GetCommandTab((int)type, title);

            // If we did not get it, just ignore
            if (unsafeTab == null && !createIfNotExist)
            {
                return(null);
            }

            // If we want to remove any previous tabs...
            while (clearExistingItems && unsafeTab != null)
            {
                // Remove it
                mBaseObject.RemoveCommandTab(unsafeTab);

                // Clean COM object
                Marshal.ReleaseComObject(unsafeTab);

                // Try and get another
                unsafeTab = mBaseObject.GetCommandTab((int)type, title);
            }

            // Create it if it doesn't exist
            if (unsafeTab == null)
            {
                unsafeTab = mBaseObject.AddCommandTab((int)type, title);
            }

            // If it's still null, we failed
            if (unsafeTab == null)
            {
                // Throw error
                throw new SolidDnaException(SolidDnaErrors.CreateError(
                                                SolidDnaErrorTypeCode.SolidWorksCommandManager,
                                                SolidDnaErrorCode.SolidWorksCommandGroupCreateTabError,
                                                Localization.GetString("ErrorSolidWorksCommandCreateTabError")));
            }

            // Return tab
            return(new CommandManagerTab(unsafeTab));
        }
Example #17
0
        /// <summary>
        /// Saves a file to the specified path, with the specified options
        /// </summary>
        /// <param name="savePath">The path of the file to save as</param>
        /// <param name="version">The version</param>
        /// <param name="options">Any save as options</param>
        /// <param name="pdfExportData">The PDF Export data if the save as type is a PDF</param>
        /// <returns></returns>
        public ModelSaveResult SaveAs(string savePath, SaveAsVersion version = SaveAsVersion.CurrentVersion, SaveAsOptions options = SaveAsOptions.None, PdfExportData pdfExportData = null)
        {
            // Start with a successful result
            var results = new ModelSaveResult();

            // Set errors and warnings to none to start with
            var errors   = 0;
            var warnings = 0;

            // Wrap any error
            return(SolidDnaErrors.Wrap(() =>
            {
                // Try and save the model using the SaveAs method
                mBaseObject.Extension.SaveAs(savePath, (int)version, (int)options, pdfExportData?.ExportData, ref errors, ref warnings);

                // If this fails, try another way
                if (errors != 0)
                {
                    mBaseObject.SaveAs4(savePath, (int)version, (int)options, ref errors, ref warnings);
                }

                // Add any warnings
                results.Warnings = (SaveAsWarnings)warnings;

                // Add any errors
                results.Errors = (SaveAsErrors)errors;

                // If successful...
                if (results.Successful)
                {
                    // Reload model data
                    ReloadModelData();
                }

                // Return result
                return results;
            },
                                       SolidDnaErrorTypeCode.SolidWorksModel,
                                       SolidDnaErrorCode.SolidWorksModelSaveAsError,
                                       Localization.GetString("SolidWorksModelGetMaterialError")));
        }
        /// <summary>
        /// Attempts to create
        /// </summary>
        /// <param name="iconPath">An absolute path to an icon to use for the taskpane (ideally 37x37px)</param>
        /// <param name="toolTip">The title text to show at the top of the taskpane</param>
        public async Task <Taskpane> CreateTaskpaneAsync(string iconPath, string toolTip)
        {
            // Wrap any error creating the taskpane in a SolidDna exception
            return(SolidDnaErrors.Wrap <Taskpane>(() =>
            {
                // Attempt to create the taskpane
                var comTaskpane = mBaseObject.CreateTaskpaneView2(iconPath, toolTip);

                // If we fail, return null
                if (comTaskpane == null)
                {
                    return null;
                }

                // If we succeed, create SolidDna object
                return new Taskpane(comTaskpane);
            },
                                                  SolidDnaErrorTypeCode.SolidWorksTaskpane,
                                                  SolidDnaErrorCode.SolidWorksTaskpaneCreateError,
                                                  await Localization.GetStringAsync("ErrorSolidWorksTaskpaneCreateError")));
        }
Example #19
0
        /// <summary>
        /// Creates a command group
        /// </summary>
        /// <param name="title">The title</param>
        /// <param name="items">The command items to add</param>
        /// <param name="tooltip">The tool tip</param>
        /// <param name="hint">The hint</param>
        /// <param name="position">Position of the CommandGroup in the CommandManager for all document templates.
        /// NOTE: Specify 0 to add the CommandGroup to the beginning of the CommandMananger, or specify -1 to add it to the end of the CommandManager.
        /// NOTE: You can also use ICommandGroup::MenuPosition to control the position of the CommandGroup in specific document templates.</param>
        /// <param name="ignorePreviousVersion">True to remove all previously saved customization and toolbar information before creating a new CommandGroup, false to not.
        ///     Call CommandManager.GetGroupDataFromRegistry before calling this method to determine how to set IgnorePreviousVersion.
        ///     Set IgnorePreviousVersion to true to prevent SOLIDWORKS from saving the current toolbar setting to the registry, even if there is no previous version.</param>
        /// <param name="hasMenu">Whether the CommandGroup should appear in the Tools dropdown menu.</param>
        /// <param name="hasToolbar">Whether the CommandGroup should appear in the Command Manager and as a separate toolbar.</param>
        /// <returns></returns>
        private CommandManagerGroup CreateCommandGroup(string title, List <CommandManagerItem> items, string tooltip = "", string hint = "", int position = -1, bool ignorePreviousVersion = true, bool hasMenu = true, bool hasToolbar = true)
        {
            // NOTE: We may need to look carefully at this Id if things get removed and re-added based on this SolidWorks note:
            //
            //       If you change the definition of an existing CommandGroup (i.e., add or remove toolbar buttons), you must assign a
            //       new unique user-defined UserID to that CommandGroup. You must perform this action to avoid conflicts with any
            //       previously existing CommandGroups and to allow for backward and forward compatibility of the CommandGroups in your application.
            //

            // Get the next Id
            var id = mCommandGroups.Count == 0 ? 1 : mCommandGroups.Max(f => f.UserId) + 1;

            // Store error code
            var errors = -1;

            // Attempt to create the command group
            var unsafeCommandGroup = mBaseObject.CreateCommandGroup2(id, title, tooltip, hint, position, ignorePreviousVersion, ref errors);

            // Check for errors
            if (errors != (int)swCreateCommandGroupErrors.swCreateCommandGroup_Success)
            {
                // Get enum name
                var errorEnumString = ((swCreateCommandGroupErrors)errors).ToString();

                // Throw error
                throw new SolidDnaException(SolidDnaErrors.CreateError(
                                                SolidDnaErrorTypeCode.SolidWorksCommandManager,
                                                SolidDnaErrorCode.SolidWorksCommandGroupCreateError,
                                                Localization.GetString("ErrorSolidWorksCommandGroupAddError") + $". {errorEnumString}"));
            }

            // Otherwise we got the command group
            var group = new CommandManagerGroup(unsafeCommandGroup, items, id, title, tooltip, hint, hasMenu, hasToolbar);

            // Return it
            return(group);
        }
        /// <summary>
        /// Called before a file has started opening
        /// </summary>
        /// <param name="filename">The filename to the file being opened</param>
        /// <returns></returns>
        private int FileOpenPreNotify(string filename)
        {
            // Don't handle the ActiveModelDocChangeNotify event for file open events
            // - wait until the file is open instead

            // NOTE: We need to check if the variable already has a value because in the case of a drawing
            // we get multiple pre events - one for the drawing, and one for each model in it,
            // we're only interested in the first

            // Wrap any error
            SolidDnaErrors.Wrap(() =>
            {
                if (mFileLoading == null)
                {
                    mFileLoading = filename;
                }
            },
                                SolidDnaErrorTypeCode.SolidWorksApplication,
                                SolidDnaErrorCode.SolidWorksApplicationFilePreOpenError,
                                Localization.GetString("SolidWorksApplicationFilePreOpenError"));

            // NOTE: 0 is OK, anything else is an error
            return(0);
        }
        /// <summary>
        /// Get's a list of all materials in SolidWorks
        /// </summary>
        /// <param name="database">If specified, limits the results to the specified database full path</param>
        public List <Material> GetMaterials(string database = null)
        {
            // Wrap any error
            return(SolidDnaErrors.Wrap(() =>
            {
                // Create an empty list
                var list = new List <Material>();

                // If we are using a specified database, use that
                if (database != null)
                {
                    ReadMaterials(database, ref list);
                }
                else
                {
                    // Otherwise, get all known ones
                    // Get the list of material databases (full paths to sldmat files)
                    var databases = (string[])mBaseObject.GetMaterialDatabases();

                    // Get materials from each
                    if (databases != null)
                    {
                        foreach (var d in databases)
                        {
                            ReadMaterials(d, ref list);
                        }
                    }
                }

                // Order the list
                return list.OrderBy(f => f.DisplayName).ToList();
            },
                                       SolidDnaErrorTypeCode.SolidWorksApplication,
                                       SolidDnaErrorCode.SolidWorksApplicationGetMaterialsError,
                                       Localization.GetString("SolidWorksApplicationGetMaterialsError")));
        }
        /// <summary>
        /// Gets the mass properties of a part/assembly
        /// </summary>
        /// <param name="doNotThrowOnError">If true, don't throw on errors, just return empty mass</param>
        /// <returns></returns>
        public MassProperties GetMassProperties(bool doNotThrowOnError = true)
        {
            // Wrap any error
            return(SolidDnaErrors.Wrap(() =>
            {
                // Make sure we are a part
                if (!Parent.IsPart && !Parent.IsAssembly)
                {
                    if (doNotThrowOnError)
                    {
                        return new MassProperties();
                    }
                    else
                    {
                        throw new InvalidOperationException(Localization.GetString("SolidWorksModelGetMassModelNotPartError"));
                    }
                }

                double[] massProps = null;
                var status = -1;

                //
                // SolidWorks 2016 is the start of support for MassProperties2
                //
                // Tested on 2015 and crashes, so drop-back to lower version for support
                //
                if (SolidWorksEnvironment.Application.SolidWorksVersion.Version < 2016)
                {
                    // NOTE: 2 is best accuracy
                    massProps = (double[])BaseObject.GetMassProperties(2, ref status);
                }
                else
                {
                    // NOTE: 2 is best accuracy
                    massProps = (double[])BaseObject.GetMassProperties2(2, out status, false);
                }

                // Make sure it succeeded
                if (status == (int)swMassPropertiesStatus_e.swMassPropertiesStatus_UnknownError)
                {
                    if (doNotThrowOnError)
                    {
                        return new MassProperties();
                    }
                    else
                    {
                        throw new InvalidOperationException(Localization.GetString("SolidWorksModelGetMassModelStatusFailed"));
                    }
                }
                // If we have no mass, return empty
                else if (status == (int)swMassPropertiesStatus_e.swMassPropertiesStatus_NoBody)
                {
                    return new MassProperties();
                }

                // Otherwise we have the properties so return them
                return new MassProperties(massProps);
            },
                                       SolidDnaErrorTypeCode.SolidWorksModel,
                                       SolidDnaErrorCode.SolidWorksModelGetMassPropertiesError,
                                       Localization.GetString("SolidWorksModelGetMassPropertiesError")));
        }
        /// <summary>
        /// Creates the command group based on it's current children
        /// NOTE: Once created, parent command manager must remove and re-create the group
        /// This group cannot be re-used after creating, any edits will not take place
        /// </summary>
        /// <param name="manager">The command manager that is our owner</param>
        public void Create(CommandManager manager)
        {
            if (mCreated)
            {
                throw new SolidDnaException(SolidDnaErrors.CreateError(
                                                SolidDnaErrorTypeCode.SolidWorksCommandManager,
                                                SolidDnaErrorCode.SolidWorksCommandGroupReActivateError,
                                                Localization.GetString("ErrorSolidWorksCommandGroupReCreateError")));
            }

            #region Set Icons

            //
            // Set the icons
            //
            // NOTE: The order in which you specify the icons must be the same for this property and MainIconList.
            //
            //       For example, if you specify an array of paths to
            //       20 x 20 pixels, 32 x 32 pixels, and 40 x 40 pixels icons for this property
            //       then you must specify an array of paths to
            //       20 x 20 pixels, 32 x 32 pixels, and 40 x 40 pixels icons for MainIconList.</remarks>
            //

            // Set all icon lists
            var icons = GetIconListPaths();

            // 2016+ support
            mBaseObject.IconList = icons.ToArray();

            // <2016 support
            if (icons.Count > 0)
            {
                // Largest icon for this one
                mBaseObject.LargeIconList = icons.Last();

                // The list of icons
                mBaseObject.MainIconList = icons.ToArray();

                // Use the largest available image for small icons too
                mBaseObject.SmallIconList = icons.Last();
            }

            #endregion

            #region Add Items

            // Add items
            this.Items?.ForEach(item => AddCommandItem(item));

            #endregion

            // Activate the command group
            mCreated = mBaseObject.Activate();

            // Get command Ids
            this.Items?.ForEach(item => item.CommandId = mBaseObject.CommandID[item.UniqueId]);

            #region Command Tab

            // Add to parts tab
            var list = this.Items.Where(f => f.TabView != CommandManagerItemTabView.None && f.VisibleForParts).ToList();
            if (list?.Count > 0)
            {
                AddItemsToTab(ModelType.Part, manager, list);
            }

            // Add to assembly tab
            list = this.Items.Where(f => f.TabView != CommandManagerItemTabView.None && f.VisibleForAssemblies).ToList();
            if (list?.Count > 0)
            {
                AddItemsToTab(ModelType.Assembly, manager, list);
            }

            // Add to drawing tab
            list = this.Items.Where(f => f.TabView != CommandManagerItemTabView.None && f.VisibleForDrawings).ToList();
            if (list?.Count > 0)
            {
                AddItemsToTab(ModelType.Drawing, manager, list);
            }

            #endregion

            // If we failed to create, throw
            if (!mCreated)
            {
                throw new SolidDnaException(SolidDnaErrors.CreateError(
                                                SolidDnaErrorTypeCode.SolidWorksCommandManager,
                                                SolidDnaErrorCode.SolidWorksCommandGroupActivateError,
                                                Localization.GetString("ErrorSolidWorksCommandGroupActivateError")));
            }
        }
        /// <summary>
        /// Reads the material database and adds the materials to the given list
        /// </summary>
        /// <param name="database">The database to read</param>
        /// <param name="list">The list to add materials to</param>
        private void ReadMaterials(string database, ref List <Material> list)
        {
            // First make sure the file exists
            if (!File.Exists(database))
            {
                throw new SolidDnaException(
                          SolidDnaErrors.CreateError(
                              SolidDnaErrorTypeCode.SolidWorksApplication,
                              SolidDnaErrorCode.SolidWorksApplicationGetMaterialsFileNotFoundError,
                              Localization.GetString("SolidWorksApplicationGetMaterialsFileNotFoundError")));
            }

            try
            {
                // File should be an XML document, so attempt to read that
                using (var stream = File.Open(database, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    // Try and parse the Xml
                    var xmlDoc = XDocument.Load(stream);

                    // Make sure we got something
                    if (xmlDoc == null)
                    {
                        throw new ArgumentNullException(Localization.GetString("SolidWorksApplicationGetMaterialsXmlNotLoadedError"));
                    }

                    var materials = new List <Material>();

                    // Iterate all classification nodes and inside are the materials
                    xmlDoc.Root.Elements("classification")?.ToList()?.ForEach(f =>
                    {
                        // Get classification name
                        var classification = f.Attribute("name")?.Value;

                        // Iterate all materials
                        f.Elements("material").ToList().ForEach(material =>
                        {
                            // Add them to the list
                            materials.Add(new Material
                            {
                                Database          = database,
                                DatabaseFileFound = true,
                                Classification    = classification,
                                Name        = material.Attribute("name")?.Value,
                                Description = material.Attribute("description")?.Value,
                            });
                        });
                    });

                    // If we found any materials, add them
                    if (materials.Count > 0)
                    {
                        list.AddRange(materials);
                    }
                }
            }
            catch (Exception ex)
            {
                // If we crashed for any reason during parsing, wrap in SolidDna exception
                if (!File.Exists(database))
                {
                    throw new SolidDnaException(
                              SolidDnaErrors.CreateError(
                                  SolidDnaErrorTypeCode.SolidWorksApplication,
                                  SolidDnaErrorCode.SolidWorksApplicationGetMaterialsFileFormatError,
                                  Localization.GetString("SolidWorksApplicationGetMaterialsFileFormatError"),
                                  ex));
                }
            }
        }