What helps you decide if something was successful or failed is very specific o what you do. As Mike already said TRY..CATCH..FINALLY only is one answer. If you save buffered changes of a table with TABLEUPDATE() it has a return value .T. or .F. stating success or failure/conflicts, if you use SQLExec() it has a return value meaning a status.
Not all failures create an error trapped by CATCH or ON ERROR, so also your own code should verify its own success and report it back in one or the other way. Whatever suits best. You might even use ERROR to cause an error, if some needed precondition isn't met.
There is no general way of doing things, just very many good principles. Mike already mentioned one: To give progress feedback in case something takes long. Processing any DBF can be short or long, depends on how much data there is in it. 2GB is not processed fast, for example.
In the task you describe sufficient code would do
Code:
Local lcStep, llSucess
TRY
llSucess = .T. && assume we'll have no problem
lcStep = "Retreiving data"
SELECT something FROM somewhere INTO CURSOR csrPreresult READWRITE
lcStep = "Transforming data"
UPDATE crsPreresult SET somecolumn = "0"+somecolumn
lcStep = "Creating dbf"
COPY TO somefilename.dbf
USE crsPreresult
Messagebox("The output dbf was created")
CATCH
llSucess = .F.
Messagebox("The output dbf was not created. Failing at "+lcStep)
ENDTRY
RETURN llSuccess
This is putting the message in a somewhat user friendly manner, though most users won't know the single steps involved in creating the output dbf file, would they?
You can have more detailed and valuable info on what did go wrong for you as developer, by CATCH TO loException. This Exception object then tells more, eg an error number, message, line number of the failing line etc., for example the SELECT query can fail on "somewhere" not existing, "somewhere" not being accessible to the user or the query creating a too large crsPreresult cursor or network errors or, or, or.., as a developer you would want to know and the CATCH TO loException would tell more. In the same manner the routine triggered by any error can get info via AERROR(), LINENO() and more functions.
You can't be prepared for any thinkable failure of other software, hardware or administrative circumstances.
Using lcStep to give the user a hint what exactly failed doesn't need to be done for each line of code, often enough not at all, knowing you fail at this block of code might be sufficient.
Bye, Olaf.