using OfficeOpenXml; using SolidWorks.Interop.sldworks; using SolidWorks.Interop.swconst; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; namespace ExportDXF.Forms { public partial class MainForm : Form { private SldWorks sldWorks; private BackgroundWorker worker; private DrawingDoc templateDrawing; private DateTime timeStarted; private IViewFlipDecider viewFlipDecider; public MainForm() { InitializeComponent(); worker = new BackgroundWorker(); worker.WorkerSupportsCancellation = true; worker.DoWork += Worker_DoWork; worker.RunWorkerCompleted += Worker_RunWorkerCompleted; viewFlipDecider = new ViewFlipDecider(); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); button1.Enabled = false; var task = new Task(ConnectToSolidWorks); task.ContinueWith((t) => { Invoke(new MethodInvoker(() => { SetActiveDocName(); button1.Enabled = true; })); }); task.Start(); } private void button1_Click(object sender, EventArgs e) { if (worker.IsBusy) { worker.CancelAsync(); return; } worker.RunWorkerAsync(); } private void button2_Click(object sender, EventArgs e) { } private void Worker_DoWork(object sender, DoWorkEventArgs e) { timeStarted = DateTime.Now; sldWorks.UserControl = false; sldWorks.ActiveModelDocChangeNotify -= SldWorks_ActiveModelDocChangeNotify; Invoke(new MethodInvoker(() => { button1.Image = Properties.Resources.stop_alt; if (richTextBox1.TextLength != 0) richTextBox1.AppendText("\n\n"); })); var model = sldWorks.ActiveDoc as ModelDoc2; Print("Started at " + DateTime.Now.ToShortTimeString()); DetermineModelTypeAndExportToDXF(model); sldWorks.UserControl = true; } private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { Invoke(new MethodInvoker(() => { if (templateDrawing != null) { sldWorks.CloseDoc(((ModelDoc2)templateDrawing).GetTitle()); templateDrawing = null; } button1.Image = Properties.Resources.play; })); var duration = DateTime.Now - timeStarted; Print("Run time: " + duration.ToReadableFormat()); Print("Done.", Color.Green); sldWorks.ActiveModelDocChangeNotify += SldWorks_ActiveModelDocChangeNotify; } private int SldWorks_ActiveModelDocChangeNotify() { if (InvokeRequired) { Invoke(new MethodInvoker(() => { SetActiveDocName(); })); } else { SetActiveDocName(); } return 1; } private void Print(string s) { Invoke(new MethodInvoker(() => { richTextBox1.AppendText(s + System.Environment.NewLine); richTextBox1.ScrollToCaret(); })); } private void Print(string s, Color color) { Invoke(new MethodInvoker(() => { richTextBox1.AppendText(s + System.Environment.NewLine, color); richTextBox1.ScrollToCaret(); })); } private void ConnectToSolidWorks() { Print("Connecting to SolidWorks, this may take a minute..."); sldWorks = Activator.CreateInstance(Type.GetTypeFromProgID("SldWorks.Application")) as SldWorks; if (sldWorks == null) { MessageBox.Show("Failed to connect to SolidWorks."); Application.Exit(); return; } sldWorks.Visible = true; sldWorks.ActiveModelDocChangeNotify += SldWorks_ActiveModelDocChangeNotify; Print("Ready", Color.Green); } private void SetActiveDocName() { var model = sldWorks.ActiveDoc as ModelDoc2; textBox1.Text = model != null ? model.GetTitle() : ""; } private void DetermineModelTypeAndExportToDXF(ModelDoc2 model) { if (model is PartDoc) { Print("Active document is a Part"); ExportToDXF(model as PartDoc); } else if (model is DrawingDoc) { Print("Active document is a Drawing"); ExportToDXF(model as DrawingDoc); } else if (model is AssemblyDoc) { Print("Active document is a Assembly"); ExportToDXF(model as AssemblyDoc); } } private void ExportToDXF(DrawingDoc drawing) { Print("Finding BOM tables..."); var bomTables = GetBomTables(drawing); if (bomTables.Count == 0) { Print("Error: Bill of materials not found.", Color.Red); return; } Print("Found " + bomTables.Count); Print(""); foreach (var bom in bomTables) { if (worker.CancellationPending) return; Print(bom.BomFeature.Name); Print("Fetching components..."); var items = GetItems(bom); Print("Found " + items.Count); Print(""); ExportToDXF(items); } } private void ExportToDXF(PartDoc part) { var prefix = textBox2.Text; var model = part as ModelDoc2; var dir = UserSelectFolder(); if (dir == null) { Print("Cancelled\n", Color.Red); return; } if (dir == null) return; var title = model.GetTitle().Replace(".SLDPRT", ""); var config = model.ConfigurationManager.ActiveConfiguration.Name; var name = config.ToLower() == "default" ? title : string.Format("{0} [{1}]", title, config); var savePath = Path.Combine(dir, prefix + name + ".dxf"); SavePartToDXF(part, savePath); } private void ExportToDXF(AssemblyDoc assembly) { Print("Fetching components..."); var items = GetItems(assembly, false); Print("Found " + items.Count); Print(""); ExportToDXF(items); } private void ExportToDXF(IEnumerable items) { var savePath = UserSelectFolder(); var prefix = textBox2.Text; if (savePath == null) { Print("Canceled\n", Color.Red); return; } templateDrawing = CreateDrawing(); Print(""); foreach (var item in items) { if (worker.CancellationPending) break; item.ItemNo = prefix + item.ItemNo; var fileName = item.ItemNo + ".dxf"; var savepath = Path.Combine(savePath, fileName); var model = item.Component.GetModelDoc2() as ModelDoc2; var part = model as PartDoc; var config = item.Component.ReferencedConfiguration; var sheetMetal = model.GetFeatureByTypeName("SheetMetal"); if (sheetMetal != null) { var kfactor = sheetMetal.GetDimension("D2")?.GetValue2(config); if (kfactor.HasValue) item.KFactor = kfactor.Value; var thickness = sheetMetal.GetDimension("Thickness")?.GetValue2(config); if (thickness.HasValue) item.Thickness = thickness.Value; } var db = string.Empty; item.Material = part.GetMaterialPropertyName2(config, out db); if (part == null) continue; SavePartToDXF(part, config, savepath); Application.DoEvents(); } var bomFile = Path.Combine(savePath, "BOM.xlsx"); CreateBOMExcelFile(bomFile, items.ToList()); } private string ChangePathExtension(string fullpath, string newExtension) { var dir = Path.GetDirectoryName(fullpath); var name = Path.GetFileNameWithoutExtension(fullpath); return Path.Combine(dir, name + newExtension); } private bool SavePartToDXF(PartDoc part, string savePath) { var partModel = part as ModelDoc2; var config = partModel.ConfigurationManager.ActiveConfiguration.Name; return SavePartToDXF(part, config, savePath); } private bool SavePartToDXF(PartDoc part, string partConfiguration, string savePath) { try { var partModel = part as ModelDoc2; if (partModel.IsSheetMetal() == false) { Print(partModel.GetTitle() + " - skipped, not sheet metal"); return false; } if (templateDrawing == null) templateDrawing = CreateDrawing(); var sheet = templateDrawing.IGetCurrentSheet(); var modelName = Path.GetFileNameWithoutExtension(partModel.GetPathName()); sheet.SetName(modelName); Print(partModel.GetTitle() + " - Creating flat pattern."); SolidWorks.Interop.sldworks.View view; view = templateDrawing.CreateFlatPatternViewFromModelView3(partModel.GetPathName(), partConfiguration, 0, 0, 0, false, false); view.ShowSheetMetalBendNotes = true; var drawingModel = templateDrawing as ModelDoc2; drawingModel.ViewZoomtofit2(); if (ShouldFlipView(view)) { Print(partModel.GetTitle() + " - Flipped view", Color.Blue); view.FlipView = true; } drawingModel.SaveAs(savePath); Print(partModel.GetTitle() + " - Saved to \"" + savePath + "\"", Color.Green); Print(""); drawingModel.SelectByName(0, view.Name); drawingModel.DeleteSelection(false); return true; } catch (Exception ex) { MessageBox.Show(ex.Message); return false; } } private void CreateBOMExcelFile(string filepath, IList items) { var templatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Templates", "BomTemplate.xlsx"); File.Copy(templatePath, filepath, true); var newFile = new FileInfo(filepath); using (var pkg = new ExcelPackage(newFile)) { var workbook = pkg.Workbook; var partsSheet = workbook.Worksheets["Parts"]; for (int i = 0; i < items.Count; i++) { var item = items[i]; var row = i + 2; partsSheet.Cells[row, 1].Value = item.ItemNo; partsSheet.Cells[row, 2].Value = item.Quantity; partsSheet.Cells[row, 3].Value = item.Description; partsSheet.Cells[row, 4].Value = item.PartNo; if (item.Thickness > 0) partsSheet.Cells[row, 5].Value = item.Thickness; partsSheet.Cells[row, 6].Value = item.Material; if (item.KFactor > 0) partsSheet.Cells[row, 7].Value = item.KFactor; } workbook.Calculate(); pkg.Save(); } } private string UserSelectFolder() { string path = null; Invoke(new MethodInvoker(() => { var dlg = new FolderBrowserDialog(); dlg.Description = "Where do you want to save the DXF files?"; path = dlg.ShowDialog() == DialogResult.OK ? dlg.SelectedPath : null; })); return path; } private bool ShouldFlipView(SolidWorks.Interop.sldworks.View view) { return viewFlipDecider.ShouldFlip(view); } private DrawingDoc CreateDrawing() { return sldWorks.NewDocument( DrawingTemplatePath, (int)swDwgPaperSizes_e.swDwgPaperDsize, 1, 1) as DrawingDoc; } private List GetBomTables(DrawingDoc drawing) { var model = drawing as ModelDoc2; return model.GetAllFeaturesByTypeName("BomFeat") .Select(f => f.GetSpecificFeature2() as BomFeature) .Select(f => (f.GetTableAnnotations() as Array)?.Cast().FirstOrDefault()) .ToList(); } private List GetItems(BomTableAnnotation bom) { var items = new List(); var table = bom as TableAnnotation; var itemNoColumnIndex = table.IndexOfColumnType(swTableColumnTypes_e.swBomTableColumnType_ItemNumber); if (itemNoColumnIndex == -1) { Print("Error: Item number column not found."); return null; } else { Print("Item numbers are in the " + Helper.GetNumWithSuffix(itemNoColumnIndex + 1) + " column."); } var qtyColumnIndex = table.IndexOfColumnType(swTableColumnTypes_e.swBomTableColumnType_Quantity); if (qtyColumnIndex == -1) { Print("Error: Quantity column not found."); return null; } var descriptionColumnIndex = table.IndexOfColumnTitle("Description"); if (descriptionColumnIndex == -1) { Print("Error: Description column not found."); return null; } var partNoColumnIndex = table.IndexOfColumnType(swTableColumnTypes_e.swBomTableColumnType_PartNumber); if (partNoColumnIndex == -1) { Print("Error: Part number column not found."); return null; } var isBOMPartsOnly = bom.BomFeature.TableType == (int)swBomType_e.swBomType_PartsOnly; for (int rowIndex = 0; rowIndex < table.RowCount; rowIndex++) { if (table.RowHidden[rowIndex] == true) continue; var bomComponents = isBOMPartsOnly ? ((Array)bom.GetComponents2(rowIndex, bom.BomFeature.Configuration))?.Cast() : ((Array)bom.GetComponents(rowIndex))?.Cast(); if (bomComponents == null) continue; var distinctComponents = bomComponents .GroupBy(c => c.ReferencedConfiguration) .Select(group => group.First()); //var itemNumber = table.Text[rowIndex, itemNoColumnIndex].PadLeft(2, '0'); //var rev = 'A'; if (distinctComponents.Count() > 1) { throw new NotImplementedException(); //foreach (var comp in distinctComponents) //{ // items.Add(new Item // { // Name = itemNumber + rev++, // Component = comp // }); //} } else { items.Add(new Item { PartNo = table.DisplayedText[rowIndex, partNoColumnIndex], Quantity = int.Parse(table.DisplayedText[rowIndex, qtyColumnIndex]), Description = table.DisplayedText[rowIndex, descriptionColumnIndex], ItemNo = table.DisplayedText[rowIndex, itemNoColumnIndex].PadLeft(2, '0'), Component = distinctComponents.First() }); } } return items; } private List GetItems(AssemblyDoc assembly, bool topLevel) { var list = new List(); assembly.ResolveAllLightWeightComponents(false); var assemblyComponents = ((Array)assembly.GetComponents(topLevel)) .Cast() .Where(c => !c.IsHidden(true)); var componentGroups = assemblyComponents .GroupBy(c => c.GetTitle() + c.ReferencedConfiguration); foreach (var group in componentGroups) { var component = group.First(); var name = component.ReferencedConfiguration.ToLower() == "default" ? component.GetTitle() : string.Format("{0} [{1}]", component.GetTitle(), component.ReferencedConfiguration); list.Add(new Item { PartNo = name, Quantity = group.Count(), Component = component }); } return list; } private static string DrawingTemplatePath { get { return Path.Combine(Application.StartupPath, "Templates", "Blank.drwdot"); } } } }