Autocad mechanical - automatic Parts List extraction (C#)

Autocad mechanical - automatic Parts List extraction (C#)

Anonymous
Not applicable
5,309 Views
12 Replies
Message 1 of 13

Autocad mechanical - automatic Parts List extraction (C#)

Anonymous
Not applicable

I am trying to access the Parts List created by Autocad Mechanical.

 

It can be done manually in Autocad Mechanical , but I'd like to automate it. Link to manually extract the parts list

 

I found this code in VBA, which I could convert to C#, but i do not have AtuoDesk McadAuto Type Library, even though I have Autocad Mechanical Installed. I have tried to find it, but have had no success.

 

 

I looked at the Developer Guide for AutoCAD Mechanical, but this did not seem to help

 

The code below finds the parts list in the attached drawing file, but i cannot find what to do to read the parts list.

DBObjectCollection objs = new DBObjectCollection();
Document doc = AcadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
ObjectId Id;
 
using (Transaction tr = db.TransactionManager.StartTransaction())
{
    BlockTable bt;
    bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
 
    BlockTableRecord btr;
    btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
    ObjectIdCollection ids = new ObjectIdCollection();
 
    foreach (ObjectId id in btr)
    {
        if (id.ObjectClass.DxfName == "ACMPARTLIST")
        {
            // code to read data from parts list

        }
    }
}

 

 

The ACMPARTLIST looks like a table, but it cannot be extracted using the autocad command TableExport, or DataExtraction.

I have tried other suggestions. This one extracts tables, but ACMPARTLIST is not a table.

http://forums.autodesk.com/t5/net/extracting-bom-from-autocad-using-c/m-p/3873852#M34623

 

Do i need the McadAuto.dll so I can access the BOM, or am i missing something else?

0 Likes
Accepted solutions (1)
5,310 Views
12 Replies
Replies (12)
Message 2 of 13

FRFR1426
Collaborator
Collaborator

You need to add a reference to MCadAuto and SymBBAuto library (they are in C:\Program Files\Common Files\Autodesk Shared), then you can access the parts list with code like this (not tested):

 

 

Set mcad = app.GetInterfaceObject("AcadmAuto.AcadmApplication")
Dim oSymBB As McadSymbolBBMgr = mcad.GetInterfaceObject("SymBBAuto.McadSymbolBBMgr") Dim oBOMMgr As McadBOMMgr = oSymBB.BOMMgr If oBOMMgr.BOMTableExists("testBOM") Then Set oBOM As McadBOM = oBOMMgr.GetBOMTable(doc.ModelSpace, "testBOM")
// See documentation for McadBOM to see what you can do with that
// http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=14952981 End If

Please note that it is recommended to put the version in the ProgId (AcadmAuto.AcadmApplication.5 for AutoCAD 2016 for example)

Maxence DELANNOY
Manager
Add-ins development for Autodesk software products
http://wiip.fr
0 Likes
Message 3 of 13

Anonymous
Not applicable

Thanks for that, they were there all along with a slightly different name.

 

The link you gave did not work. I tried searching for something similar, but i cannot find how to read the parts list data of each item in the parts list.

 

 

Below is my current code.

It finds the BOM table (Always called MAIN).

I tried

 

                 SymBBAuto.IMcadSymbolBBMgr symbbmgr;
                    symbbmgr = acApp.GetInterfaceObject("SymBBAuto.McadSymbolBBMgr");

                    SymBBAuto.IMcadBOMs cadBOMs;
                    cadBOMs = symbbmgr.BOMMgr.GetAllBOMTables(false);

                    SymBBAuto.IMcadBOM cadBOM;
                    cadBOM = cadBOMs.Item(0);

                    SymBBAuto.IMcadBOMMgr cadBOMmgr;
                    cadBOMmgr = symbbmgr.BOMMgr;

                    if (cadBOMmgr.BOMTableExists("MAIN"))
                    {
                        cadBOMmgr.ExportBOM(cadBOM, "csv", FullPatheName); // doesnt do anything

                        IMcadBOMItems bomItems = cadBOM.Items;
                        object oItem;
                        foreach (McadBOMItem bomItem in bomItems)
                        {
                            // add code to read parts list data
                        }
                    } 

 

I tried to export the BOM, which did not work.

I also tried to export the parts list from the BOM, which gave me the error "the file being exported to cannot be created"

 

                        McadBOMMgr cadBOMmgr2;
                        cadBOMmgr2 = symbbmgr.BOMMgr as McadBOMMgr;
                        McadPartLists PL;
                        PL = cadBOM.PartLists;
                        cadBOMmgr2.ExportPartList(McadBOMExportFormatType.exCSV, PL.Item(0), FullPathName, "MAIN", true);

 

I tried to go through each bom item and extract its data, but i could notfind how to get this data

                        IMcadBOMItems bomItems = cadBOM.Items;
                        object oItem;
                        foreach (McadBOMItem bomItem in bomItems)
                        {
                            // add code to get item of each bom item
                        }

 

If you have any advice/links on how to get any of them to work, that would be greatly appreciated.

 

Thank you.

0 Likes
Message 4 of 13

FRFR1426
Collaborator
Collaborator

FileType should be .csv (starting with a dot).

 

cadBOMmgr.ExportBOM(cadBOM, ".csv", FullPatheName);
Maxence DELANNOY
Manager
Add-ins development for Autodesk software products
http://wiip.fr
0 Likes
Message 5 of 13

Anonymous
Not applicable

I added the starting dot, but it does not create any file.

 

This is the path i chose (just a temp path for testing). I also tried it without the .csv in FullPAtheName and that didnt work either.

Would anything in this stop it working?

 

string FullPatheName = @"C:\BOM Out.csv";

 

Do you have any links to other examples?

I have searhed through alot of other posts but cannot find any.

 

0 Likes
Message 6 of 13

Anonymous
Not applicable

I still cannot get this to work, this is my code

 

        public static void Extract_BOM()
        {
            string FullPathName = @"C:\BOM Out.csv";            

            DBObjectCollection objs = new DBObjectCollection();
            Document doc = AcadApp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            string BomName = "MAIN";

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                AcadApplication acApp = null;
                const string progID = "AutoCAD.Application.19";
                acApp = (AcadApplication)Marshal.GetActiveObject(progID);
                if (acApp != null)
                {

                    SymBBAuto.IMcadSymbolBBMgr symbbmgr;
                    symbbmgr = acApp.GetInterfaceObject("SymBBAuto.McadSymbolBBMgr");

                    AXDBLib.AcadObject obj;   //requires AXDBlib reference
                    LayoutManager LM = LayoutManager.Current;
                    SymBBAuto.IMcadBOMMgr cadBOMmgr;
                    cadBOMmgr = symbbmgr.BOMMgr;

                    try
                    {
                        obj = (AXDBLib.AcadObject)LM.GetLayoutId(LM.CurrentLayout).GetObject(OpenMode.ForRead).AcadObject;
                        //  sheetSetMgr.GetSheetFromLayout(obj, out sheet);
                        if (cadBOMmgr.BOMTableExists(BomName))
                        {
                            SymBBAuto.IMcadBOM cadBOM;

                            cadBOMmgr.ExportBOM(cadBOM, ".csv", FullPathName);
                        }
                        }
                        catch (System.Exception e)
                        {
                            System.Windows.Forms.MessageBox.Show("There was an error getting the sheet set info for this layout: " + e.Message);
                        }                  
                }
            }
        }

 

The line 

cadBOMmgr.ExportBOM(cadBOM, ".csv", FullPathName);

Gives me the error "There was an error getting the sheet set info for this layout: Error HRESULT E_FAIL has been returned from a call to a COM component.

 

I have tried a few methods as previously stated.

 

Do you have any links where I can view working code, so I can work backwards from it?

 

0 Likes
Message 7 of 13

Anonymous
Not applicable

Try the direct interface to AcadApplication instead of using Marshal.

 

AcadApplication acApp = Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication
AcadDocument acDoc = acApp.ActiveDocument

I found this works better in .net than using the COM interface.

 

EDIT:

 

You may also need to add

 

Using Autodesk.AutoCAD.Interop;
Using Autodesk.AutoCAD.Interop.Common;
0 Likes
Message 8 of 13

Anonymous
Not applicable

Okay, I got it working in VB.net. First thing to note is the COM library has Interface and Non-Interface variables. Once you have an Interface variable you want to save it to a non-Interface type variable and then dispose of the interface.

 

I found that using SymBBAuto.IMcadBOM would throw an error about not being able to write while SymBBAuto.McadBOM wrote the file.

 

 

Dim FullPathName As String = "c:\test\test.csv"
Dim BomName As String = "MAIN"

Dim acadApp As AcadApplication = Application.AcadApplication
Dim acadDoc As AcadDocument = acadApp.ActiveDocument

' --------------------------------------------------------------
' Get the Surface Texture Library Object
Try
	' Get Interface to SymbolBBMMgr
	Dim I_symBBmgr3 As IMcadSymbolBBMgr3 = Nothing
	I_symBBmgr3 = acadDoc.Application.GetInterfaceObject("SymBBAuto.McadSymbolBBMgr") 

	' Get Interface to BOMMgr from the active document
	Dim I_cadBOMmgr3 As SymBBAuto.IMcadBOMMgr3 = Nothing
	I_cadBOMmgr3 = I_symBBmgr3.BOMMgr(acadDoc)

	' Save the Contents to Non-Interface variable
	Dim cadBOMmgr As SymBBAuto.McadBOMMgr = Nothing
	cadBOMmgr = I_cadBOMmgr3

	' Dispose of the Interface
	I_cadBOMmgr3 = Nothing

	' Check if BOMName exists in Table
	If cadBOMmgr.BOMTableExists(BomName) Then
		' Get the BOMTable by name (Non-Interface Variable)
		Dim cadBom As SymBBAuto.McadBOM = Nothing
		cadBom = cadBOMmgr.GetBOMTableByName(BomName)

		If cadBom IsNot Nothing Then
			cadBOMmgr.ExportBOM2(SymBBAuto.McadBOMExportFormatType.exCSV, cadBom, FullPathName, "Main", True)
		End If
	End If

Catch acEx As Autodesk.AutoCAD.Runtime.Exception
	' Write Error Message
Catch ex As System.Exception
	' Write Error Message
End Try

 

This should be fairly easy to translate to C# if that is what you need. If you are going from VBA, I would suggest VB.net instead of C#.net because it's a little less of a learning curve. However, most people do use C# so it's all up to you on which one to use.

 

Hope this helps!

 

0 Likes
Message 9 of 13

Anonymous
Not applicable

Here is the c# version:

 

 

string FullPathName = "c:\\test\\test.csv";
string BomName = "MAIN";

AcadApplication acadApp = Application.AcadApplication;
AcadDocument acadDoc = acadApp.ActiveDocument;

// --------------------------------------------------------------
// Get the Surface Texture Library Object
try
{
    // Get Interface to SymbolBBMMgr
    IMcadSymbolBBMgr3 I_symBBmgr3 = null;
    I_symBBmgr3 = acadDoc.Application.GetInterfaceObject("SymBBAuto.McadSymbolBBMgr");

    // Get Interface to BOMMgr from the active document
    SymBBAuto.IMcadBOMMgr3 I_cadBOMmgr3 = null;
    I_cadBOMmgr3 = I_symBBmgr3.BOMMgr(acadDoc);

    // Save the Contents to Non-Interface variable
    SymBBAuto.McadBOMMgr cadBOMmgr = null;
    cadBOMmgr = I_cadBOMmgr3;

    // Dispose of the Interface
    I_cadBOMmgr3 = null;

    // Check if BOMName exists in Table
    if (cadBOMmgr.BOMTableExists(BomName))
    {
        // Get the BOMTable by name (Non-Interface Variable)
        SymBBAuto.McadBOM cadBom = null;
        cadBom = cadBOMmgr.GetBOMTableByName(BomName);

        if (cadBom != null)
        {
            cadBOMmgr.ExportBOM2(SymBBAuto.McadBOMExportFormatType.exCSV, cadBom, FullPathName, "Main", true);
        }
    }
}
catch (Autodesk.AutoCAD.Runtime.Exception acEx)
{
    // Write Error Message
}
catch (System.Exception ex)
{
    // Write Error Message
}
0 Likes
Message 10 of 13

Anonymous
Not applicable

Did the C# code compile for you?

 

 

I received the following errors;

I tried to fix it, but couldn't get it to work.


Error CS1955 Non-invocable member 'IMcadSymbolBBMgr3.BOMMgr[object]' cannot be used like a method.

Error CS0266 Cannot implicitly convert type 'SymBBAuto.IMcadBOMMgr3' to 'SymBBAuto.McadBOMMgr'. An explicit conversion exists (are you missing a cast?)

Error CS0266 Cannot implicitly convert type 'SymBBAuto.IMcadBOM' to 'SymBBAuto.McadBOM'. An explicit conversion exists (are you missing a cast?) 
Error CS0266 Cannot implicitly convert type 'object' to 'Autodesk.AutoCAD.Interop.AcadApplication'. An explicit conversion exists (are you missing a cast?)

 

Thanks in advance.

 

0 Likes
Message 11 of 13

Anonymous
Not applicable

Unfortunately I hadn't tested the C# code. All my development in Autocad has been with VB. All my C# experience comes from my development with CATIA which has mostly been at the COM level. Try these fixes, they should help a bit.

 


Error CS1955 Non-invocable member 'IMcadSymbolBBMgr3.BOMMgr[object]' cannot be used like a method.

The VB intellisense shows that it's needed but the Object Browser shows the param as optional. Try removing the acadDoc from the line.

 

I_cadBOMmgr3 = I_symBBmgr3.BOMMgr;

 This line also has another error with the solution below.

 


Error CS0266 Cannot implicitly convert type 'SymBBAuto.IMcadBOMMgr3' to 'SymBBAuto.McadBOMMgr'. An explicit conversion exists (are you missing a cast?)

Error CS0266 Cannot implicitly convert type 'SymBBAuto.IMcadBOM' to 'SymBBAuto.McadBOM'. An explicit conversion exists (are you missing a cast?) 
Error CS0266 Cannot implicitly convert type 'object' to 'Autodesk.AutoCAD.Interop.AcadApplication'. An explicit conversion exists (are you missing a cast?)


These should be able to be fixable by explicitly casting; something like this:

 

I_symBBmgr3 = (IMcadSymbolBBMgr3)acadDoc.Application.GetInterfaceObject("SymBBAuto.McadSymbolBBMgr");


I_cadBOMmgr3 = (SymBBAuto.IMcadBOMMgr3)I_symBBmgr3.BOMMgr;


cadBOMmgr = (SymBBAuto.McadBOMMgr)I_cadBOMmgr3;

That will explicitly cast the objects and should hopefully fix them.

 

Let me know how it goes.

 

0 Likes
Message 12 of 13

Anonymous
Not applicable
Accepted solution

Scratch some of that previous post, the first error wasn't happening in the spot I thought it was. Compiled, and tested C# code is as follows.

 

 

using System;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using SymBBAuto;
using Autodesk.AutoCAD.Interop;


// This line is not mandatory, but improves loading performances
[assembly: CommandClass(typeof(TESTER.MyCommands))]

namespace TESTER
{
    public class MyCommands
    {
        // Modal Command with localized name
        [CommandMethod("TTT", "TTT", CommandFlags.Modal)]
        public void TTT() // This method can have any name
        {
            string FullPathName = "c:\\temp\\test.csv";
            string BomName = "MAIN";

            AcadApplication acadApp = (AcadApplication)Application.AcadApplication;
            AcadDocument acadDoc = acadApp.ActiveDocument;

            try
            {
                // Get Interface to SymbolBBMMgr
                IMcadSymbolBBMgr3 I_symBBmgr3 = null;
                I_symBBmgr3 = (IMcadSymbolBBMgr3)acadDoc.Application.GetInterfaceObject("SymBBAuto.McadSymbolBBMgr");

                // Get Interface to BOMMgr from the active document
                SymBBAuto.IMcadBOMMgr3 I_cadBOMmgr3 = null;
                I_cadBOMmgr3 = (SymBBAuto.IMcadBOMMgr3)I_symBBmgr3.BOMMgr;

                // Save the Contents to Non-Interface variable
                SymBBAuto.McadBOMMgr cadBOMmgr = null;
                cadBOMmgr = (SymBBAuto.McadBOMMgr)I_cadBOMmgr3;

                // Dispose of the Interface
                I_cadBOMmgr3 = null;

                // Check if BOMName exists in Table
                if (cadBOMmgr.BOMTableExists(BomName))
                {
                    // Get the BOMTable by name (Non-Interface Variable)
                    SymBBAuto.McadBOM cadBom = null;
                    cadBom = (SymBBAuto.McadBOM)cadBOMmgr.GetBOMTableByName(BomName);

                    if (cadBom != null)
                    {
                        cadBOMmgr.ExportBOM2(SymBBAuto.McadBOMExportFormatType.exCSV, cadBom, FullPathName, "Main", true);
                    }
                }
            }
            catch (Autodesk.AutoCAD.Runtime.Exception acEx)
            {
                // Write Error Message
            }
            catch (System.Exception ex)
            {
                // Write Error Message
            }
        }
    }
}

Do note the output directory "FullPathName" must be an actual location. The export doesn't seem to want to create folders. The file it creates okay, however.

 

Cheers.

0 Likes
Message 13 of 13

Anonymous
Not applicable

I see where i went wrong.

Makes sense, and worked perfectly.

 

Thanks a lot for the help.

0 Likes