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

Copy Layout & its viewports from dwt/dwg

5 REPLIES 5
Reply
Message 1 of 6
Bica.Bogdan
1042 Views, 5 Replies

Copy Layout & its viewports from dwt/dwg

Hello. I've been trying unsuccesfully to copy a layout and its viewports from a dwt/dwg file. I'll post some of the code, leaving out the failure checks, since none of the function calls failed in my tests. I know the functionality already exists, but we need an automated process for our purposes.

 

AcDbDatabase *pTempAcDbDatabase = new AcDbDatabase(false, true);
es = pTempAcDbDatabase->readDwgFile(szProjectName, _SH_DENYNO);

AcDbDictionary *pAcDbDictionary = acadGetLayoutDictionary(pTempAcDbDatabase);

I then retrieve the layout i am interested in, as an AcDbLayout*

 

AcDbObjectId layoutId,blockTableRecordId;
AcDbLayout *pAcDbLayout = NULL;
es = pLayoutMng->createLayout(szLayoutName,layoutId,blockTableRecordId); assert(es == Acad::eOk);
es = acdbOpenObject(pAcDbLayout,layoutId,AcDb::kForWrite); assert(es == Acad::eOk);
es = pAcDbLayout->copyFrom(pAcDbOrigLayout); assert(es == Acad::eOk);

es = pAcDbLayout->close();

pLayoutMng->updateLayoutTabs();
pLayoutMng->updateCurrentPaper();
es = pLayoutMng->setCurrentLayout(szLayoutName);

 

It works fine if i keep to just copying the layout

 

I have tried two different methods of copying the viewports, i'll describe the symptoms

Method 1

AcDbBlockTable *pTable;
AcDbBlockTableRecord *pPsBTR;
AcDbObjectId pPsBTRId;
if (Acad::eOk == acdbHostApplicationServices()->workingDatabase()->getBlockTable(pTable, AcDb::kForRead))
if (Acad::eOk == pTable->getAt(ACDB_PAPER_SPACE, pPsBTR, AcDb::kForWrite))
pPsBTRId = pPsBTR->objectId();
AcDbObjectIdArray viewportArray = pAcDbOrigLayout->getViewportArray();
viewportArray.removeAt(0);

 

AcDbIdMapping idMapping;
es = pTempAcDbDatabase->wblockCloneObjects(viewportArray, pPsBTRId, idMapping, AcDb::kDrcMangleName);
assert(es == Acad::eOk);

 

If i check with the GetViewportArray function for pAcDbLayout, it returns an array with the logical length of one, when i should have been five. 

i then close the original layout, new layout and layoutdictionary.

If i delete the pTempDatabase, i get a crash "error handle re-entered, exiting now" after i try to double click one of the viewports. I can't see anything through the viewports,

If i don't delete the pTempDatabase, i don't get any crashes, double clicking on the viewports doesn't let me "enter" them, nor can i see anything through them.

 

Method 2 gets the same results basically

 

AcDbObjectIdArray viewportArray = pAcDbOrigLayout->getViewportArray();
  for(int i=0; i<viewportArray.logicalLength(); i++)
    {
    AcDbViewport *pOldAcDbViewport;
    if(acdbOpenObject(pOldAcDbViewport, viewportArray[i], AcDb::kForRead) == Acad::eOk)
      {
      AcDbViewport *pNewAcDbViewport = new AcDbViewport(/*pOldAcDbViewport*/);       
      if(pNewAcDbViewport->copyFrom(pOldAcDbViewport) == Acad::eOk)
        {
        AcDbBlockTableRecord *pBtr = NULL;
        if(acdbOpenObject(pBtr, pPsBTRId, AcDb::kForWrite) == Acad::eOk)
           es = pBtr->appendAcDbEntity(pNewAcDbViewport); assert(es == Acad::eOk);
        es = pBtr->close(); assert(es == Acad::eOk);
        es = pNewAcDbViewport->close(); assert(es == Acad::eOk);
        }
      es = pOldAcDbViewport->close(); assert(es == Acad::eOk);
      }
  }

 

5 REPLIES 5
Message 2 of 6
fenton.webb
in reply to: Bica.Bogdan
Message 3 of 6
Bica.Bogdan
in reply to: Bica.Bogdan

So here i am with an update. I'm not sure of anything anymore, the error seems somehow related to a corruption error i get when exiting the program manually, not via "stop debugging", meaning it only manifest itself after i get that error. So it's probably not this code, since i've had this error since before i started working on this function.

Message 4 of 6
fenton.webb
in reply to: Bica.Bogdan

Try this...

 

1) In Visual Studio, select tools->options->debugging->symbols and add http://symbols.autodesk.com/symbols as a Symbol file (.pdb) location. Make sure All Modules are set to load at the bottom. 

2) Open your application project in Visual Studio and start debugging... This make time some time because the debug pdb's are being downloaded from http://symbols.autodesk.com/symbols to your symbol temp folder.

3) Once AutoCAD has finished loading, go back to Visual Studio and select Debugging->Exceptions... turn on all VS exception handlers.

4) Run your program as normal... Does VS ping up with any exceptions? If so, check the Callstack in Visual Studio - anything strange?

5) Quit AutoCAD, does VS ping up with any exceptions? If so, check the Callstack in Visual Studio - anything strange? Pint the callstack here...




Fenton Webb
AutoCAD Engineering
Autodesk

Message 5 of 6
Bica.Bogdan
in reply to: Bica.Bogdan

Sorry, i wasn't clear enough, the error when quitting the problem was on bricscad. So the new code still isn't working on brics, but that none of your concern.

In the new code, i used both the transaction manager and switching the current database, even though i would love a few pointer the when i should and when i should not switch the current database. Here's the code for a single layout copy. When i've got enought time i'll try and see wether it's the transaction manager or the changing of the current database that did the trick. Also, i'll try copying the viewportidarray directly.

      AcDbDatabase *pOldWorkingDatabase = acdbHostApplicationServices()->workingDatabase();      
      AcDbTransactionManager *pTransaction = acdbHostApplicationServices()->workingDatabase()->transactionManager();
      pTransaction->startTransaction();
      
      AcDbObjectId layoutId,blockTableRecordId;            
      AcDbLayout *pAcDbLayout = NULL;
      es = pLayoutMng->createLayout(szLayoutName,layoutId,blockTableRecordId,pOldWorkingDatabase);
      es = acdbOpenObject(pAcDbLayout,layoutId,AcDb::kForWrite);
      acdbHostApplicationServices()->setWorkingDatabase(pTempAcDbDatabase);   
      es = pAcDbLayout->copyFrom(pAcDbOrigLayout);
      acdbHostApplicationServices()->setWorkingDatabase(pOldWorkingDatabase); 		
      es = pAcDbLayout->close();      
      es = pLayoutMng->setCurrentLayout(szLayoutName);
     
      AcDbObjectId id = pAcDbOrigLayout->getBlockTableRecordId();      
      AcDbBlockTableRecord *pBTR = NULL;
      es = acdbOpenObject(pBTR, id, AcDb::kForRead);
      AcDbBlockTableRecordIterator *pIter = NULL;
      es = pBTR->newIterator(pIter);
      AcDbObjectIdArray objIdArray;
      for(;!pIter->done();pIter->step())
        {
        AcDbObjectId objectId;
        es = pIter->getEntityId(objectId);
        objIdArray.append(objectId);
        }
      delete pIter;
      es = pBTR->close();
      if(objIdArray.logicalLength() > 0)
        {
        acdbHostApplicationServices()->setWorkingDatabase(pTempAcDbDatabase);   
        AcDbIdMapping idMapping;     
        es = pOldWorkingDatabase->wblockCloneObjects(objIdArray, pAcDbLayout->getBlockTableRecordId(), idMapping, AcDb::kDrcMangleName); 
        acdbHostApplicationServices()->setWorkingDatabase(pOldWorkingDatabase);
        }
      es = pTransaction->endTransaction();

 

 

Message 6 of 6
Balaji_Ram
in reply to: Bica.Bogdan

You are right. Setting the workingdatabase is required for copying layouts.

 

Setting the working database should be avoided if possible, as it can make AutoCAD unstable.

But there are few examples like the one you have come across that still need setting of the working database.

 

In such cases, the setting of the working database and resetting it back should be limited to a small portion of your code.

 

The other API that I am aware of which also needs the setting of the working database is the "adjustAlignment" method.



Balaji
Developer Technical Services
Autodesk Developer Network

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

Post to forums  

Autodesk Design & Make Report

”Boost