AfraLisp Blog

The AutoLisp/Visual Lisp/VBA Resource Website

AfraLisp Blog

Home Newsletter Utter Rubbish Coding Tips AutoCAD Tips Contact Downloads WAUN

Error Trapping.

This was another area that caused me quite a bit of confusion when I was first learning AutoLISP. All AutoLISP routines should contain Error Trapping. There is nothing worse than running a routine and finding out that once it has run, or been cancelled, your system variables, etc. have all changed and nothing works the same any more.

I am going to look at two types of Error Trapping here. Firstly, an Error Trapping routine build into a function, and secondly, a Global Error Trapping function. But first, some background on the AutoCAD *error* function.

AutoLISP provides a method for dealing with user (or program errors).
It is one of the only AutoLISP functions that is user-definable.
This is the *error* function.

(*error* string)

It is executed as a function whenever an AutoLISP error condition exists.
If there is an error, AutoCAD passes one argument to *error*, which is a string containing a description of the error.

The following function does the same thing that the AutoLISP standard error handler does. Print error and the description. 

	(defun *error* (errmsg)
	 (princ "error: ")
	 (princ errmsg)
	 (princ)
	)
Before designing an Error Trapping function there is a couple of things to keep in mind.
First, the Error-Trap function must be called *error*. It also must have an argument passing variable. Our variable is called errmsg.
You can call this variable anything you like. Now, you can put anything you like in the body of this function. For example : 
	(defun *error* (errmsg)
	 (princ "\nAn error has occurred in the programme. ")
	 (terpri)
	 (prompt errmsg)
	 (princ)
	)

To test this error trap, create a lisp file with the preceding code and load the file. Begin running any program or command that you like. In the middle of the program hit ESC or Ctrl C. (AutoCAD thinks that this is an error.)
Control should be passed to the Error Trap.

It is important to note, and courteous, that you should never change a users settings, including an existing Error Trap, without first saving it as a variable and then replacing it at the end of the program.
Remember, as well, to place the replacement of this Error Trap in your Error Trap routine as your program could also crash.

Here is an example of Error Trap build into an AutoLISP routine : 

(defun c:drawline ()					;define function
	(setq temperr *error*)				;store *error*
	(setq *error* trap1)				;re-assign *error*
	(setq oldecho (getvar "cmdecho"))		;store variables			
	(setq oldlayer (getvar "clayer"))
	(setq oldsnap (getvar "osmode"))
	(setvar "cmdecho" 0)				;set variables
	(setvar "osmode" 32)
	(command "undo" "m")				;undo mark
	(setq pt1 (getpoint "\nPick First Point: "))	;get points
	(setq pt2 (getpoint pt1 "\nPick Second Point: "))
	(command "LAYER" "M" "2" "")			;change layer
	(command "Line" pt1 pt2 "")			;draw line
	(setq pt3 (getpoint pt2 "\nPick Third Point: "));get 3rd point
	(setvar "osmode" 0)				;switch off snap
	(command "Line" pt2 pt3 "")			;draw line
	(setvar "clayer" oldlayer)			;reset variables
	(setvar "osmode" oldsnap)
	(setvar "cmdecho" oldecho)
	(setq *error* temperr)				;restore *error*
   (princ)
)

(defun trap1 (errmsg)					;define function
	(command "u" "b")				;undo back
	(setvar "osmode" oldsnap)			;restore variables
	(setvar "clayer" oldlayer)
	(setvar "cmdecho" oldecho)
	(setq *error* temperr)				;restore *error*
	(prompt "\nResetting System Variables ")	;inform user
   (princ)
)

This routine simply asks for 3 points then draws a line, on layer 2, between them. As you can see, the existing (*error*) error trap is saved to the variable temperr. *error* is then re-assigned to the error trap, called trap1.
Any system variables such as object snaps and command echo, are saved as well as the current layer. An UNDO MARK is then put in place.
When an error occurs, the error trap first performs an UNDO BACK before resetting the drawing back to it's original settings.
Try choosing the first two points and then hitting ESC or Ctrl C.
Did you see what happened? The first line that was drawn was erased and your settings have been returned to their initial state.

The following is an example of an Error Trap using a Global Function :

Our drawline routine with some differences!!

(defun c:drawline ()					;define function
	(initerr)					;intit error
	(setvar "cmdecho" 0)				;reset variables
	(setvar "osmode" 32)
	(command "undo" "m")				;set mark
	(setq pt1 (getpoint "\nPick First Point: "))	;get points
	(setq pt2 (getpoint pt1 "\nPick Second Point: "))
	(command "LAYER" "M" "2" "")			;change layer
	(command "Line" pt1 pt2 "")			;draw line
	(setq pt3 (getpoint pt2 "\nPick Third Point: "));get 3rd point
	(setvar "osmode" 0)				;reset snap
	(command "Line" pt2 pt3 "")			;draw line
	(reset)						;reset variables
   (princ)
)

(princ)

Now our Global Error Trap named Error.Lsp 

(defun error()						;load function
(prompt "\nGlobal Error Trap Loaded")			;inform user
(princ)
);defun
;;;*==========================================================
(defun initerr ()					;init error
  (setq oldlayer (getvar "clayer"))			;save settings
  (setq oldsnap (getvar "osmode"))
  (setq oldpick (getvar "pickbox"))
  (setq temperr *error*)				;save *error*
  (setq *error* trap)					;reassign *error*
  (princ)
);defun
;;;*===========================================================
(defun trap (errmsg)					;define trap
  (command nil nil nil)
  (if (not (member errmsg '("console break" "Function Cancelled"))
      )
    (princ (strcat "\nError: " errmsg))			;print message
  )                 
  (command "undo" "b")					;undo back
  (setvar "clayer" oldlayer)				;reset settings
  (setvar "blipmode" 1)
  (setvar "menuecho" 0)
  (setvar "highlight" 1)
  (setvar "osmode" oldsnap)
  (setvar "pickbox" oldpick)
  (princ "\nError Resetting Enviroment ")		;inform user
  (terpri)
  (setq *error* temperr)				;restore *error*
  (princ)
);defun
;;;*===========================================================
(defun reset ()						;define reset
  (setq *error* temperr)				;restore *error*
  (setvar "clayer" oldlayer)				;reset settings
  (setvar "blipmode" 1)
  (setvar "menuecho" 0)
  (setvar "highlight" 1)
  (setvar "osmode" oldsnap)
  (setvar "pickbox" oldpick)
  (princ)
);defun
;;;*======================================================
(princ)

To run and test this you must load Error.Lsp before you load Drawline.Lsp.
As you can see, by using a Global Error routine you can save yourself the bother of writing individual error traps for each of your programs.
Error.Lsp could easily be loaded from your Acad.Lsp and would then be available whenever one of your routines wishes to call upon it.

Happy Error Trapping!!!!

 
The AutoLisp/Visual Lisp/VBA Resource Website

Copyright 1999-Perpetuity by AfraLisp

All rights reserved.
Information in this document is subject to change without notice.
Site created and maintained by Kenny Ramage

The AutoLisp/Visual Lisp/VBA Resource Website