'=========================================================================== ' Subject: ASSEMBLY IN QBASIC 8: ERROR Date: 04-21-97 (15:45) ' Author: Rick Elbers Code: QB, QBasic, PDS ' Origin: rick@tip.nl Packet: ASMCODE.ABC '=========================================================================== 'ASSEMBLY IN QBASIC 8: ERRORHANDLING '--------------------------------------- 'RICK ELBERS APRIL 1997( this one thanks to Brian Mclaughlin) '--------------- 'INTRODUCTION '-------------- 'This might seem an easy and minor topic, but it is not. 'Getting errors before the program breaks, and return 'an appropriate message to the user, is what could make 'the difference so to speak. 'In general you should investigate your program and 'make an estimate for what could be expected errors. 'For instance when you prompt the user for a filename, 'and use OPEN [file] FOR INPUT AS [handle] after that, 'then there is a good chance that the file will not 'exist/ or the path will not exist. I think it is good 'habit to handle that errors IN your BASIC program, 'by redoing the userinput for instance. This might seem 'a trivial example, but it is not. Still a lot of QBASIC 'programs which handle userinput, do not have an 'appropriate ERRORHANDLER installed while that is very 'easy to do with ON ERROR GOTO ERRORHANDLER. 'ERRORHANDLING FOR ASSEMBLY ROUTINES '*********************************** 'Since the topic of this series is assembly in QBASIC 'I will not demonstrate ON ERROR GOTO here. When we 'are using assembly in QBASIC errorhandling is even more 'important. In a lot of cases the errorinformation 'returned from assembly routines is well documented and 'informative. So that gives you the chance to take 'appropriate action, before youre program has to quit 'on every error. For instance when you want to allocate '100 KB and the message returned says there is only '10 KB available you can prompt the user for making the 'choice to still allocate 10 KB or to use other measures. 'MINIMAL ERRORHANDLING '********************* 'What I consider the absolute minimum for EVERY assembly 'routine is: '1) Check for errors occuring. 'Although quit obvious, a lot of people using INTERRUPTX just 'forget about that. In case you use that INTERRUPTX you should 'test for the carry flag most of the time( flags and 1). '2) Print message about in what routine the error occurred. 'Not so obvious even to experienced programmers.. Take f.i that 'you are going to write a copy routine in asm, and an error is 'occuring while writing. In that case you have still to close 'source AND destiny. But when the error occurred while opening 'the destiny( say you do that after opening the source), then 'you ONLY need to close the SOURCE. And when the error occurred 'while opening the source you do not have to close any file at 'all. See why you need to know WHERE the error occurred ? '3) Print message what error occurred. 'This is probably the most obvious. THe dos errors are well known, 'so it won't be difficult to translate the errornumber( mostly but 'NOT always in AX) to the appropriate message. This is also where 'the concept MINIMAL is getting some meaning. Printing out the 'message about the error will not help much for taking action. 'Much better is of course to add a few errorhandling routines for 'the known errors of a routine. 'The points above can be operationalized for QBASIC as follows: 'ad 1) Assuming you last variable which you pass to the routine is 'some variable ERRS, you can use almost every time some routine 'like this: '[some routines use some value of AX( either 0 or 1) to indicate errors, 'but most of them use Carry flag] ' INT whatever ' JC errorhandling 'store needed: ' 'return to QBASIC: ' POP BP ' RETF N 'errorhandling: ' MOV BX,[BP+06] ' MOV [BX],AX ' JMP return to QBASIC: 'This routine is optimized for no_error! In fact the errorhandling is 'slow beyond belief[ two jumps taken and pipe line stall], but in case 'of error that is not so tragic. It writes NOTHING to the variable 'ERRS if there was no error, so ERRS will remain the same as before. 'Apart from making better optimizing that is also better habit then 'writing 0 to it. When you always use the same ERRS then a former ERROR 'will still show in a later routine, which is nice double check!. 'ad 2) When you use simple asm routines which call only 1 interrupt or 'handler then you know on beforehand that the error reported has 'occured in that interrupt. Typically my QBASIC routines calling absolute 'are looking like this: 'DEF SEG=STRINGSEG 'CALL ABSOLUTE(VAR,VAR,VAR,ERRS,SADD(ROUTINE$) 'IF ERRS THEN ' PRINT "THERE WAS AN ERROR WHILE ......" 'ELSE ' PRINT "SUCCESFULLY DID ........." 'ENDIF 'Of course on .....you should fill in the routines exact purpose ( opening 'a file, allocating low memory etc..). 'When you use complex asm routines which are calling more interrupts, 'device drivers then you need some additions. First of all your asm 'routine needs to store a WHEREID in AH( AL contains dos error), which 'can be done using some algorithm like this: ' INT whatever ' MOV AH,WHEREID 'f.i 1st routine gets 0, 2nd 1 etc ' JC errorhandling 'store needed: ' 'return to QBASIC: ' POP BP ' RETF N 'errorhandling: ' MOV BX,[BP+06] ' MOV [BX],AX ' JMP return to QBASIC: 'Since MOV does not affect flags the JC jump is still valid. 'Note: An important trick for control of your errorhandling is 'to reverse the jumps 'In addition to this errorhandling in asm routine you also need 'some addition in the calling absolute statements like so: 'DEF SEG=STRINGSEG 'CALL ABSOLUTE(VAR,VAR,VAR,ERRS,SADD(ROUTINE$) 'IF ERRS THEN ' WHEREID=(ERRS/&H100)AND &HFF:ERRS=ERRS AND &HFF ' SELECT CASE WHEREID ' CASE 1 ' PRINT "THERE WAS AN ERROR WHILE ......" ' CASE 2 ' PRINT "THERE WAS AN ERROR WHILE......." ' CASE 3 ' PRINT "THERE WAS AN ERROR WHILE......." ' END SELECT 'ELSE ' PRINT "SUCCESFULLY DID ........." 'ENDIF 'Of course this will not cut it in most cases since complex routines 'often needs actions to be taken on some errors, but this is the 'first necessary step! And even after action has been taken this kind 'of routine can tell you how far the routine has executed fine.. 'ad 3) For automating doserrorhandling I made the SUB ERRORHANDLING, '(with a change suggested by Tyler Barnes), which just prints the 'appropriate message if provided the errornumber. You should adjust 'your routines to call this routine after you print the WHEREID like 'this: 'DEF SEG=STRINGSEG 'CALL ABSOLUTE(VAR,VAR,VAR,ERRS,SADD(ROUTINE$) 'IF ERRS THEN ' PRINT "THERE WAS AN ERROR WHILE ......, " ' CALL ERRORHANDLING(ERRS) 'ELSE ' PRINT "SUCCESFULLY DID ........." 'ENDIF 'For the complex routines you can make 1 call to errorhandler after 'END SELECT. I'll leave that up to you. 'This is basically what errorhandling is about. It took me months of 'experimenting with a lot of different formats to finally find out that 'this might be the best one. 'For the sake of experimenting a somewhat more maximalized errorhandling 'which still bears the same principles I include a LFN file copier. 'It is still running beta, and does not yet copy filetimes too, but 'it seems to work just fine, including the actions taken on errors. DECLARE SUB COPYDEMO () DECLARE SUB ERRORHANDLING (ERRS%) DECLARE FUNCTION COPYLFN$ () 'This is program in stage beta 2. Attributes seems oke. 'Filetimes will be added later.. 'All kind of situations are handled oke, like the destiny 'can not be existant, if an read/write error is encountered 'then open files are closed etc.. 'If someone still finds some files open, or some other bug, 'be so kind to mail me so that I can update it. I am getting 'bored testing thats why.. DEFINT A-Z CLS CALL COPYDEMO 'Good bye, 'Rick(rick@tip.nl) END SUB COPYDEMO 'This will give a demonstration of the filecopier: 'From a dosbox you can copy from short to lfn from lfn to lfn, 'from lfn to short and from short to short 'From plain dos you can copy from short(alias) to short(alias). 'GOOD luck. RIck( currently beta2: next version will copy filetimes too!) 'INITIATING.. copyit$ = COPYLFN$ DEF SEG = VARSEG(copyit$) 'USERINPUT: PRINT "WHICH SOURCE DO YOU WANT TO COPY..? "; COLOR 0, 7: DO: LINE INPUT src$ LOOP UNTIL src$ <> "" COLOR 7, 0: PRINT "COPY SOURCE TO WHICH DESTINY......? "; COLOR 0, 7: DO: LINE INPUT dest$ LOOP UNTIL dest$ <> "" 'GO RUN IT.." PRINT "COPYING....": PRINT a! = TIMER CALL absolute(src$, dest$, ERRS, SADD(copyit$)) b! = TIMER: DEF SEG IF ERRS THEN id = (ERRS / &H100) AND &HFF: ERRS = ERRS AND &HFF IF id = 1 THEN PRINT "ERROR OPENING SOURCE, "; ELSEIF id = 2 THEN PRINT "ERROR GETTING SOURCE ATTRIBUTES, "; ELSEIF id = 4 THEN PRINT "ERROR CREATING DESTINY, "; ELSEIF id = 8 THEN PRINT "ERROR READING FROM SOURCE, "; ELSEIF id = 16 THEN PRINT "ERROR WRITING TO DESTINY, "; ELSEIF id = 32 THEN PRINT "ERROR CLOSING DESTINY, "; ELSE PRINT "ERROR CLOSING SOURCE, "; END IF CALL ERRORHANDLING(ERRS) ELSE COLOR 7, 0: PRINT "COPIED FILE: "; : COLOR 0, 7: PRINT src$; COLOR 7, 0: PRINT " TO: "; : COLOR 0, 7: PRINT dest$; : COLOR 7, 0: PRINT " IN : "; : COLOR 0, 7: PRINT b! - a!; : COLOR 7, 0: PRINT " ticks"; END IF END SUB DEFSTR A-Z FUNCTION COPYLFN$ '--------------------------------------------------- 'STACKPASSING: FILENAME1,FILENAME2,ERRS 'copy it using byte per byte copy.. 'IN : FILENAME SRC ASCI.. ' FILENAME DEST ASCI.. 'OUT : ERRS = 0 OR ERROR ' ERRS HIGHBYTE=1 OPEN SOURCE ERROR ' =2 GET ATTRIBUTES ERROR ' =4 CREATE DESTINY ERROR ' =8 READ ERROR ' =16 WRITE ERROR ' =32 CLOSE DESTINY ERROR ' =64 CLOSE SOURCE ERROR ' LOWBYTE =DOSERRORCODE.. '--------------------------------------------------- '------------********************************----------------------- ' *BUFFER FOR WIN PATH/ FILENAMES* ' ******************************** DIM srcnamebuffer AS STRING * 260 'FILE/PATH BUFFER. offset% = VARPTR(srcnamebuffer) DIM DESTnamebuffer AS STRING * 260 offset2% = VARPTR(DESTnamebuffer) '------------------------------------------------------------------- 'COPYBUFFER NEEDS TO BE STATIC TOO DIM BUFFER AS STRING * 512: OFFS% = VARPTR(BUFFER) '-------------------------------------------------------------------- asm = "" asm = asm + CHR$(&H55) 'PUSH BP asm = asm + CHR$(&H89) + CHR$(&HE5) 'MOV BP,SP '************ 'OPEN SOURCE '************ 'STORE NAME IN BUFFER AND APPEND A ZERO.. asm = asm + CHR$(&H6) 'PUSH ES asm = asm + CHR$(&HFC) 'CLD asm = asm + CHR$(&H8B) + CHR$(&H5E) + CHR$(&HA) 'MOV BX,[BP+A] asm = asm + CHR$(&H8B) + CHR$(&H77) + CHR$(&H2) 'MOV SI,[BX+2]OFFSET(FILE) asm = asm + CHR$(&H8B) + CHR$(&HF) 'MOV CX,[BX] LEN(FILE) asm = asm + CHR$(&HBF) + MKI$(offset%) 'MOV DI,OFFSET(SRCBUFFER) asm = asm + CHR$(&H89) + CHR$(&HFA) 'MOV DX,DI FOR WIN FUNCTION asm = asm + CHR$(&HE) + CHR$(&H7) 'PUSH CS:POP ES ES=CS asm = asm + CHR$(&HF3) + CHR$(&HA4) 'REP MOVSB asm = asm + CHR$(&HB0) + CHR$(&H0) 'MOV AL,0 asm = asm + CHR$(&HAA) 'STOSB APPEND 0 'FILENAME TO DS[SI] asm = asm + CHR$(&H89) + CHR$(&HD6) 'MOV SI,DX TO FILENAME 'OPEN&MADE MASK TO DL(open if exist) asm = asm + CHR$(&HBA) + MKI$(&H1) 'MOV DX,1 'READ&WRITE MASK TO BX(open for read only) asm = asm + CHR$(&H31) + CHR$(&HDB) 'XOR BX,BX 'WINDOWS OPEN EXTENDED.. asm = asm + CHR$(&HB8) + CHR$(&H6C) + CHR$(&H71)'MOV AX,716C asm = asm + CHR$(&HCD) + CHR$(&H21) 'INT 21 asm = asm + CHR$(&HBA) + MKI$(offset%) 'MOV DX,OFFSET(SRC BUFFER) asm = asm + CHR$(&H72) + CHR$(107) 'JC +107 DOS OPEN SRC ? 'GO ON :SAVE SCR HANDLE 1 asm = asm + CHR$(&H50) 'PUSH AX SAVE SRC HANDLE 'GET ATTRIBUTES TO CX 'EXECUTE WINDOZE FUNCTION 43h 13 asm = asm + CHR$(&HB3) + CHR$(&H0) 'MOV BL,0 GET ATTRIBS asm = asm + CHR$(&HB8) + CHR$(&H43) + CHR$(&H71)'MOV AX,7143 asm = asm + CHR$(&HCD) + CHR$(&H21) 'INT 21 asm = asm + CHR$(&H72) + CHR$(120) 'JC +120 GET ATTRIB ERRS asm = asm + CHR$(&H51) 'PUSH CX SAVE ATTRIBUTES '******************* 'CREATE DESTINY.. '******************* 'STORE NAME IN BUFFER AND APPEND A ZERO..20 asm = asm + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H8) 'MOV BX,[BP+8] asm = asm + CHR$(&H8B) + CHR$(&H77) + CHR$(&H2) 'MOV SI,[BX+2]OFFSET(FILE) asm = asm + CHR$(&H8B) + CHR$(&HF) 'MOV CX,[BX] LEN(FILE) asm = asm + CHR$(&HBF) + MKI$(offset2%) 'MOV DI,OFFSET(DESTBUFFER) asm = asm + CHR$(&H89) + CHR$(&HFA) 'MOV DX,DI FOR WIN FUNCTION asm = asm + CHR$(&HE) + CHR$(&H7) 'PUSH CS:POP ES ES=CS asm = asm + CHR$(&HF3) + CHR$(&HA4) 'REP MOVSB asm = asm + CHR$(&HB0) + CHR$(&H0) 'MOV AL,0 asm = asm + CHR$(&HAA) 'STOSB APPEND 0 'FILENAME TO DS[SI] 2 asm = asm + CHR$(&H89) + CHR$(&HD6) 'MOV SI,DX TO FILENAME 'OPEN&MADE MASK TO DL(make if not exist) 3 asm = asm + CHR$(&HBA) + MKI$(&H10) 'MOV DX,10 'READ&WRITE MASK TO BX(open for write only) 3 asm = asm + CHR$(&HBB) + MKI$(&H1) 'MOV BX,1 'FILETYPE TO CX 2 asm = asm + CHR$(&H59) 'POP CX ATTRIBUTES SRC 'WINDOWS OPEN EXTENDED.. 7 asm = asm + CHR$(&HB8) + CHR$(&H6C) + CHR$(&H71)'MOV AX,716C asm = asm + CHR$(&HCD) + CHR$(&H21) 'INT 21 asm = asm + CHR$(&H72) + CHR$(93) 'JC +93 DOS EXTENDED OPEN? 'GO ON: SAVE DESTINY HANDLE TO DI,SRC HANDLE TO SI 3 asm = asm + CHR$(&H5E) 'POP SI GET SRC HANDLE TO SI asm = asm + CHR$(&H89) + CHR$(&HC7) 'MOV DI,AX SAVE DEST HANDLE 'COPY.. 6 asm = asm + CHR$(&HB9) + MKI$(&H200) 'MOV CX,512 BUFFERLENGTH asm = asm + CHR$(&HBA) + MKI$(OFFS%) 'MOV DX,OFFSET(BUFFER) 'COPYLOOP.. 6 asm = asm + CHR$(&H89) + CHR$(&HF3) 'MOV BX,SI SRC HANDLE asm = asm + CHR$(&HB4) + CHR$(&H3F) 'MOV AH,3F asm = asm + CHR$(&HCD) + CHR$(&H21) 'INT 21 READ SRC 'ERROR HANDLING 12 asm = asm + CHR$(&H72) + CHR$(107) 'JC +107 READ ERROR asm = asm + CHR$(&H39) + CHR$(&HC1) 'CMP AX,CX EOF REACHED ? asm = asm + CHR$(&H89) + CHR$(&HFB) 'MOV BX,DI DEST HANDLE asm = asm + CHR$(&H75) + CHR$(&H8) 'JNE +8 EOF asm = asm + CHR$(&HB4) + CHR$(&H40) 'MOV AH,40 asm = asm + CHR$(&HCD) + CHR$(&H21) 'INT 21 WRITE DEST 'ERROR HANDLING 4 asm = asm + CHR$(&H72) + CHR$(104) 'JC +104 WRITE ERROR asm = asm + CHR$(&HEB) + CHR$(&HEA) 'JMP COPYLOOP -22 'EOF HANDLING( WRITE LAST BYTES) 8 asm = asm + CHR$(&H89) + CHR$(&HC1) 'MOV CX,AX asm = asm + CHR$(&HB4) + CHR$(&H40) 'MOV AH,40 asm = asm + CHR$(&HCD) + CHR$(&H21) 'INT 21 WRITE DEST asm = asm + CHR$(&H72) + CHR$(94) 'JC +94 WRITE ERROR 'CLOSE DEST HANDLE 6 asm = asm + CHR$(&H89) + CHR$(&HFB) 'MOV BX,DI CLOSE DESTINY HANDLE asm = asm + CHR$(&HB4) + CHR$(&H3E) 'MOV AH,3E asm = asm + CHR$(&HCD) + CHR$(&H21) 'INT 21 CLOSE DESTINY 'ERROR HANDLING 2 asm = asm + CHR$(&H72) + CHR$(95) 'JC +95 CLOSE DEST ERROR 'CLOSE SCR HANDLE 6 asm = asm + CHR$(&H89) + CHR$(&HF3) 'MOV BX,SI CLOSE SOURCE HANDLE asm = asm + CHR$(&HB4) + CHR$(&H3E) 'MOV AH,3E asm = asm + CHR$(&HCD) + CHR$(&H21) 'INT 21 CLOSE SOURCE 'ERROR HANDLING 2 asm = asm + CHR$(&H72) + CHR$(96) 'JC +96 CLOSE SRC ERROR 'RETURN(NO) ERROR AND TO QBASIC.. 5 asm = asm + CHR$(&H7) 'POP ES asm = asm + CHR$(&H5D) 'POP BP asm = asm + CHR$(&HCA) + MKI$(6) 'RETF 6 'ERROR HANDLING: DOSFUNCTIONS ? 'WIN95 FUNCTION OPEN SRC ERROR.. 5 asm = asm + CHR$(&H3D) + CHR$(&H0) + CHR$(&H71) 'CMP AX,7100 FUNCTION UNSUPPORTED ? asm = asm + CHR$(&H75) + CHR$(42) 'JNZ +42 OPEN SRC ERROR.. 'IF SO EXECUTE DOS FUNCTION &H6C(EXTENDED OPEN) 8 asm = asm + CHR$(&HB8) + MKI$(&H6C00) 'MOV AX,6C00 asm = asm + CHR$(&HCD) + CHR$(&H21) 'INT 21 asm = asm + CHR$(&H72) + CHR$(35) 'JC +35 OPEN SRC ERROR asm = asm + CHR$(&H50) 'PUSH AX SAVE SRC HANDLE 'IF SO EXECUTE DOS FUNCTION &H4300(GET ATTRIBS) 10 asm = asm + CHR$(&HB8) + MKI$(&H4300) 'MOV AX,4300 asm = asm + CHR$(&HCD) + CHR$(&H21) 'INT 21 asm = asm + CHR$(&H72) + CHR$(3) 'JC +3 GET ATTRIBS ERROR asm = asm + CHR$(&H51) 'PUSH CX SAVE ATTRIBUTES asm = asm + CHR$(&HEB) + CHR$(&H77) 'JMP -119 GO ON CREATE DEST.. 'GET ATTRIBUTES ERROR: 10 asm = asm + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H6) 'MOV BX,[BP+06] asm = asm + CHR$(&HB4) + CHR$(&H2) 'MOV AH,2 asm = asm + CHR$(&H89) + CHR$(&H7) 'MOV [BX],AX asm = asm + CHR$(&H5E) 'POP SI NEED SRC HANDLE asm = asm + CHR$(&HEB) + CHR$(&HD2) 'JMP -46 CLOSE SOURCE 'WIN95 FUNCTION ERROR ON CREATING DESTINY 5 asm = asm + CHR$(&H3D) + CHR$(&H0) + CHR$(&H71) 'CMP AX,7100 FUNCTION UNSUPPORTED ? asm = asm + CHR$(&H75) + CHR$(16) 'JNZ +16 CREATE DESTINY ERROR.. 'IF SO EXECUTE DOS FUNCTION &H6C(EXTENDED OPEN) 9 asm = asm + CHR$(&HB8) + MKI$(&H6C00) 'MOV AX,6C00 asm = asm + CHR$(&HCD) + CHR$(&H21) 'INT 21 asm = asm + CHR$(&H72) + CHR$(9) 'JC +9 CREATE DESTINY ERROR asm = asm + CHR$(&HEB) + CHR$(&H95) 'JMP -107 GO ON COPY FILE 'ERRORHANDLING 27 37 48 '************** 'OPEN SRC ERROR: 7 asm = asm + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H6) 'MOV BX,[BP+06] asm = asm + CHR$(&HB4) + CHR$(&H1) 'MOV AH,1 asm = asm + CHR$(&HEB) + CHR$(&HC5) 'JMP -59 RETURN BASIC 'CREATE DEST ERROR: 10 asm = asm + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H6) 'MOV BX,[BP+06] asm = asm + CHR$(&HB4) + CHR$(&H4) 'MOV AH,4 asm = asm + CHR$(&H89) + CHR$(&H7) 'MOV [BX],AX asm = asm + CHR$(&H5E) 'POP SI NEED SRC HANDLE asm = asm + CHR$(&HEB) + CHR$(&HB3) 'JMP -77 CLOSE SOURCE.. 'READERROR: 9 asm = asm + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H6) 'MOV BX,[BP+06] asm = asm + CHR$(&HB4) + CHR$(&H8) 'MOV AH,8 asm = asm + CHR$(&H89) + CHR$(&H7) 'MOV [BX],AX asm = asm + CHR$(&HEB) + CHR$(&HA2) 'JMP -94 CLOSE DESTINY/SOURCE.. 'WRITEERROR: 9 asm = asm + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H6) 'MOV BX,[BP+06] asm = asm + CHR$(&HB4) + CHR$(16) 'MOV AH,16 asm = asm + CHR$(&H89) + CHR$(&H7) 'MOV [BX],AX asm = asm + CHR$(&HEB) + CHR$(&H99) 'JMP -103 CLOSE DESTINY/SOURCE.. 'CLOSE DESTINY ERROR 9 asm = asm + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H6) 'MOV BX,[BP+06] asm = asm + CHR$(&HB4) + CHR$(32) 'MOV AH,32 asm = asm + CHR$(&H89) + CHR$(&H7) 'MOV [BX],AX ERROR OR 0 asm = asm + CHR$(&HEB) + CHR$(&H98) 'JMP -104 CLOSE SOURCE 'CLOSE SOURCE ERROR: 4 asm = asm + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H6) 'MOV BX,[BP+06] asm = asm + CHR$(&HB4) + CHR$(64) 'MOV AH,64 asm = asm + CHR$(&H89) + CHR$(&H7) 'MOV [BX],AX ERROR OR 0 asm = asm + CHR$(&HEB) + CHR$(&H97) 'JMP -105 RETURN TO BASIC COPYLFN = asm END FUNCTION DEFINT A-Z SUB ERRORHANDLING (ERRS) DIM ERRORS$(&H5A) ERRORS$(1) = "INVALID FUNCTION NUMBER" ERRORS$(2) = "FILE NOT FOUND" ERRORS$(3) = "PATH NOT FOUND" ERRORS$(4) = "TOO MANY OPEN FILES (NO HANDLES LEFT)" ERRORS$(5) = "ACCESS DENIED" ERRORS$(6) = "INVALID HANDLE" ERRORS$(7) = "MEMORY CONTROL BLOCKS DESTROYED" ERRORS$(8) = "INSUFFICIENT MEMORY" ERRORS$(9) = "INVALID MEMORY BLOCK ADDRESS" ERRORS$(10) = "INVALID ENVIRONMENT" ERRORS$(11) = "INVALID FORMAT" ERRORS$(12) = "INVALID ACCESS MODE (OPEN MODE IS INVALID)" ERRORS$(13) = "INVALID DATA" ERRORS$(14) = "RESERVED" ERRORS$(15) = "INVALID DRIVE SPECIFIED" ERRORS$(16) = "ATTEMPT TO REMOVE CURRENT DIRECTORY" ERRORS$(17) = "NOT SAME DEVICE" ERRORS$(18) = "NO MORE FILES" ERRORS$(19) = "ATTEMPT TO WRITE ON A WRITE-PROTECTED DISKETTE" ERRORS$(20) = "UNKNOWN UNIT" ERRORS$(21) = "DRIVE NOT READY" ERRORS$(22) = "UNKNOWN COMMAND" ERRORS$(23) = "CRC ERROR" ERRORS$(24) = "BAD REQUEST STRUCTURE LENGTH" ERRORS$(25) = "SEEK ERROR" ERRORS$(26) = "UNKNOWN MEDIA TYPE" ERRORS$(27) = "SECTOR NOT FOUND" ERRORS$(28) = "PRINTER OUT OF PAPER" ERRORS$(29) = "WRITE FAULT" ERRORS$(30) = "READ FAULT" ERRORS$(31) = "GENERAL FAILURE" ERRORS$(32) = "SHARING VIOLATION" ERRORS$(33) = "LOCK VIOLATION" ERRORS$(34) = "INVALID DISK CHANGE" ERRORS$(35) = "FCB UNAVAILABLE" ERRORS$(36) = "SHARING BUFFER OVERFLOW" ERRORS$(37) = "RESERVED" ERRORS$(38) = "UNABLE TO COMPLETE FILE OPERATION (DOS 4.X)" ERRORS$(39) = "1 RESERVED" ERRORS$(40) = "UNINDENTIFIED FLYING OBJECT!" ERRORS$(41) = ERRORS$(40): ERRORS$(42) = ERRORS$(40): ERRORS$(43) = ERRORS$(40) ERRORS$(44) = ERRORS$(40): ERRORS$(45) = ERRORS$(40): ERRORS$(46) = ERRORS$(40) ERRORS$(47) = ERRORS$(40): ERRORS$(48) = ERRORS$(40): ERRORS$(49) = ERRORS$(40) ERRORS$(50) = "NETWORK REQUEST NOT SUPPORTED" ERRORS$(51) = "REMOTE COMPUTER NOT LISTENING" ERRORS$(52) = "DUPLICATE NAME ON NETWORK" ERRORS$(53) = "NETWORK NAME NOT FOUND" ERRORS$(54) = "NETWORK BUSY" ERRORS$(55) = "NETWORK DEVICE NO LONGER EXISTS" ERRORS$(56) = "NETBIOS COMMAND LIMIT EXCEEDED" ERRORS$(57) = "NETWORK ADAPTER ERROR" ERRORS$(58) = "INCORRECT NETWORK RESPONSE" ERRORS$(59) = "UNEXPECTED NETWORK ERROR" ERRORS$(60) = "INCOMPATIBLE REMOTE ADAPTER" ERRORS$(61) = "PRINT QUEUE FULL" ERRORS$(62) = "NO SPACE FOR PRINT FILE" ERRORS$(63) = "PRINT FILE DELETED" ERRORS$(64) = "NETWORK NAME DELETED" ERRORS$(65) = "ACCESS DENIED" ERRORS$(66) = "NETWORK DEVICE TYPE INCORRECT" ERRORS$(67) = "NETWORK NAME NOT FOUND" ERRORS$(68) = "NETWORK NAME LIMIT EXCEEDED" ERRORS$(69) = "NETBIOS SESSION LIMIT EXCEEDED" ERRORS$(70) = "TEMPORARILY PAUSED" ERRORS$(71) = "NETWORK REQUEST NOT ACCEPTED" ERRORS$(72) = "PRINT OR DISK REDIRECTION IS PAUSED" ERRORS$(73) = ERRORS$(40): ERRORS$(74) = ERRORS$(40) ERRORS$(75) = ERRORS$(40): ERRORS$(76) = ERRORS$(40) ERRORS$(77) = ERRORS$(40): ERRORS$(78) = ERRORS$(40): ERRORS$(79) = ERRORS$(40) ERRORS$(80) = "FILE ALREADY EXISTS" ERRORS$(81) = "RESERVED" ERRORS$(82) = "CANNOT MAKE DIRECTORY ENTRY" ERRORS$(83) = "FAIL ON INT 24" ERRORS$(84) = "TOO MANY REDIRECTIONS" ERRORS$(85) = "DUPLICATE REDIRECTION" ERRORS$(86) = "INVALID PASSWORD" ERRORS$(87) = "INVALID PARAMETER" ERRORS$(88) = "NETWORK DEVICE FAULT" ERRORS$(89) = "FUNCTION NOT SUPPORTED BY NETWORK (DOS 4.X)" ERRORS$(90) = "REQUIRED SYSTEM COMPONENT NOT INSTALLED (DOS 4.X)" PRINT "BECAUSE "; IF ERRS > &H5A OR ERRS = 0 THEN PRINT "YOU ARE ( OR SHOULD BE) DEBUGGING YOUR ASM$ ROUTINE" ELSE PRINT ERRORS$(ERRS) END IF END SUB