The problem appears to be that AutoCAD won't prevent the deletion of dictionary entries in the "acad_tablestyle" dictionary even if they are in use or active. Such hammer down deletion leaves tables referencing a deleted tablestyle knackered as AutoCAD does not update the table style reference (dxf code 342) in impacted ACAD_TABLE objects. In limited testing AutoCAD (2019) appears to fix it when saving.
I don't have time to better illustrate but if you view the attached image it details the labyrinth of references between associated table objects. (As noted above) When deleting a tablestyle unconditionally (highlighted in yellow) the reference in the table object (highlighted in red) do not appear to get updated, *boom*.
Here's some general use functions I pulled from my library and one penned for the task (max-purge-table-styles). Seems like a lot of code but it's generic (i.e. good library fodder) and relatively robust; speedy.
(defun max-get-block-defs-matching ( doc pattern / name result )
( (lambda ( pattern )
(vlax-for b (vla-get-blocks doc)
(and
(eq :vlax-false (vla-get-islayout b))
(eq :vlax-false (vla-get-isxref b))
(eq 'str (type (setq name (vl-catch-all-apply 'vla-get-name (list b)))))
(wcmatch (strcase name) pattern)
(setq result (cons b result))
)
)
(reverse result)
)
(strcase pattern)
)
)
(defun max-get-block-refs-matching ( doc pattern / result )
(vl-catch-all-apply 'eval
'( (setq result
(apply 'append
(mapcar 'max-get-block-refs
(max-get-block-defs-matching doc pattern)
)
)
)
)
)
result
)
(defun max-get-block-refs ( block / result )
(vl-catch-all-apply 'eval
'( (setq result
(vl-remove nil
(mapcar
(function
(lambda ( p / v )
(if (eq 331 (car p))
(if (null (vlax-erased-p (setq v (cdr p))))
(if (entget v) (vlax-ename->vla-object v))
)
)
)
)
(entget (vlax-vla-object->ename block))
)
)
)
)
)
result
)
(defun max-item ( collection key / result )
(vl-catch-all-apply 'eval
'((setq result (vla-item collection key)))
)
result
)
(defun max-items ( collection / result )
(vl-catch-all-apply 'eval
'((vlax-for x collection (setq result (cons x result))))
)
(reverse result)
)
(defun max-purge-table-styles ( doc )
( (lambda ( in-use / name deleted )
(foreach style (max-items (max-item (vla-get-dictionaries doc) "acad_tablestyle"))
(if (not (member (strcase (setq name (vla-get-name style))) in-use))
(if (vlax-erased-p (progn (vl-catch-all-apply 'vla-delete (list style)) style))
(progn
(if *debug* (princ (strcat "\nDeleted table style: \"" name "\".")))
(setq deleted (cons name deleted))
)
(if *debug* (princ (strcat "\nFailed to delete table style: \"" name "\".")))
)
(if *debug* (princ (strcat "\nTable style: \"" name "\" in use, did not delete.")))
)
)
deleted ;; return list of the tablestyles deleted to the caller
)
(mapcar 'strcase
(append
(list (getvar 'ctablestyle) "Standard")
(mapcar 'vla-get-stylename (max-get-block-refs-matching doc "`*T#*"))
)
)
)
)
Run on your goodtable.dwg:
(setq *debug* t)
(vl-load-com)
(max-purge-table-styles (vla-get-activedocument (vlax-get-acad-object)))
Table style: "BOM" in use, did not delete.
Table style: "Index FedExTB" in use, did not delete.
Table style: "Standard" in use, did not delete.
Cheers.