Author Topic: Help with WBlockCloneObjects  (Read 14935 times)

0 Members and 1 Guest are viewing this topic.

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Help with WBlockCloneObjects
« Reply #30 on: March 17, 2011, 05:42:50 PM »
I was thinking it was the same as in the issue of making a document current.  Not sure if changing the document to active within the editor makes it current, when another document is what called the program, and that is in essence the current document.  That is how the thinking went on in my head at least.

Quote from: Arx help: Accessing the Current Document and Its Related Objects
The key call an ObjectARX application must make when it gains control is to find out the current document, which can be accomplished with the function acDocManager->curDocument().

Note  The current document is not always the active document. This is the case during transitional states, such as when the documentToBeActivated() reactor occurs. Do not attempt extensive processing during transitional states. Consider using mdiActiveDocument() if you are interested in the active document.
From the current document, you can determine the current database, the relevant transaction manager, and your application's associated document-specific state, and then do whatever needs to be done before returning.

Once a command has stored the current document and associated information on its stack, it does not need to query the current document again until completion. Whenever a prompt for user input is made, the user can switch documents, but if that is done, the current command is suspended and its stack state is saved until the document is reactivated.

If your application is operating from the application execution context, it must lock and unlock the current document to modify anything associated with it. It can do so by directly invoking the AcApDocManager::lockDocument() and unlockDocument() member function.

If your application is operating from an ObjectARX or AutoLISP function, no locking should be necessary, as the system establishes the locks and removes them automatically around commands and AutoLISP expressions.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Help with WBlockCloneObjects
« Reply #31 on: March 17, 2011, 05:43:17 PM »
I remember Tony T telling me that .Net could not set a document current within a code.  Current document does not mean the active one in reality.  I wonder if that is the issue you are having, and if it is, if you can ever hope to get it working with .Net.  You can set a document current with Arx though.  I'll see if I can find the post.  I think it's on the Adesk site.

Maybe a P/Invoke would work?

Edit:  Found post.  Look at his second in this thread.
[ http://forums.autodesk.com/t5/NET/Updating-blocks-in-open-non-current-drawing/m-p/2678788/highlight/true#M19093 ]

It's unfortunate that Tony's posts at Augi are not displaying.



Hi Jeff_M,

and here it is a binary file to run a test under 2010 or 2011 and see if works in c3d, it is a quick one no more than 20-30 minutes of coding...
< .. >

Luis, What does your solution entail ?
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

LE3

  • Guest
Re: Help with WBlockCloneObjects
« Reply #32 on: March 17, 2011, 05:44:10 PM »
...C3D2010 it works, Luis. This is quite fast, but it looks like it uses the same idea Jeff_H used of not making each drawing current. If so, the .NET version works, too, but not quite as quickly.
From arx you can do something like(have not tried the same from C#):
Code: [Select]
AcApDocumentIterator *pIter = acDocManager->newAcApDocumentIterator();
for (; !pIter->done();)
{
AcApDocument *pDoc = pIter->document();
// avoid target drawing - grab ids from the other ones opened...
if (pCurDoc != pDoc)
{
if (acDocManager->setCurDocument(pDoc) == Acad::eOk && acDocManager->lockDocument(pDoc) == Acad::eOk)
{
ids.removeAll();
ScanForAllBlockReference(ids);
if (ids.length() >0)
{
for (int i = 0; i < ids.length(); i++)
{
allIds.append(ids[i]);
}
}
acDocManager->unlockDocument(pDoc);
}
}
pIter->step();
}
delete pIter;

Then from the above, you call: wblockCloneObjects on the current drawing, create the table and do the insert.

LE3

  • Guest
Re: Help with WBlockCloneObjects
« Reply #33 on: March 17, 2011, 05:47:53 PM »
Luis, What does your solution entail ?
Just posted the main part of the code.

I also knew about Tony wrapper solution, but it is not avail anymore...

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Help with WBlockCloneObjects
« Reply #34 on: March 18, 2011, 12:08:03 AM »
Could the database used to call member function WblockCloneObjects cause problems?

I have done litte testing but worked fine for each scnerio.

It did not matter which Database I used

From post http://www.theswamp.org/index.php?topic=37401.msg425024#msg425024
Code: [Select]
                            ObjectIdCollection objIdCollection = new ObjectIdCollection();
                            objIdCollection.Add(btr.ObjectId);
                            IdMapping idMap = new IdMapping();
                            openDatabase.WblockCloneObjects(objIdCollection, db.BlockTableId, idMap, DuplicateRecordCloning.Ignore, false);
replacing openDatabase with wb
Code: [Select]
                          db.WblockCloneObjects(objIdCollection, db.BlockTableId, idMap, DuplicateRecordCloning.Ignore, false);


Worked for switching active document and did it with db and openDatabase for calls to member function WblockCloneObjects

Code: [Select]
[CommandMethod("ImportBlocks3", CommandFlags.Session)]
        public void ImportBlocks3()
        {
            List<string> blockNames = new List<string>(); // A generic list to keep up with all blocks to check later if a block has already inserted.

            DocumentCollection documents = Application.DocumentManager; // All the current open documents

            Document doc = Application.DocumentManager.MdiActiveDocument; // Active Document
            Editor ed = doc.Editor; // Active Document's Editor
            Database db = doc.Database; // Active Document Database

            Document openDocument; // Temporay variable to hold each non-active Document
            Database openDatabase; //Temporay variable to hold each non-active Document's Database

            using (DocumentLock doclock = doc.LockDocument()) // Start Lock on Active Document
            using (Transaction trx = db.TransactionManager.StartTransaction()) // Start Transaction with Active Document's Database
            {
                // Start looping through each document
                foreach (Document document in documents)
                {
                    openDocument = document;
                    string fileName = openDocument.Name;
                    openDatabase = openDocument.Database;

                    // If the document is the current or Active document skip it
                    if (doc.Name == fileName || fileName == null || fileName == String.Empty)
                        continue;

                    documents.MdiActiveDocument = openDocument;
                    using (Transaction openDbTrx = openDatabase.TransactionManager.StartTransaction())
                    {//Start Transaction with Open Document's Database

                        BlockTable openBlockTable = openDbTrx.GetObject(openDatabase.BlockTableId, OpenMode.ForRead) as BlockTable;

                        // Loop through each BlockTableRecord
                        foreach (ObjectId btrId in openBlockTable)
                        {
                            BlockTableRecord btr = openDbTrx.GetObject(btrId, OpenMode.ForRead) as BlockTableRecord;
                            // Make sure it is not a ModelSpace or any of the PaperSpaces, any type of Xref
                            // or MEP type Object, or has already been clone before etc.... & and the block has been inserted at least once
                            if (btr.IsLayout || btr.IsAnonymous || btr.IsFromExternalReference || btr.IsFromOverlayReference || blockNames.Contains(btr.Name)
                                || btr.Name.StartsWith("Aec", StringComparison.OrdinalIgnoreCase) || btr.Name.StartsWith("_")
                                || btr.GetBlockReferenceIds(true, false).Count < 1)
                                continue;
                            //Add Block to list of blocks
                            blockNames.Add(btr.Name);

                            //Do Cloning
                            ObjectIdCollection objIdCollection = new ObjectIdCollection();
                            objIdCollection.Add(btr.ObjectId);
                            IdMapping idMap = new IdMapping();
                            openDatabase.WblockCloneObjects(objIdCollection, db.BlockTableId, idMap, DuplicateRecordCloning.Ignore, false);

                        }
                        openDbTrx.Commit();
                    }//End Transaction with Open Document's Database
                    openDatabase.Dispose(); // Dispose Database
                }// End foreach
                trx.Commit();
            }// End Lock on Active Document & Transaction with Active Document's Database
            documents.MdiActiveDocument = doc;
        }

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Help with WBlockCloneObjects
« Reply #35 on: March 24, 2011, 01:46:06 PM »
Well I submitted this to ADN late last week. After 2 techs looked at it, it was concluded that Civil3D (and, presumably, all the verticals that use the Aec* base) needs to have the target drawing for the blocks to be current at the time of the WblockCloneObjects().  I still have a bunch of testing to do with my full code, but initial tests show that this does solve the problem.

Thanks to everyone for their input!

Code: [Select]
[CommandMethod("InsertBlocks", CommandFlags.Session)]
        static public void InsertBlocks()
        {
            List<string> blockNames = new List<string>();
            DocumentCollection documents = Application.DocumentManager;
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db  = doc.Database;

            foreach (Document openDocument in documents)
            {
                ObjectIdCollection objIdCollection = new ObjectIdCollection();
                IdMapping idMap = new IdMapping();

                string fileName = openDocument.Name;

                if (doc.Name == fileName || fileName == null || fileName == String.Empty)
                    continue;

                // Needed for Civil 3D since it works on the active document.
                Application.DocumentManager.MdiActiveDocument = openDocument;

                using (Transaction openDbTrx = openDocument.Database.TransactionManager.StartTransaction())
                {
                    BlockTable openBlockTable = openDbTrx.GetObject(openDocument.Database.BlockTableId, OpenMode.ForRead) as BlockTable;

                    foreach (ObjectId btrId in openBlockTable)
                    {
                        BlockTableRecord btr = openDbTrx.GetObject(btrId, OpenMode.ForRead) as BlockTableRecord;

                        if (btr.IsLayout || btr.IsAnonymous || btr.IsFromExternalReference || btr.IsFromOverlayReference || blockNames.Contains(btr.Name)
                            || btr.Name.StartsWith("Aec", StringComparison.OrdinalIgnoreCase) || btr.Name.StartsWith("_")
                            || btr.GetBlockReferenceIds(true, false).Count < 1)
                            continue;

                        blockNames.Add(btr.Name);
                        objIdCollection.Add(btr.ObjectId);
                    }
                    openDbTrx.Commit();
                }

                using (DocumentLock doclock = doc.LockDocument())
                {
                    // Needed for Civil 3D since the destination database has to be active.
                    Application.DocumentManager.MdiActiveDocument = doc;
                    openDocument.Database.WblockCloneObjects(objIdCollection, db.BlockTableId, idMap, DuplicateRecordCloning.Ignore, false);
                }
            }
        }