If you do not trap the SYNTAX condition at all, your main script will abruptly abort when SYNTAX is raised. If you have data that may need to be saved to permanent media, it will be lost unless you have a FINALLY section which does the save. So too, if you have any handles to anything that are not maintained by Reginald or some other REXX add-on, these may not be properly closed unless your FINALLY section takes care of this.
Therefore, you should trap SYNTAX if you don't want your script to abort, and you should have a FINALLY section if you have any special cleanup that needs to be done before your script ends.
If you have created a standard Main Window Layout script, then it includes a CATCH instruction to handle SYNTAX condition raised in the main script. If a child script has a SYNTAX error, and doesn't have its own CATCH SYNTAX to handle it, then the main script's CATCH SYNTAX will deal with it as well.
The main script's CATCH SYNTAX simply posts a message box informing the user of an error, and then continues on with the message loop. So, some particular operation may be aborted, but otherwise, the main script will carry on.
The main script also has a FINALLY section to which you can add any special cleanup instructions.
Note: HALT condition is not raised in a GUI script unless you specifically use the RAISE instruction to raise it. If you do that, you should also CATCH HALT, or your script will abort.
Non-syntax errors
With the exception of GuiSay() and GuiInfo(), all GUI functions will return an empty string if successful, or an error message if a problem occurs. So, you can check the return from a GUI function, and if it's not an empty string, then do some error handling.
By default, you are expected to check the return string from any GUI function you call (except for GuiSay and GuiInfo) and do error handling if necessary. You will also need to take care of presenting a message to the user (if you desire that).
For example, consider the following instructions (note: we assume OPTIONS "C_CALL"):
/* Do user interaction. */ err = GuiGetMsg() /* Check if GuiGetMsg succeeded. */ IF err == "" THEN DO /* Yes, GuiGetMsg succeeded. Here, you would * determine who woke you up, and why. */ END ELSE GuiSay(err)Let's assume that you have not opened any GUI windows before calling GuiGetMsg. Reginald considers that to be an error. So what happens when you call GuiGetMsg? GuiGetMsg returns an error message of No open windows. You'll note above that we check whether GuiGetMsg has returned an empty string, and if not, then we display that error message to the user (using GuiSay's message box). Therefore, we properly check for errors above.
Error numbers versus strings
Every error message that a GUI function can return has a unique number associated with it. For example, the error number 114 is associated with the error message No open windows. If you prefer, each GUI function can return the error number instead of the error message (ie, 114 versus No open windows). To enable this option, you set a variable named GuiErr to the value 'NUM' (before calling any GUI functions) as so:
/* Return error numbers instead of messages. */ GuiErr = 'NUM'You need set GuiErr only once. Its setting will remain in effect until you either set it to some other value, or DROP it to restore the default error message returns.
/* Restore the default -- error messages. */ DROP GuiErrHere is each error number, and its respective message. Note that where you see part of a message enclosed within < and >, this will be replaced by some other, more detailed text in the error message.
Number | Message |
100 | Cancel |
101 | Out of memory for this operation |
102 | Object already has a window |
103 | An existing object must call this function |
104 | Bad filename |
105 | GUI block not found |
106 | WINDOW definition not found in GUI block |
107 | WINDOW x, y, width, and height must be whole numbers, or -1 for defaults |
108 | Control x, y, width, and height must be whole numbers |
109 | No open windows |
110 | Object doesn't have an open window |
111 | FONT height and width must be whole numbers |
112 | Window defaults can't be set while a window is still open |
113 | Not a window |
114 | Not a defined type of control |
115 | Error creating MENU heading <headingNum> |
116 | Error creating MENU item <headingNum> : <itemNum> |
117 | Error creating MENU item <headingNum> : <itemNum> : <subItemNum> |
118 | Unknown message string |
119 | Can't find the STRING definition named <name> |
120 | STRING definition is missing its DEND |
121 | Error adding the string: <string> |
195 | Message will vary. It concerns GuiCreateWindow failing to add the menu to the window |
196 | Message will vary. It concerns GuiSetCtlPlacement failing to move or resize the window |
197 | Message will vary. It concerns GuiWindowDefaults failing to register your chosen window defaults |
198 | Message will vary. It concerns bad styles specified for some control in your WINDOW definition when calling GuiCreateWindow, or passed to GuiAddControl |
199 | Message will vary. It concerns GuiCreateWindow failing to create the window |
200 | Message will vary. It concerns GuiMakeShortcut failing |
Adding a heading to the message/number
If desired, you can tell Reginald to preface the message or number with a heading. This heading will tell you which GUI function caused the failure. For example, if GuiGetMsg is called with no windows being open, then the error message will be DLL function "GUIGETMSG" reports "No open windows". This is more informative when you present the error message to the user.
To enable headings, you must set a variable named GuiHeading once:
/* Add a heading to error messages/numbers. */ GuiHeading = 1To restore the default of no headings, then DROP GuiHeading.
SYNTAX
Alternately, you can choose to have Reginald raise the SYNTAX condition when an error occurs with a GUI function.
If you have not set up your own SYNTAX handler in your script, then your script will immediately abort with a message box automatically displayed by Reginald. The message box will include the error message, the source line upon which the error occurred, the name of the script that caused the error, and a help button to bring up online help for that error.
On the other hand, if you've used CATCH SYNTAX to set up your own SYNTAX handler, then Reginald will automatically jump to that handler. You'll never even return from that call to GuiGetMsg. Rather, you'll jump out of GuiGetMsg and jump directly to your CATCH SYNTAX instructions. You can use CONDITION('D') to retrieve the error message (ie, here it would be No open windows or DLL function "GUIGETMSG" reports "No open windows", depending upon whether you have enabled headings), CONDITION('E') to fetch the error number associated with that message (ie, here it would be 110), and CONDITION('M') to display a message box to the user containing the error message.
To enable the SYNTAX reporting feature, set GuiErr to the value 'SYNTAX' before calling any GUI functions. Here, we enable the 'SYNTAX' option, and we CATCH SYNTAX. You'll note that we no longer have to check the return from GuiGetMsg. Why? Because if an error occurs, we will jump directly to the CATCH SYNTAX. So, it's irrelevant what GuiGetMsg returns.
/* Enable SYNTAX option and headings. */ GuiErr = 'SYNTAX' GuiHeading = 1 /* A useful option. */ OPTIONS "C_CALL" /* Do our event loop. */ EventLoop: DO FOREVER /* Do user interaction. */ GuiGetMsg() /* GuiGetMsg succeeded if we didn't jump to CATCH SYNTAX. * So here, you would determine who woke you up, and why. */ CATCH SYNTAX /* Display an error message. */ CONDITION('M') /* We'll drop out of the DO FOREVER loop now. If * you wish to instead attempt to recover, you * would SIGNAL to the EventLoop label. */ /* NOTE: If you have any special cleanup code, then put * a FINALLY instruction here, followed by your * cleanup instructions. */ END
Note: Unless you create an Empty Window Layout script with REXX Programmer Center's resource editor, then the script automatically sets the GuiErr and GuiHeading variables such that SYNTAX condition is raised for GUI errors, and a heading is prepended to the error message.
ERROR
Another alternative you have is for Reginald to raise the ERROR condition when an error occurs with a GUI function.
If you have not set up your own CATCH ERROR handler, then the GUI function will simply return the error message as it does by default. Your script will not abort. Of course, you should check the return string for an error message in this case.
On the other hand, if you've used CATCH ERROR to set up your own ERROR handler, then Reginald will automatically jump to your CATCH ERROR instructions, just like in our SYNTAX example above.
To enable the ERROR reporting feature, set GuiErr to the value 'ERROR' before calling any GUI functions.
/* Raise ERROR whenever a GUI function has an error. */ GuiErr = 'ERROR'
FAILURE
Another alternative you have is for Reginald to raise the FAILURE condition when an error occurs with a GUI function.
If you have not set up your own CATCH FAILURE handler, then the GUI function will simply return the error message as it does by default. Your script will not abort. Of course, you should check the return string for an error message in this case.
On the other hand, if you've used CATCH FAILURE to set up your own FAILURE handler, then Reginald will automatically jump to your CATCH FAILURE instructions, just like in our SYNTAX example above.
To enable the FAILURE reporting feature, set GuiErr to the value 'FAILURE' before calling any GUI functions.
/* Raise FAILURE whenever a GUI function has an error. */ GuiErr = 'FAILURE'
USER
Another alternative you have is for Reginald to raise one of the USER conditions when an error occurs with a GUI function.
If you have not set up your own CATCH USER handler, then the GUI function will simply return the error message as it does by default. Your script will not abort. Of course, you should check the return string for an error message in this case.
On the other hand, if you've used CATCH USER to set up your own USER handler, then Reginald will automatically jump to your CATCH USER instructions, just like in our SYNTAX example above.
To enable the USER reporting feature, set GuiErr to the number of the desired USER condition before calling any GUI functions. Here, we have modified our event loop to use USER 10 condition:
/* Enable USER 10 option and headings. */ GuiErr = 10 GuiHeading = 1 /* A useful option. */ OPTIONS "C_CALL" /* Do our event loop. */ EventLoop: DO FOREVER /* Do user interaction. */ GuiGetMsg() /* GuiGetMsg succeeded if we didn't jump to CATCH USER 10. * So here, you would determine who woke you up, and why. */ CATCH USER 10 /* Display an error message. */ CONDITION('M') /* We'll drop out of the DO FOREVER loop now. If * you wish to instead attempt to recover, you * would SIGNAL to the EventLoop label. */ /* NOTE: If you have any special cleanup code, then put * a FINALLY instruction here, followed by your * cleanup instructions. */ END