MultiError is a small, command-line utility (à la ResFind) which you can call to generate a multi-tasking error or message window. It is intended to be used in your !Run files, but there's nothing to stop you using it from within your actual program to launch independent message windows. Apart from the multi-taskingness, it also provides an extra button which users can click on to visit a website and it logs the error message using SysLog. (These two "extras" are only implemented if relevant and possible on the user's system.)
MultiError is designed to be customisable and to integrate easily into your application. For instance, the message can be read via a token in your standard messages file, and the template can be taken from your standard Templates file. The ability to use tokens means you can "internationalise" your !Run file error messages easily. MultiError is in the public domain so you can even fiddle with the code to your heart's content.
I've packaged it up in a very simple example program which you can download here. The latest version is 1.02. The package includes a skeleton "internationalised" application structure with some examples of the use of MultiError. Double-clicking on the application gives a very simple example. For a variety of annotated examples, have a look at !LongRun in the application directory.
MultiError is called using a command which might look like:
<Foo$Dir>.MultiError -template <Foo$Dir>.Templates -text "This is a test message"
Note that Templates
(the name is unimportant) can either be a dedicated templates file or the templates file which you're already using for your application. In either case, it should contain a template called ME_Message
which meets a few criteria:
The text in the buttons, the size and shape of the window, the presence (or otherwise) of window furniture and the number of other icons and objects in the window are all completely up to you.
If you would like the message to be read from a Messages file, then instead of supplying a string preceded by -text
, you should provide a reference to the location of the messages file, together with the name of the token to be found. For instance:
<Foo$Dir>.MultiError -t <Foo$Dir>.Templates -m <Foo$Dir>.Messages -k error_pimodnotfound
Notice that short forms of the switches can be used in place of the long, descriptive, forms. The full list of switches (in both long and short form) for the MultiError command is as follows:
-q|-quiet
(suppresses the system beep generated when the message window appears)
-n|-nofocus
(stops MultiError grabbing the input focus when the message window appears)
-t|-template <template file location>
-m|-messagefile <messages file location>
-k|-token <message token>
-p|-parameter <message token parameter>
-e|-text <Some plain text>
-l|-logname <Task name for use with SysLog>
(max. 10 characters)
All the switches are optional, but please note that:
-e
will be ignored if -m
and -k
are present and successfully interpreted.
-p
s to use as parameters when looking up the message token. They are read in the order they're presented.
-t
is not present, an inbuilt template definition will be used.
-l
is not present, an attempt will be made to guess at a useful name from the path to MultiError. It will start with "ME_"
-e
will be assumed.
MultiError This is an error message
will be interpreted sensibly. This gives some backwards compatibility with the RISC OS *Error
command.
MultiError uses about 40K of memory, so if calling it from an obey file, you should set an appropriate minimum slot size first.
In contrast to the RISC OS Error
command, MultiError will not stop the flow of the script or program which calls it. If you're using MultiError in a !Run file, you may well wish to do this however. (For instance, to prevent your program running if a certain module is not present.) A suggested way of achieving this is as follows:
At the beginning of your !Run file, include a line such as:
Set FooProg$CarryOn "True"
Next, carry out the tests which you need to perform for your program to start up and alter the CarryOn
variable as necessary. For example:
RMEnsure PiModule 3.14 IfThere System:Modules.PiModule Then RMLoad System:Modules.PiModule
RMEnsure PiModule 3.14 <FooProg$Dir>.MultiError -t <FooProg$Dir>.Templates -e Sorry, PiModule not found.
RMEnsure PiModule 3.14 UnSet FooProg$CarryOn
Finally, only call your main program if no errors have occurred:
If "<FooProg$CarryOn>" = "True" Then Run <FooProg$Dir>.!RunImage
To see this in action, look at the example !LongRun file provided. Note the use of IfThere
in the above example. If that wasn't included then a non-multitasking error box (with a pretty unhelpful error message) would be generated if the specified module wasn't present in System.
Note: Early versions of MultiError used a different syntax. If you'd like to look at the legacy instructions for versions up to 0.29, please click here.
I've tried to make MultiError as robust as possible. In particular, you might be worried about it accessing your templates and messages files. This shouldn't be a problem: MultiError opens, reads and closes the templates file before its first poll loop. The same goes for the messages file unless it's already open, in which case the token value is read from RAM and the file left well alone. If you're still worried, there's nothing stopping you specifying separate files for exclusive use with MultiError. You're also free to modify MultiError as you see fit - though I'd appreciate it if you could report any bugs or improvements to me, if possible.
MultiError checks for the presence of the SysLog module and, if it exists, will log error messages using the SysLog SWIs. Unless specified using the -l
switch, the task name sent to SysLog is ME_Foo, where Foo is guessed-at from the command line passed to MultiError. If MultiError can't make a guess at Foo, it'll just use "MultiError". In general, the message presented to the user (in the case of an internal error) won't be particularly helpful for de-bugging, though a more relevant error message will be passed to SysLog.
MultiError uses the standard MessageTrans SWIs, so token lookups and parameter substitution are performed in the standard way.
If the message passed to MultiError contains the string http
then MultiError will check for the presence of the AcornURI module and use the URI_Dispatch SWI to launch the URL when button number 3 is clicked on. If the string does not contain http
or AcornURI is not present, then the icon is deleted before the message window is opened.
That's about it. I hope you find some use for MultiError and I'd be very interested to hear from you if do (or if you find any bugs!). If you'd like to get in touch, please email me at riscos@snowstone.org.uk.
Last update: 8th September 2007