Recently spotted some AutoLISP code on web, which was supposed to remove the embedded VBA macros from the current AutoCAD database.
(defun removeEmbedMacro()
(entdel (cdr (car (dictsearch (namedobjdict) "ACAD_VBA"))))
)
It has a serious problem. If there are no VBA macros embedded into the current database or the code has run once against the existing ACAD_VBA dictionary, a coding error will be reported onto the command line.
Command: (removeEmbedMacro)
; error: bad argument type: lentityp nil
If the LISP function were tested a bit carefully, the problem would have shown up naturally. If the code were debugged through, it would have been found out very easily that the dictsearch AutoLISP function returned ‘nil’ if the ACAD_VBA dictionary was not there or had been removed already.
Is it a big deal?
Of course, it is. As clearly declared by the error message, some LISP function calls have been fed a ‘bad argument’, which means coding problem instead of user error. By the way, if a similar thing happens in AutoCAD .NET, an exception will likely be thrown out and the whole application will be aborted due to the problem; in ObjectARX/C++ however, if the case is not addressed properly, AutoCAD will just crash.
Is it too hard to address so common a scenario?
Not at all. A simple return value check does it. Of course, it’s better to print out something to let users know about it.
(defun removeVBAEmbedMacroIfApplicable()
(setq vbaMacroDict (dictsearch (namedobjdict) "ACAD_VBA"))
(if (/= vbaMacroDict nil)
(entdel (cdr (car vbaMacroDict)))
(print "No VBA-Macro has been embedded.")
)
(princ)
)
Command: (removeVBAEmbedMacroIfApplicable)
"No VBA-Macro has been embedded."
The guy might argue again that making the code bulletproof is hard and unnecessary in this case and his making the code look that way is for READBILITY and SIMPLICITY.
He had forgotten a simple fact, as discussed in detail before, all the READBILITY and SIMPLICITY things must serve for one aim, making the code work reliably enough first.
If he is not good at real coding, it is not a big problem. Presenting some pseudo code but making the coding logic right like the following should work better, at least not causing confusions to or misleading newbie programmers.
dict = dictsearch "ACAD_VBA" in namedobjdict
if dict <> nil
delete dict
else
alert user
return
If the guy were really good at wording, a single sentence would have made it clear too.
All AutoCAD embedded VBA macros are stored in a sub-dictionary ACAD_VBA in the Named Object Dictionary, so deleting the ACAD_VBA dictionary using any AutoCAD APIs including AutoLISP will remove all the embedded macros.
Here's another way: (dictremove (namedobjdict) "ACAD_VBA")
Posted by: Jimmy Bergmark - JTB World | 10/27/2012 at 08:08 AM
JTB, thanks a lot for the tip. Your way is absolutely better!
Posted by: Spiderinnet1 | 10/27/2012 at 09:00 PM