.Net WblockCloneObjects please help

Hi …
This portion of code with C# does the copy between databases without error …

var mapping = new IdMapping();
using (var sourceDb = new Database(false, true))
{
    sourceDb.ReadDwgFile(xrpath, FileOpenMode.OpenForReadAndAllShare, true, "");
    ObjectId xrMsId = SymbolUtilityServices.GetBlockModelSpaceId(sourceDb);
    var ids = new ObjectIdCollection();
    using (var tr = new OpenCloseTransaction())
    {
        BlockTableRecord xrMS = (BlockTableRecord)tr.GetObject(xrMsId, OpenMode.ForWrite);
        foreach (ObjectId id in xrMS)
        {
            Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite);
            ent.TransformBy(EM);
            if (msg1.Contains(ent.Layer))
                ids.Add(id);
        }
    }
    var db = doc.Database;
    ObjectId MsId = SymbolUtilityServices.GetBlockModelSpaceId(db);
    sourceDb.WblockCloneObjects(ids, MsId, mapping, DuplicateRecordCloning.Ignore, false);
}

Here’s my attempt using python script in Dynamo…

# Load the Python Standard and DesignScript Libraries
import sys
import clr
import fnmatch

# Add Assemblies for AutoCAD and Civil3D
clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')

# axtra for ReadDwgFile
from System.IO import FileShare

# Import references from AutoCAD
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.EditorInput import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *

# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *


bn = IN[1] #example: "TAN"
LF = IN[2] #exxample: "ZONE*H*"

# missing ... user select nested enttity for the transform matrix

adoc = Application.DocumentManager.MdiActiveDocument
editor = adoc.Editor

xrefGraph = adoc.Database.GetHostDwgXrefGraph(True)
xrefNode = xrefGraph.GetXrefNode(bn)
xrpath = ""

with OpenCloseTransaction() as tr:
    xrbr = tr.GetObject(xrefNode.BlockTableRecordId, OpenMode.ForRead)
    xrpath = xrbr.GetXrefDatabase(False).Filename

ids = ObjectIdCollection()

with Database(False, True) as db:
    db.ReadDwgFile(xrpath, FileShare.ReadWrite, False, "")
    xrMsId = SymbolUtilityServices.GetBlockModelSpaceId(db);
    with OpenCloseTransaction() as tr:
        xrMS = tr.GetObject(xrMsId, OpenMode.ForWrite)
        for id in xrMS:
            try:
                ent = tr.GetObject(id, OpenMode.ForWrite)
                if fnmatch.fnmatch(ent.Layer,LF):
                    # ent.TransformBy(EM);
                    ids.Add(id)
            except:
                continue
        #
        #mapping = IdMapping()
        #MsId = SymbolUtilityServices.GetBlockModelSpaceId(adoc.Database)
        #db.WblockCloneObjects(ids, MsId, mapping, DuplicateRecordCloning.Ignore, False)
        #
        #with adoc.LockDocument():
        #    with adoc.Database as docdb:
        #        with docdb.TransactionManager.StartTransaction() as t: 
        #            mapping = IdMapping()        
        #            MsId = SymbolUtilityServices.GetBlockModelSpaceId(docdb)
        #            ms = t.GetObject(MsId,OpenMode.ForWrite)
        #            db.WblockCloneObjects(ids, MsId, mapping, DuplicateRecordCloning.Ignore, False)
        #            t.Commit()
        

OUT = ids

These lines result in Lock Violation error …

        mapping = IdMapping()
        MsId = SymbolUtilityServices.GetBlockModelSpaceId(adoc.Database)
        db.WblockCloneObjects(ids, MsId, mapping, DuplicateRecordCloning.Ignore, False)

And these lines result in error … was not open for write …

        with adoc.LockDocument():
            with adoc.Database as docdb:
                with docdb.TransactionManager.StartTransaction() as t: 
                    mapping = IdMapping()        
                    MsId = SymbolUtilityServices.GetBlockModelSpaceId(docdb)
                    ms = t.GetObject(MsId,OpenMode.ForWrite)
                    db.WblockCloneObjects(ids, MsId, mapping, DuplicateRecordCloning.Ignore, False)
                    t.Commit()

? I have something the wrong way around ?

Here are a few pointers to help clean up your code and get it working

With AutoCAD all actions on the document should be inside a transaction with a locked document
Following lines are outside the transaction

xrefGraph = adoc.Database.GetHostDwgXrefGraph(True)
xrefNode = xrefGraph.GetXrefNode(bn)
xrpath = ""

You also use the with OpenCloseTransaction() as tr: I have not used this class as typically a transaction is called on a particular database object. If you make any changes to the database a tr.Commit() should be called

In python the with statement is used to encapsulate code for cleaner execution as it automatically tries to clean up memory at completion. Nesting here is important. This line ids = ObjectIdCollection() brings the nesting back to the left and effectively closes the prior with statement so your transaction is now closed

Next you are trying to “side load” the xref database for Tan and transform all objects on layer(s) that match ZONE*H*. Note minor typo with a semi-colon at end of line 49

The python library fnmatch is for Unix filename matching and although it does work you could use string methods if ent.Layer.startswith("ZONE") and "H" in ent.Layer: or a regular expression if re.fullmatch("^ZONE.*H.*$", ent.Layer):

You will have to save the side loaded xref database for the changes to be permanent

I would look at Kean’s C# code for clues how to do this here → Modifying the contents of an AutoCAD xref using .NET

1 Like

Silly Me!!! It’s working now! … very first sentence … With AutoCAD all actions on the document should be inside a transaction with a locked document … that solved it …
Thank You!!!

1 Like