Author Topic: How get items in CADmep Fab API  (Read 4682 times)

0 Members and 1 Guest are viewing this topic.

Offline dopefishTopic starter

  • Senior Member
  • ****
  • Posts: 484
  • Country: us
  • Gender: Male
How get items in CADmep Fab API
« on: Mar 07, 2024, 00:17:48 AM »
Hey xtracad. I'm out of ideas but I'm sure I am missing something simple. I can not seem to parse my selection set and collect Items into a list using the API. I pretty much copied the method shown on HouseofBIM. I will post the code below. I have set watches on all the variables and anything of type item always reads null.

Code: [Select]
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using Autodesk.Fabrication;
using Autodesk.Fabrication.Events;
using Autodesk.Fabrication.DB;
using System.Linq;
using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.Fabrication.ApplicationServices;
using Autodesk.Fabrication.Content;
using Application = Autodesk.AutoCAD.ApplicationServices.Application;
using Database = Autodesk.AutoCAD.DatabaseServices.Database;
using System;

namespace ACAD2022Plugin
{
    public class Commands
    {

        //Start of the command "ConnectSpools"
        [CommandMethod("ConnectSpools")]

        public void ConnectSpools()
        {

            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            TypedValue[] typeArray = new TypedValue[1];
            typeArray[0] = new TypedValue((int)DxfCode.Start, "MAPS_SOLID");

            SelectionFilter selFilter = new SelectionFilter(typeArray);
            PromptSelectionResult selResult = ed.GetSelection(selFilter);

            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    SelectionSet ss = selResult.Value;

                    List<Item> Spools1 = new List<Item>();

                    List<Item> Spools2 = new List<Item>();

                    ed.WriteMessage(String.Format("\n{0}", ss.Count.ToString()));

                    foreach (SelectedObject selObject in ss)
                    {
                        if (selObject != null)
                        {
                            Entity ent = tr.GetObject(selObject.ObjectId, OpenMode.ForRead) as Entity;
                            if (ent != null)
                            {
                                string entHandle = ent.Handle.ToString();
                                Item myitem;
                                myitem = Job.GetFabricationItemFromACADHandle(ent.Handle.ToString());
             
                                if (myitem != null)
                                {
                                     if (myitem.SpoolName !=null)
                                     {
                                         Spools1.Add(myitem);
                                         Spools2.Add(myitem);
                                     }
                                }
                            }
                        }
                    }

                    foreach (Item MySpool1 in Spools1)
                    {
                        foreach (Item MySpool2 in Spools2)
                        {

                            if (Utilities.IsConnected(MySpool1, MySpool2, 0.0))

                            {
                                MySpool1.Notes = MySpool2.SpoolName.ToString();
                                MySpool1.Update();
                                MySpool2.Notes = MySpool1.SpoolName.ToString();
                                MySpool2.Update();
                            }
                        }
                    }
                }
            }
        }
    }
}
« Last Edit: Mar 21, 2024, 00:09:48 AM by dopefish »
"And the wood header is still 4  3/4" on top of the top of the double top plate." . . . Random VDC Coodinator

I love coordination

Offline dopefishTopic starter

  • Senior Member
  • ****
  • Posts: 484
  • Country: us
  • Gender: Male
Re: How get items in CADmep Fab API
« Reply #1 on: Mar 07, 2024, 15:45:18 PM »
I'm just going pile on to my own post here. Since I think these issues may be linked.

Anytime I try to invoke the collection Job.Items in anyways I get an unhandled exception error attempting to access protected memory error. Anyone ever run across this?

My debugging kung fu is not at a point where I will be able to trace this in the call stack and have some kind of eureka moment.

Any thoughts or ideas would be welcome.
"And the wood header is still 4  3/4" on top of the top of the double top plate." . . . Random VDC Coodinator

I love coordination

Offline craigjonnson

  • Senior Member
  • ****
  • Posts: 303
  • Country: au
  • Gender: Male
Re: How get items in CADmep Fab API
« Reply #2 on: Mar 11, 2024, 02:28:44 AM »
I ran this past our developer, and he asked If your platform build is set to any CPU. Try changing this to x64 and run it again.

Offline dopefishTopic starter

  • Senior Member
  • ****
  • Posts: 484
  • Country: us
  • Gender: Male
Re: How get items in CADmep Fab API
« Reply #3 on: Mar 11, 2024, 18:43:16 PM »
Thank you for replying! :)

That was one of the first things I changed as it was giving me a warning at build time.

I am running this thru the debugger in visual studio. I don't know if that might be causing issues.
"And the wood header is still 4  3/4" on top of the top of the double top plate." . . . Random VDC Coodinator

I love coordination

Offline dopefishTopic starter

  • Senior Member
  • ****
  • Posts: 484
  • Country: us
  • Gender: Male
Re: How get items in CADmep Fab API
« Reply #4 on: Mar 20, 2024, 05:54:08 AM »
OK. I got it sorted out. One of my references was not compatible with x64 architecture and was giving me memory address exceptions. I cleaned up the code by removing most of the libraries and simplified refactored everything into one namespace and things are working now.

In summary if you ever get an exception: "Attempted to read or write to protected memory" or if you are having trouble getting items to filter into a selection then there is a good chance there is an incompatible library reference in the project.
« Last Edit: Mar 20, 2024, 05:57:57 AM by dopefish »
"And the wood header is still 4  3/4" on top of the top of the double top plate." . . . Random VDC Coodinator

I love coordination

Offline cyan

  • Premier Member
  • *****
  • Posts: 626
  • Country: us
  • Gender: Male
Re: How get items in CADmep Fab API
« Reply #5 on: Oct 02, 2025, 15:44:51 PM »
I have to piggyback off of this topic because I found this issue today and it's a pretty far reaching issue.

We've built some infrastructure to start bringing some simplicity to the madness that is everyday construction. This means, for example, a common internal NuGet package infrastructure that we can use to standardize stuff like logging, database calls, Stratus, etc.

It's really seemed like a boon so far.

I have a pretty beefy FabricationAPI addin that's primarily used in CAMduct for now, but will also be used in ESTmep. There's not much plan for any usage in CADmep though. The specific solution relative to this AddIn is x64 across all projects within it. Everything seems to run fine if you open the AddIn and smoke test it thoroughly.

However, if you close the MAJ file that you are in and open a new one, you will start hitting protected memory issues because the items in Job.Items become polluted with empty dimension references that have "" for a name and 0 for a value. And if you close and open the AddIn again, it just straight up crashes because the items are now protected memory or non-existent.

I'm checking and double checking, but if the conclusion to this is that I cannot use any external packages, which consist of a few small ones of our own and Microsoft's Logging/DI frameworks, then this reflects extremely poorly on the Fabrication API's readiness for production and realistic commercial use.

Although I feel like I originally assigned everything to x64 because I was hitting protected memory issues even in the first opened project, so I'm not entirely convinced that this is the cause. But it is problematic all the same. Anyone familiar with this?

Edit:

And for the sake of clarity, my test was pretty simple.

Land in a breakpoint somewhere in my AddIn startup and just use the intermediate window to watch this:
Job.Items.SelectMany(item => item.Dimensions).Select(dim => dim.Name)

The first project you open, that code gives you the expected list of dimensions like "Width", "Depth", "Length", etc. You should see no "" values.

Close the addin, close the current CAM project, then open another one. Repeat and you'll see values of "" all over the place.

You can also target the instances of it via
Job.items.Where(item => item.Dimensions.Any(dim => string.IsNullOrWhitespace(dim.Name))

Last Edit:

I just copied their HelloFabrication code and simply added a single call to
 var emptyItems = Job.Items.Where(item => item.Dimensions.Any(dim => string.IsNullOrWhiteSpace(dim.Name)))
            .ToArray();

Still crashes. I think I found a global bug. You can't use Job.Items reliably in CAMduct/ESTmep if you are not staying in the same MAJ file per session. And in CADmep I know people are already just using the AutoCAD toolset to get fab items.

I will file an ADN report, hope they still address FabAPI issues.

« Last Edit: Oct 02, 2025, 17:46:12 PM by cyan »

Offline cyan

  • Premier Member
  • *****
  • Posts: 626
  • Country: us
  • Gender: Male
Re: How get items in CADmep Fab API
« Reply #6 on: Oct 09, 2025, 19:07:42 PM »
I will still be reporting this, because it is still a meaningful bug.

But if you run into this, the usable workaround turned out to be really simple.

Do a foreach on the items in the job and run Update() every time the addin opens. It's not that intensive, runs quickly, and you're ready to roll.