.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Transaction.Commit() results in System.AccessViolationException

7 REPLIES 7
SOLVED
Reply
Message 1 of 8
Joshua_claytonWV5WP
608 Views, 7 Replies

Transaction.Commit() results in System.AccessViolationException

I have a custom command to handle part creations internally (in this sample code it's "CREATEBLOCK2").

 

  1. Create a simple object (circle, rectangle).
  2. Call CreateBlock2.
  3. Select the object's insertion point (center, bottom-left, whatever) and then the object itself.
  4. Object is made into a block with attributes, copied to the current directory's "xxx - Parts" folder, object removed then XREF'd back in from the newly created file.

Part of step 4 is opening a drawing template to WBLOCK the object into. Here in lies my problem.

 

In the attached solution there are 2 drawing template files. "acad.dwt" from the installed AutoCAD 2021 Mechanical instance. "BLANK_3.dwg" is a deleted/purged copy of one of our templates (sans the title block, layers, etc.).

 

If I test with the empty "acad.dwt" I get zero problems.

If I test with "BLANK_3.dwg" it will regularly fail, but not guaranteed.

 

I think the issue is in the "UpdateMaster()" function's trans.Commit() (or really non-disposed objects?).

private bool UpdateMaster(ObjectId blockID, string outputFileName)
{
    string blockName = txtBlockName.Text.Trim();
    string blockDesc = txtBlockDescription.Text.Trim();
    string partTemplate = txtPartTemplate.Text.Trim();

    Document document = ACAD_APP.DocumentManager.MdiActiveDocument;
    Database database = document.Database;

    try
    {
        using (DocumentLock doclock = document.LockDocument())
        {
            using (Transaction trans = database.TransactionManager.StartTransaction())
            {
                //create variable used to determine is it is a block reference
                Entity ent = trans.GetObject(blockID, OpenMode.ForRead, false) as Entity;

                if (ent is BlockReference)
                {
                    BlockReference blkRef = trans.GetObject(blockID, OpenMode.ForRead, false) as BlockReference;
                    BlockReference delBlkRef = trans.GetObject(blockID, OpenMode.ForWrite, false) as BlockReference;

                    Autodesk.AutoCAD.DatabaseServices.AttributeCollection attRefIds = blkRef.AttributeCollection;

                    //cycle through the attributes associated with the current block
                    foreach (ObjectId attrefid in attRefIds)
                    {
                        AttributeReference attref = (AttributeReference)trans.GetObject(attrefid, OpenMode.ForRead, false);

                        switch (attref?.Tag)
                        {
                            //if block has attribute Name then create the wblock
                            case "Name":
                                {
                                    string strBlockName = blkRef.Name;
                                    bool ok = false;

                                    //Add block objectID
                                    ObjectIdCollection oidc2 = new ObjectIdCollection();
                                    oidc2.Add(blkRef.ObjectId);

                                    using (var DestData = new Database(false, false))
                                    {
                                        DestData.ReadDwgFile(partTemplate, FileShare.ReadWrite, false, string.Empty);

                                        using (Transaction transNewDb = DestData.TransactionManager.StartTransaction())
                                        {
                                            BlockTable bt = transNewDb.GetObject(DestData.BlockTableId, OpenMode.ForRead) as BlockTable;

                                            IdMapping IDMap = new IdMapping();
                                            DestData.WblockCloneObjects(oidc2, bt[BlockTableRecord.ModelSpace], IDMap, DuplicateRecordCloning.Replace, false);

                                            if (!oidc2.IsDisposed)
                                            {
                                                oidc2.Dispose();
                                            }
                                            if (!IDMap.IsDisposed)
                                            {
                                                IDMap.Dispose();
                                            }

                                            CreatePartDrawingProps(transNewDb, DestData, attRefIds, blockName, blockDesc);

                                            transNewDb.Commit();

                                            DestData.SaveAs(outputFileName, DwgVersion.AC1027);

                                            DeleteBlockRef(delBlkRef);
                                            delBlkRef.Erase(true);

                                            ok = true;
                                        }
                                    }

                                    //Was wBlock successful?
                                    if (ok)
                                    {
                                        BlockTable xrefBt = (BlockTable)trans.GetObject(database.BlockTableId, OpenMode.ForRead);
                                        BlockTableRecord btrMs2 = (BlockTableRecord)trans.GetObject(xrefBt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);

                                        //create objectID for XRef
                                        string fileName = Path.GetFileNameWithoutExtension(outputFileName);
                                        ObjectId xrid = database.AttachXref(outputFileName, fileName);

                                        //create block reference, reference the xref objectID
                                        using (var bref = new BlockReference(Point3d.Origin, xrid))
                                        {
                                            bref.Rotation = blkRef.Rotation;
                                            bref.ScaleFactors = blkRef.ScaleFactors;

                                            //append xref to blocktable
                                            btrMs2.AppendEntity(bref);

                                            string blname = $"XRef - {Path.GetFileNameWithoutExtension(outputFileName)}";

                                            //Get the layer table first...
                                            LayerTable lt = (LayerTable)trans.GetObject(database.LayerTableId, OpenMode.ForRead);
                                            ObjectId layerId = ObjectId.Null;

                                            //Check if Layer exists...
                                            if (lt.Has(blname))
                                            {
                                                layerId = lt[blname];
                                            }
                                            else
                                            {
                                                //If not, create the layer here.
                                                lt.UpgradeOpen();
                                                using (var ltr = new LayerTableRecord())
                                                {
                                                    ltr.Name = blname; // Set the layer name
                                                    ltr.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 7);
                                                    layerId = lt.Add(ltr);
                                                    trans.AddNewlyCreatedDBObject(ltr, true);
                                                }
                                                lt.DowngradeOpen();
                                            }

                                            bref.LayerId = layerId;

                                            trans.AddNewlyCreatedDBObject(bref, true);

                                            layerId = ObjectId.Null;
                                            lt.Dispose();
                                        }

                                        xrid = ObjectId.Null;

                                        btrMs2.Dispose();
                                    }
                                }

                                break;
                            }

                        attref.Dispose();
                    }

                    delBlkRef.Dispose();
                    blkRef.Dispose();
                }

                ent.Dispose();
                
                trans.Commit(); // ***** This will randomly fail!
            }
        }
    }
    catch (System.Exception ex)
    {
        ACAD_APP.ShowAlertDialog("Error occurred: " + ex.ToString() + "\n" + ex.StackTrace);
        return false;
    }

    return true;
}

 

 

7 REPLIES 7
Message 2 of 8

The code you posted has lots of issues.

 

First, not even one call to Dispose() is necessary in the method you posted.  When you open a DBObject from a Transaction, there is no need to call Dispose() on the DBObject.

 

In one of the source files you attached, you are using SendStringToExecute() to execute commands from a command method. The commands you issue with SendStringToExecute() do not execute until after your command method has returned. Although in this case, I don't think that has anything to do with your issue.

 

One possible cause is this:

 

var DestData = new Database(false, false)

 

The second argument should be true, not false.

 

 

Message 3 of 8

I obviously went overboard with the Dispose() calls to see if it would be of any benefit (it's not).

 

Changing the

var DestData = new Database(false, false)

in the UpdateMaster() function to be:

var DestData = new Database(false, true)

 results in an error "eNotFromThisDocument" soon after when the CreatePartDrawingProps() function is called on this line:

AttributeReference attref = (AttributeReference)trans.GetObject(attrefid, OpenMode.ForRead, false);

 

Joshua_claytonWV5WP_0-1710768419076.png

 

Any thoughts on why that won't pull the Attribute Reference(s) ?

Message 4 of 8

Would the error dump files from the AutoCAD fatal crash be of any use here?

Message 5 of 8

I'm just guessing, maybe you should change 

 

using (Transaction transNewDb = DestData.TransactionManager.StartTransaction()

 

 

to 

 

 

using (Transaction transNewDb = DestData.TransactionManager.StartOpenCloseTransaction())

 

 

Also, I allways first define the database.transactionmanger and after that the using the transactionmanager.startopenclose. But don't know if that matters.  

Message 6 of 8


@Joshua_claytonWV5WP wrote:

I obviously went overboard with the Dispose() calls to see if it would be of any benefit (it's not).

 

Changing the

 

var DestData = new Database(false, false)

 

in the UpdateMaster() function to be:

 

var DestData = new Database(false, true)

 

 results in an error "eNotFromThisDocument" soon after when the CreatePartDrawingProps() function is called on this line:

 

AttributeReference attref = (AttributeReference)trans.GetObject(attrefid, OpenMode.ForRead, false);

 

 

Joshua_claytonWV5WP_0-1710768419076.png

 

Any thoughts on why that won't pull the Attribute Reference(s) ?


I didn't see you post that function so I don't know what's going on, other than that the error message says that you're most-likely passing an ObjectId from a database to a transaction that's not associated with that database. Before you changed the second argument to the Database constructor, the error may not have occurred because the external database was using the active document's transaction manager.

 

Message 7 of 8

Here is the function that causing this to fail entirely now if I leave the Database(false, true).

 

 

        private void CreatePartDrawingProps(Transaction trans, Database db, Autodesk.AutoCAD.DatabaseServices.AttributeCollection attRefIds, string blockName, string blockDesc)
        {
            DatabaseSummaryInfoBuilder DbSib = GetDatabaseSummaryInfoBuilderProperties(blockName, blockDesc);

            foreach (ObjectId attrefid in attRefIds)
            {
                AttributeReference attref = (AttributeReference)trans.GetObject(attrefid, OpenMode.ForRead, false);
                if (!DbSib.CustomPropertyTable.Contains(attref.Tag.ToUpper()))
                {
                    try
                    {
                        DbSib.CustomPropertyTable.Add(attref.Tag.ToUpper(), attref.TextString);
                    }
                    catch (System.Exception ex)
                    {
                        if (ex.Message == "eDuplicateKey")
                        {
                            //Continue For
                        }
                        else
                        {
                            Debug.WriteLine(ex.Message + "\n" + ex.StackTrace);
                        }
                    }
                }
            }

            try
            {
                IDictionaryEnumerator iDict = db.SummaryInfo.CustomProperties;

                while (iDict.MoveNext())
                {
                    if (iDict.Key.ToString() == "SHEET SIZE")
                    {
                        try
                        {
                            DbSib.CustomPropertyTable.Add(iDict.Key, iDict.Value);
                        }
                        catch (System.Exception ex)
                        {
                            Debug.WriteLine(ex.Message + "\n" + ex.StackTrace);
                        }
                        break;
                    }
                }
            }
            catch (System.Exception ex)
            {
                Debug.WriteLine(ex.Message + "\n" + ex.StackTrace);
            }

            db.SummaryInfo = DbSib.ToDatabaseSummaryInfo();
        }

 

 It would be on line 7 above.

 

EDIT: I see what you mean about it being part of the wrong database transaction... Not entirely sure how to go about changing that to make it work now though.

Message 8 of 8

Alright, so you were correct it should have been Database(false, true). Then the wrong transaction was being passed into the function I posted above, obviously causing it to fail.

 

Thanks for the keen eye(s)!

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report