How to remove objects from a drawing

I have several objects on a DWG drawing that I want to delete when I load the drawing. It is a single block that is in one specific layer and used all over the drawing.
So what I want is some way to check if an object on screen is this specific one and remove it. I couldn't find any examples for this. I only found one example that loops through all objects on screen and I was able to detect the ones I want to remove, but how to remove them? I tried several things but nothing worked.

This is the program code I tried:

void deleteObjects()
{
AcDbBlockReference* pBlockRef;
AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase();

// Get the current space object
AcDbBlockTableRecord* pBlockTableRecord;
Acad::ErrorStatus es = acdbOpenObject(pBlockTableRecord, pDb->currentSpaceId(), AcDb::kForRead);

// Create a new block iterator that will be used to step through each object in the current space
AcDbBlockTableRecordIterator* pItr;
pBlockTableRecord->newIterator(pItr);

// Create a variable AcDbEntity type which is a generic object to represent a Line, Circle, Arc, among other objects
AcDbEntity* pEnt;

// Step through each object in the current space
for (pItr->start(); !pItr->done(); pItr->step())
{
// Get the entity and open it for read

pItr->getEntity(pEnt, AcDb::kForRead); // I tried to put kForWrite here instead but that crashed the program instead

TCHAR* layerName = pEnt->layer();

// Check if entity is on the layer we want
if (_tcscmp(layerName, LAYERSTR_OFFSET) == 0)
{
// This works so that when I am here it is for one of the objects I want to remove

pEnt->erase(); // This doesn't work so it wasn't that easy
/*
// I tried the following code to see if that helped but no result
pBlockRef = AcDbBlockReference::cast(pEnt);
bool bBlockFound = (pBlockRef != NULL);

if (bBlockFound)
{
pBlockRef->erase();
}*/
}
pEnt->close();
}

// Close the current space object
pBlockTableRecord->close();

// Remove the block iterator object from memory
delete pItr;
}

Comments

  • If you're open to LISP, then this is an easy thing to do.

    (ssget "X" '((0 . "INSERT")(2 . "BLOCK_NAME")(8 . "BLOCK_LAYER")))

    Will create a selection set of all the blocks called "BLOCK_NAME" on the the drawing that are on the layer "BLOCK_LAYER".

    You can use this to build a function to delete the blocks
    (defun DeleteBlocks ( / sset odoc ent num) 
    	(setq sset (ssget "X" '((0 . "INSERT")(2 . "BLOCK_NAME")(8 . "BLOCK_LAYER"))))
    	(cond 
    		(sset
    			(princ (strcat "\nFound " (itoa (sslength sset)) " Blocks to delete"))
    			(setq odoc (vla-get-activedocument (vlax-get-acad-object))) ; retrieve active document
    			(vla-endundomark odoc)
    			(vla-startundomark odoc) ; set undo mark
    			(setq num 0)
    			(foreach ent (vle-selectionset->list sset)
    				(if (entdel ent) (setq num (1+ num)))
    			)
    			(vla-endundomark odoc)
    			(princ (strcat "\nDeleted " (itoa num) " Blocks\n"))
    		)
    		(T (Princ "\nBlock not found.\n"))
    	)
    	num
    )
    You add a call to this function in your on_doc_load.lsp to run automatically each time a drawing file is opened.

    Regards,
    Jason Bourhill
    BricsCAD V22 Ultimate
    CAD Concepts
  • The purge command would permit you to select a specific block. Below would be the sequence of commands to use, with what I type in bold capitals. This example would purge all blocks named "door".

    PURGE
    Purge: BAtch/All/Blocks/Dimstyles/LAyers/LTypes/MAterials/MLinestyles/Plotstyles/STyles/Tablestyles/Visualstyles/Regapps: BLOCK
    Enter name(s) to purge <*>: DOOR <-TYPE THE NAME OF THE BLOCK</i>
    Verify each name to be purged? [Yes/No] : N
    :
    So, you could create a macro that you could manually run. Or if you wanted it to run automatically, then either save as a script, that you run from the startup lisp. Or even just use the command feature of LISP to send those commands.

    -Joe
  • I have never done anything with LISP, but this code needs to be inside the C++ application so it must be in C++ code. I just want to remove all objects of a specific block from the drawing and it must be some way to do it?
  • While sending keystrokes is not generally the best way to do things, just sending the keystrokes as though you were typing at a keyboard is one way to do it. Though I don't know if there is a way to get the program to run when a drawing opens, other than putting a command to load the C program inside the startup lisp file.

    -Joe
  • I found some examples using the acedSSGet function and that worked better. The following code almost works. It works first time I tries it, but if I open a new drawing it gives error "corrupt drawing, error in database" and with the debugger I can see that it is the acedSSGet command that crash, but why?

    ads_name pName;
    struct resbuf eb;
    TCHAR sbuf[100];

    eb.restype = 8; // Layer name filter
    _tcscpy(sbuf, LAYERSTR_OFFSET);
    eb.resval.rstring = sbuf;
    eb.rbnext = NULL;
    acedSSGet(_T("X"), NULL, NULL, &eb, pName); // Retrieve all entities on layer

    long number = 0;
    if ((acedSSLength(pName, &number) != RTNORM) || (number == 0))
    {
    acedSSFree(pName);
    }
    ads_name ent;
    AcDbObjectId id = AcDbObjectId::kNull;

    // Open to delete
    for (long i = 0; i < number; i++)
    {
    acedSSName(pName, i, ent) != RTNORM;
    acdbGetObjectId(id, ent);
    AcDbEntity* pEnt = NULL;
    acdbOpenAcDbEntity(pEnt, id, AcDb::kForWrite);
    pEnt->erase();
    pEnt->close();
    }
    acedSSFree(pName);
  • I removed everything so only this code is active and is triggered after a dwg file is loaded

    ads_name pName = { 0,0 };
    acedSSGet(NULL, NULL, NULL, NULL, pName);
    acedSSFree(pName);


    It still gives error. First time I load a drawing it works, but when I close the drawing and open it again (or another) it gives error that file is corrupt and database error.
  • I got the first version working. I just had to change the entity from read to write with "pEnt->upgradeOpen();" command and after that I could do erase on it, but why the second example isn't working is another thing.