PDM Add-in Works When Files Are Closed But Throws Error When Open in SOLIDWORKS

I've developed a PDM add-in that works perfectly when parts/assemblies are closed, but throws an error when the same files are open in SOLIDWORKS.

 

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using EPDM.Interop.epdm;

namespace *********SerializationAddin
{
   [Guid("****************************************************")] // Generate new GUID in production
   [ComVisible(true)]
   public class SerializationAddIn : IEdmAddIn5
   {
       private IEdmVault5 _vault;

       // Hardcoded connection string - to be moved to Credentials table later
       private const string CONNECTION_STRING =
   "Server="*****";Database="*****";User Id="*****";Password="*****";" + "Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;";


       public void GetAddInInfo(ref EdmAddInInfo poInfo, IEdmVault5 poVault, IEdmCmdMgr5 poCmdMgr)
       {
           _vault = poVault;

           poInfo.mbsAddInName = "***** Serialization";
           poInfo.mbsCompany = "*****";
           poInfo.mbsDescription = "Sets MajorGroup, ItemGroup, and Serialization from database.";
           poInfo.mlAddInVersion = 1;
           poInfo.mlRequiredVersionMajor = 31; // PDM 2023
           poInfo.mlRequiredVersionMinor = 0;

           poCmdMgr.AddHook(EdmCmdType.EdmCmd_CardButton);
       }

       public void OnCmd(ref EdmCmd poCmd, ref EdmCmdData[] ppoData)
       {
           if (poCmd.meCmdType != EdmCmdType.EdmCmd_CardButton || ppoData == null || ppoData.Length == 0)
               return;

           // Filter only the "***** Serialization" button
           if (!string.Equals(poCmd.mbsComment, "***** Serialization", StringComparison.OrdinalIgnoreCase))
               return;

           try
           {
               foreach (var row in ppoData)
               {
                   if (_vault == null)
                   {
                       MessageBox.Show("Vault object is null.", "Serialization Add-in",
                           MessageBoxButtons.OK, MessageBoxIcon.Error);
                       continue;
                   }

                   var obj = _vault.GetObject(EdmObjectType.EdmObject_File, row.mlObjectID1);
                   var file = obj as IEdmFile5;

                   if (file == null)
                   {
                       MessageBox.Show("File object is null.", "Serialization Add-in",
                           MessageBoxButtons.OK, MessageBoxIcon.Error);
                       continue;
                   }

                   var name = file.Name ?? "";

                   // Only process SOLIDWORKS parts and assemblies
                   if (!name.EndsWith(".sldprt", StringComparison.OrdinalIgnoreCase) &&
                       !name.EndsWith(".sldasm", StringComparison.OrdinalIgnoreCase))
                   {
                       MessageBox.Show("This add-in only works with SOLIDWORKS parts (.sldprt) and assemblies (.sldasm).",
                           "Serialization Add-in", MessageBoxButtons.OK, MessageBoxIcon.Information);
                       continue;
                   }

                   // Show the serialization form
                   using (var dlg = new SerializationForm(file))
                   {
                       dlg.TopMost = true;
                       dlg.StartPosition = FormStartPosition.CenterScreen;

                       var wrapper = new Win32WindowWrapper(poCmd.mlParentWnd);
                       if (dlg.ShowDialog(wrapper) == DialogResult.OK)
                       {
                           // User clicked OK - values are already written to file

                           // Force card refresh by setting the refresh flag in EdmCmd
                           poCmd.mbsComment = "RefreshCard";

                           MessageBox.Show("Serialization values updated successfully!",
                               "Serialization Add-in", MessageBoxButtons.OK, MessageBoxIcon.Information);
                       }
                   }
               }
           }
           catch (SqlException ex)
           {
               MessageBox.Show(\\\$"Database error: {ex.Message}\\n\\nPlease contact your system administrator.",
                   "Serialization Add-in", MessageBoxButtons.OK, MessageBoxIcon.Error);
           }
           catch (COMException ex)
           {
               MessageBox.Show(\\\$"PDM COM error 0x{ex.ErrorCode:X}: {ex.Message}",
                   "Serialization Add-in", MessageBoxButtons.OK, MessageBoxIcon.Error);
           }
           catch (Exception ex)
           {
               MessageBox.Show(\\\$"Unexpected error: {ex.Message}\\n\\n{ex.StackTrace}",
                   "Serialization Add-in", MessageBoxButtons.OK, MessageBoxIcon.Error);
           }
       }

       #region Helper Classes

       private sealed class Win32WindowWrapper : IWin32Window
       {
           private readonly IntPtr _handle;
           public Win32WindowWrapper(int handle) { _handle = new IntPtr(handle); }
           public IntPtr Handle => _handle;
       }

       #endregion

       #region Serialization Form

       private sealed class SerializationForm : Form
       {
           private readonly IEdmFile5 _file;
           private ComboBox _cboMajorGroup;
           private ComboBox _cboItemGroup;
           private ComboBox _cboSerialization;
           private Button _btnOk;
           private Button _btnCancel;

           private List _majorGroups;
           private List _allItemGroups;
           private List _allSerializations;
           private DataTable _junctionTable;

           public SerializationForm(IEdmFile5 file)
           {
               _file = file;
               InitializeForm();
               LoadDataFromDatabase();
               PopulateMajorGroups();
           }

           private void InitializeForm()
           {
               Text = "Set Item Classification Properties";
               Size = new Size(500, 300);
               FormBorderStyle = FormBorderStyle.FixedDialog;
               MaximizeBox = false;
               MinimizeBox = false;
               StartPosition = FormStartPosition.CenterScreen;

               // Labels and ComboBoxes
               var lblMajorGroup = new Label
               {
                   Text = "Major Group:",
                   Location = new Point(30, 30),
                   Size = new Size(120, 23),
                   TextAlign = ContentAlignment.MiddleRight
               };

               _cboMajorGroup = new ComboBox
               {
                   Location = new Point(160, 30),
                   Size = new Size(280, 23),
                   DropDownStyle = ComboBoxStyle.DropDownList
               };
               _cboMajorGroup.SelectedIndexChanged += CboMajorGroup_SelectedIndexChanged;

               var lblItemGroup = new Label
               {
                   Text = "Item Group:",
                   Location = new Point(30, 80),
                   Size = new Size(120, 23),
                   TextAlign = ContentAlignment.MiddleRight
               };

               _cboItemGroup = new ComboBox
               {
                   Location = new Point(160, 80),
                   Size = new Size(280, 23),
                   DropDownStyle = ComboBoxStyle.DropDownList,
                   Enabled = false
               };
               _cboItemGroup.SelectedIndexChanged += CboItemGroup_SelectedIndexChanged;

               var lblSerialization = new Label
               {
                   Text = "Serialization:",
                   Location = new Point(30, 130),
                   Size = new Size(120, 23),
                   TextAlign = ContentAlignment.MiddleRight
               };

               _cboSerialization = new ComboBox
               {
                   Location = new Point(160, 130),
                   Size = new Size(280, 23),
                   DropDownStyle = ComboBoxStyle.DropDownList,
                   Enabled = false
               };

               // Buttons
               _btnOk = new Button
               {
                   Text = "OK",
                   Location = new Point(250, 200),
                   Size = new Size(90, 30),
                   Enabled = false
               };
               _btnOk.Click += BtnOk_Click;

               _btnCancel = new Button
               {
                   Text = "Cancel",
                   Location = new Point(350, 200),
                   Size = new Size(90, 30),
                   DialogResult = DialogResult.Cancel
               };

               // Add controls to form
               Controls.AddRange(new Control[]
               {
                   lblMajorGroup, _cboMajorGroup,
                   lblItemGroup, _cboItemGroup,
                   lblSerialization, _cboSerialization,
                   _btnOk, _btnCancel
               });

               AcceptButton = _btnOk;
               CancelButton = _btnCancel;
           }

           private void LoadDataFromDatabase()
           {
               try
               {
                   using (var conn = new SqlConnection(CONNECTION_STRING))
                   {
                       conn.Open();

                       // Load MajorGroups
                       using (var cmd = new SqlCommand(
                           "SELECT MajorGroupID, MajorGroupName FROM [MajorGroup] WHERE Deleted = 0 ORDER BY MajorGroupName", conn))
                       using (var reader = cmd.ExecuteReader())
                       {
                           _majorGroups = new List();
                           while (reader.Read())
                           {
                               _majorGroups.Add(new MajorGroupItem
                               {
                                   ID = reader.GetInt32(0),
                                   Name = reader.GetString(1)
                               });
                           }
                       }

                       // Load ItemGroups
                       using (var cmd = new SqlCommand(
                           "SELECT ItemGroupID, ItemGroupName FROM [ItemGroup] WHERE Deleted = 0 ORDER BY ItemGroupName", conn))
                       using (var reader = cmd.ExecuteReader())
                       {
                           _allItemGroups = new List();
                           while (reader.Read())
                           {
                               _allItemGroups.Add(new ItemGroupItem
                               {
                                   ID = reader.GetInt32(0),
                                   Name = reader.GetString(1)
                               });
                           }
                       }

                       // Load Serializations
                       using (var cmd = new SqlCommand(
                           "SELECT SerializationID, SerializationName FROM [Serialization] WHERE Deleted = 0 ORDER BY SerializationName", conn))
                       using (var reader = cmd.ExecuteReader())
                       {
                           _allSerializations = new List();
                           while (reader.Read())
                           {
                               _allSerializations.Add(new SerializationItem
                               {
                                   ID = reader.GetInt32(0),
                                   Name = reader.GetString(1)
                               });
                           }
                       }

                       // Load junction table
                       using (var cmd = new SqlCommand(
                           "SELECT MajorGroupID, ItemGroupID, SerializationID FROM [MajorGroupItemSerial] WHERE Deleted = 0", conn))
                       using (var adapter = new SqlDataAdapter(cmd))
                       {
                           _junctionTable = new DataTable();
                           adapter.Fill(_junctionTable);
                       }
                   }
               }
               catch (Exception ex)
               {
                   MessageBox.Show(\\\$"Error loading data from database:\\n{ex.Message}",
                       "Database Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                   throw;
               }
           }

           private void PopulateMajorGroups()
           {
               _cboMajorGroup.DisplayMember = "Name";
               _cboMajorGroup.ValueMember = "ID";
               _cboMajorGroup.DataSource = _majorGroups;
               _cboMajorGroup.SelectedIndex = -1;
           }

           private void CboMajorGroup_SelectedIndexChanged(object sender, EventArgs e)
           {
               _cboItemGroup.DataSource = null;
               _cboItemGroup.Enabled = false;
               _cboSerialization.DataSource = null;
               _cboSerialization.Enabled = false;
               _btnOk.Enabled = false;

               if (_cboMajorGroup.SelectedValue == null)
                   return;

               int majorGroupId = (int)_cboMajorGroup.SelectedValue;

               // Get valid ItemGroupIDs for this MajorGroup
               var validItemGroupIds = _junctionTable.AsEnumerable()
                   .Where(row => row.Field("MajorGroupID") == majorGroupId)
                   .Select(row => row.Field("ItemGroupID"))
                   .Distinct()
                   .ToList();

               // Filter ItemGroups
               var filteredItemGroups = _allItemGroups
                   .Where(ig => validItemGroupIds.Contains(ig.ID))
                   .ToList();

               if (filteredItemGroups.Count > 0)
               {
                   _cboItemGroup.DisplayMember = "Name";
                   _cboItemGroup.ValueMember = "ID";
                   _cboItemGroup.DataSource = filteredItemGroups;
                   _cboItemGroup.SelectedIndex = -1;
                   _cboItemGroup.Enabled = true;
               }
           }

           private void CboItemGroup_SelectedIndexChanged(object sender, EventArgs e)
           {
               _cboSerialization.DataSource = null;
               _cboSerialization.Enabled = false;
               _btnOk.Enabled = false;

               if (_cboMajorGroup.SelectedValue == null || _cboItemGroup.SelectedValue == null)
                   return;

               int majorGroupId = (int)_cboMajorGroup.SelectedValue;
               int itemGroupId = (int)_cboItemGroup.SelectedValue;

               // Get valid SerializationIDs for this combination
               var validSerializationIds = _junctionTable.AsEnumerable()
                   .Where(row => row.Field("MajorGroupID") == majorGroupId &&
                                 row.Field("ItemGroupID") == itemGroupId)
                   .Select(row => row.Field("SerializationID"))
                   .Distinct()
                   .ToList();

               // Filter Serializations
               var filteredSerializations = _allSerializations
                   .Where(s => validSerializationIds.Contains(s.ID))
                   .ToList();

               if (filteredSerializations.Count > 0)
               {
                   _cboSerialization.DisplayMember = "Name";
                   _cboSerialization.ValueMember = "ID";
                   _cboSerialization.DataSource = filteredSerializations;
                   _cboSerialization.SelectedIndex = -1;
                   _cboSerialization.Enabled = true;

                   // Enable OK button when serialization is selected
                   _cboSerialization.SelectedIndexChanged += (s, ev) =>
                   {
                       _btnOk.Enabled = _cboSerialization.SelectedValue != null;
                   };
               }
           }

           private void BtnOk_Click(object sender, EventArgs e)
           {
               try
               {
                   if (_cboMajorGroup.SelectedValue == null ||
                       _cboItemGroup.SelectedValue == null ||
                       _cboSerialization.SelectedValue == null)
                   {
                       MessageBox.Show("Please select all three values.", "Validation",
                           MessageBoxButtons.OK, MessageBoxIcon.Warning);
                       return;
                   }

                   string majorGroupName = ((MajorGroupItem)_cboMajorGroup.SelectedItem).Name;
                   string itemGroupName = ((ItemGroupItem)_cboItemGroup.SelectedItem).Name;
                   string serializationName = ((SerializationItem)_cboSerialization.SelectedItem).Name;

                   // Get variable enumerator once for all writes
                   dynamic varEnum = _file.GetEnumeratorVariable();
                   if (varEnum == null)
                   {
                       throw new Exception("Could not get variable enumerator.");
                   }

                   try
                   {
                       // Write all three variables at @ configuration
                       varEnum.SetVar("MajorGroup", "@", majorGroupName);
                       varEnum.SetVar("ItemGroup", "@", itemGroupName);
                       varEnum.SetVar("Serialization", "@", serializationName);
                   }
                   catch
                   {
                       // If @ doesn't work, try empty string for file-level
                       varEnum.SetVar("MajorGroup", "", majorGroupName);
                       varEnum.SetVar("ItemGroup", "", itemGroupName);
                       varEnum.SetVar("Serialization", "", serializationName);
                   }

                   // Close and save all changes at once
                   varEnum.CloseFile(true);

                   DialogResult = DialogResult.OK;
                   Close();
               }
               catch (Exception ex)
               {
                   MessageBox.Show(\\\$"Error writing to PDM:\\n{ex.Message}", "Error",
                       MessageBoxButtons.OK, MessageBoxIcon.Error);
               }
           }

           #region Data Classes

           private class MajorGroupItem
           {
               public int ID { get; set; }
               public string Name { get; set; }
           }

           private class ItemGroupItem
           {
               public int ID { get; set; }
               public string Name { get; set; }
           }

           private class SerializationItem
           {
               public int ID { get; set; }
               public string Name { get; set; }
           }

           #endregion
       }

       #endregion
   }
}


 

This is the error message. 

Also my datacard doesn't refresh automatically. Is there any specific method to do that?