'Stack overflow' error caused by AppendEntity and AddNewlyCreatedDBObject usage

'Stack overflow' error caused by AppendEntity and AddNewlyCreatedDBObject usage

Anonymous
Not applicable
1,849 Views
3 Replies
Message 1 of 4

'Stack overflow' error caused by AppendEntity and AddNewlyCreatedDBObject usage

Anonymous
Not applicable

Hello,

 

I'm a nubby in AutoCAD plugins.

I run my code in Visual Studio 2019 and AutoCAD 2016.

I wrote several simple functions that worked ok.

And now I tried to write a plugin that creates Block reference for each MTEXT at the same coordinates.

When I call my new command I got all the expected dialog alerts from my command, but after it AutoCAD closes itself and I see the following error in Visual Studio's ouput:

The target process exited without raising a CoreCLR started event. Ensure that the target process is configured to use .NET Core. This may be expected if the target process did not run on .NET Core.
The program '[21236] acad.exe' has exited with code -1073741571 (0xc00000fd) 'Stack overflow'.

 

My command's source code:

 

 

[CommandMethod("blockTest")]
static public void blockTest()
{
    string attbName = "HEIGHT";

    // Get the current docusment and database, and start a transaction
    Document acDoc = Application.DocumentManager.MdiActiveDocument;
    Database acCurDb = acDoc.Database;
    Editor acDocEd = Application.DocumentManager.MdiActiveDocument.Editor;

    using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
    {
        BlockTable bt = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;
        BlockTableRecord btr = acTrans.GetObject(acCurDb.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;

        btr.UpgradeOpen();

        foreach (ObjectId objId in btr)
        {
            if (objId.ObjectClass.DxfName == "MTEXT")
            {
                MText mtext = acTrans.GetObject(objId, OpenMode.ForRead, true) as MText;
                Point3d mtextCoord = mtext.Location;

                //create br for mtext
                br br = new br(new Point3d(mtextCoord.X, mtextCoord.Y, mtextCoord.Z), btr.Id);

                //update HEIGHT attribute in block reference to be same as mtext text
                foreach (ObjectId arId in br.AttributeCollection)
                {
                    AttributeReference ar = acTrans.GetObject(arId, OpenMode.ForRead) as AttributeReference;
                    if (null == ar)
                    {
                        Application.ShowAlertDialog("AttributeReference getting failed!");
                        return;
                    }
                    if (ar.Tag.ToUpper() == attbName)
                    {
                        ar.UpgradeOpen();
                        ar.TextString = mtext.Contents.ToString();
                        ar.DowngradeOpen();
                    }
                }
                br.SetDatabaseDefaults();
                Application.ShowAlertDialog("before AppendEntity!");
                btr.AppendEntity(br);
                acTrans.AddNewlyCreatedDBObject(br, true);
                Application.ShowAlertDialog("after AppendEntity!");
            }
        }

        acTrans.Commit();
    }
}

 

 

I ran the code on sample AutoCAD file that contains only 2 MTEXT.

If I comment out the lines that use AppendEntity and AddNewlyCreatedDBObject APIs AutoCAD doesn't close itself.

I don't understand how can I get a stack overflow.

Please help.

0 Likes
Accepted solutions (1)
1,850 Views
3 Replies
Replies (3)
Message 2 of 4

_gile
Consultant
Consultant

Hi,

 

Beyond the fact that the first following line cannot compile (br br = ...), you are inserting the current space (btr) in the current space.

br br = new br(new Point3d(mtextCoord.X, mtextCoord.Y, mtextCoord.Z), btr.Id);
// ...
btr.AppendEntity(br);

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 4

_gile
Consultant
Consultant
Accepted solution

Here's a working example.

We first check for the block definition (BlockTableRecord) in the block table, if it's not found, we create a new one.
Then, we iterate through the current space, looking for mtext entities and replace each one with a block reference. We have to explicitly add the attribute reference to the block reference.

public static void BlockTest()
{
    string attbName = "HEIGHT";
    string blockName = "BlockMtext";

    // Get the current document and database, and start a transaction
    var doc = Application.DocumentManager.MdiActiveDocument;
    var db = doc.Database;

    using (var tr = db.TransactionManager.StartTransaction())
    {
        // Open the block table and check if it contains "BlockMtext"
        var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
        ObjectId btrId;
        BlockTableRecord btr;

        // if the block table contains "BlockMtext", get its ObjectId and open it
        if (bt.Has(blockName))
        {
            btrId = bt[blockName];
            btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);
        }
        // else, create a new block definition
        else
        {
            // Create a new block definition
            btr = new BlockTableRecord();
            btr.Name = blockName;

            // Add the block definition to the block table
            tr.GetObject(bt.ObjectId, OpenMode.ForWrite);
            btrId = bt.Add(btr);
            tr.AddNewlyCreatedDBObject(btr, true);

            // Add an attribute definition to the block definition
            var attDef = new AttributeDefinition(Point3d.Origin, "---", attbName, "", db.Textstyle);
            //attDef.IsMTextAttributeDefinition = true;
            btr.AppendEntity(attDef);
            tr.AddNewlyCreatedDBObject(attDef, true);
        }

        // For each MText found in the current space, insert the block reference
        var currentSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
        foreach (ObjectId id in currentSpace)
        {
            if (id.ObjectClass.DxfName == "MTEXT")
            {
                // Open the MText
                var mtext = (MText)tr.GetObject(id, OpenMode.ForWrite);

                //Insert a block reference
                var br = new BlockReference(mtext.Location, btrId);
                currentSpace.AppendEntity(br);
                tr.AddNewlyCreatedDBObject(br, true);

                // Add the attribute references to the attribute collection of the block reference
                foreach (ObjectId attId in btr)
                {
                    if (attId.ObjectClass.DxfName == "ATTDEF")
                    {
                        var attDef = (AttributeDefinition)tr.GetObject(attId, OpenMode.ForRead);
                        var attRef = new AttributeReference();
                        attRef.SetAttributeFromBlock(attDef, br.BlockTransform);
                        if (attDef.Tag.ToUpper() == attbName)
                        {
                            attRef.TextString = mtext.Contents;
                        }
                        br.AttributeCollection.AppendAttribute(attRef);
                        tr.AddNewlyCreatedDBObject(attRef, true);
                    }
                }
                // Erase the MText
                mtext.Erase();
            }
        }
        tr.Commit();
    }
}

 

 

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 4 of 4

Anonymous
Not applicable

Thanks.

Of course you're right and

br br = new br(new Point3d(mtextCoord.X, mtextCoord.Y, mtextCoord.Z), btr.Id);

supposed to be:

BlockReferencebr = new BlockReference(new Point3d(mtextCoord.X, mtextCoord.Y, mtextCoord.Z), btr.Id);
0 Likes