Using _harderr to Capture Critical Error Interrupt 24hLast reviewed: July 17, 1997Article ID: Q32309 |
5.10 6.00 6.00a 6.00ax 7.00 | 5.10 6.00 6.00a | 1.00 1.50
MS-DOS | OS/2 | WINDOWSkbprg The information in this article applies to:
SUMMARYThe text below demonstrates using the critical-error-handler function _harderr() that was introduced with the Microsoft C version 5.0 run- time library. This function change the MS-DOS critical-error-handler interrupt, Interrupt 24h, to point to a user-defined error-handler function. This function accepts three parameters that contain information about the hardware error that triggered the call to the error-handler function. The sample code includes a number of functions that shift and mask these parameters and returns a value that corresponds to one of the manifest constant values defined in the library header file.
MORE INFORMATIONThe end of the HARDERR.C file provides information about declaring the user-defined error-handler function. The HARDTEST.C file demonstrates calling the user-defined error-handler function.
HARDERR.H
// This header file defines the manifest constants and function // prototypes for HARDERR.C. // Boolean constants #define TRUE -1 #define FALSE 0typedef signed boolean;
// Manifest constants for get_codeloc() #define DOS 0x0 #define FAT 0x1 #define DIRECTORY 0x2 #define DATA 0x3 // Manifest constants for get_errcode() #define WRITE_PROTECT_ERR 0x0 #define UNKNOWN_UNIT 0x1 #define DRIVE_NOT_READY 0x2 #define UNKNOWN_CMD 0x3 #define CRC_ERR 0x4 #define BAD_DRV_REQUEST 0x5 #define SEEK_ERR 0x6 #define UNKNOWN_MEDIA 0x7 #define SECTOR_NOT_FOUND 0x8 #define OUT_OF_PAPER 0x9 #define WRITE_FAULT 0xA #define READ_FAULT 0xB #define GENERAL_FAILURE 0xC // Manifest constants for get_curr_dev() #define CURRENT_INPUT_DEVICE 0x1 #define CURRENT_OUTPUT_DEVICE 0x2 #define CURRENT_NULL_DEVICE 0x4 #define CURRENT_CLOCK_DEVICE 0x8 #define BAD_MEM_IMAGE 0xF // Type definitions #define HEADER struct _device_headerextern HEADER { long far *devptr; unsigned far *attrib; unsigned far *stratptr; unsigned far *intrptr; char far *devname; }; // Function prototypesunsigned getdrv(void); unsigned get_errcode(void); unsigned get_deverr(void); unsigned get_codeloc(void); unsigned far* get_devhdr(HEADER *header); char get_curr_dev(void);void* get_devname(void); boolean is_harderr(void); void hardreset(void);boolean is_diskerr(void); boolean is_char_dev(void); boolean is_read_err(void); boolean is_write_err(void); void handler(unsigned deverr, unsigned errcode, unsigned far *devhdr); HARDERR.C
// This file implements a number of functions to work with the // _harderr() function in the Microsoft C run-time library. When a // hardware error occurs, the _harderr() function calls an error- // handler function defined in this file. The error handler sets flags // to indicate the cause of the hardware error in a global structure // _hflags. // // Bits in each flag byte indicate the causes of the error. The // functions shift and mask the bits to obtain the causes of the // error. // // Please read the comments in the code below carefully; they contain // several warnings. // // Compile options needed: -AL -c -Od -W3 -Zi // Link options needed: None // Preprocessor information #include <dos.h> #include <malloc.h> #define TRUE -1 #define FALSE 0 // Type definitiontypedef signed boolean;
// Do not modify the members of the HEADER structure! For more // information, please refer to an IBM or Microsoft programmer's // reference manual. #define HEADER struct _device_headertypedef HEADER { long far *devptr; unsigned far *attrib; unsigned far *stratptr; unsigned far *intrptr; char far *devname; }; // Global datastatic struct { unsigned deverr; unsigned errcode; unsigned far *devhdr; // READ ONLY pointer to a HEADER structure} near _hflags; static boolean near _err = FALSE; // Error flag. FALSE = no hardware // error // Function definitions // Use these functions to retrieve information after a hardware error // occurs. When no hardware error has occurred, these functions // return random values. // getdrv() returns drive letter if error occurred on a drive.unsigned getdrv(void) { return (_hflags.deverr & 0x00ff) + 0x41;}
// get_errcode() returns the hardware error type. The function // returns one of the manifest constants defined in HARDERR.H.unsigned get_errcode(void) { return _hflags.errcode;}
// get_deverr returns information about device errors; for example, // a disk errorunsigned get_deverr(void) { return _hflags.deverr;}
// get_codeloc() returns the code location where the hardware error // occurred. The function returns one of the code locations defined in // HARDERR.H.unsigned get_codeloc(void) { return (_hflags.deverr & 0x0600) >> 9;}
// get_devhdr() accepts the address of a HEADER structure and returns // a pointer to the device header. If the HEADER structure the pointer // parameter specifies defines the WORD fields of the device header, // these fields are defined in the HEADER structure specified by the // return value. Otherwise, these fields are not defined.unsigned far* get_devhdr(HEADER *header) { if (!_err) return 0; header = (HEADER *)_hflags.devhdr; return _hflags.devhdr;}
// get_curr_dev() returns the low nibble of the attribute word at // offset 04 of the device header. The function returns one of the // manifest constants defined in HARDERR.H. This information indicates // serious hardware failures. char get_curr_dev(void){ return (char)(_hflags.devhdr[2] & 0x000f);}
// get_devname() returns the name of the device on which the error // occurred. For example, if a printer is out of paper, this function // returns the value "PRN".void* get_devname(void) { char *ptr, i = 0; ptr = (char *)malloc(8); while (i < 8) { ptr[i] = ((char *) &(_hflags.devhdr[5]))[i]; i++; } ptr[8] = '\0'; return &ptr[0];}
// The following functions determine if a hardware error has occurred // and, if so, where it occurred. You must call these functions in the // proper order. Failing to call them in the correct order can cause // unpredictable results. // is_harderr() is the most important function of the library. It // determines that a hardware error has occurred. If this function // does not return TRUE, the values returned by all the other // functions defined in this library are undefined.boolean is_harderr(void) { return _err;}
// After calling is_harderr(), you must call hardreset(). void hardreset(void){ _err = FALSE;}
// is_diskerr() returns TRUE if a device error occurred on a disk // drive; for example, if the drive door is open. This function // returns undefined results for drives that do not exist and for // virtual drives, such as RAM drives.boolean is_diskerr(void) { return (_hflags.deverr & 0x8000) == 0 ? TRUE : FALSE;}
// If a hardware error occurred, and it is not a disk error, call // is_char_dev() to determine if the error involved a character device // (PRN, KBD, TRM, and so on) of if it is a block error. If this // function returns FALSE, the error may be a bad memory image of the // File Allocation Table (FAT).boolean is_char_dev(void) { return (_hflags.devhdr[2] & 0x8000) == 0 ? FALSE : TRUE;}
// is_read_err() returns TRUE when the error was a read error.boolean is_read_err(void) { return (_hflags.deverr & 0x0100) != 0 ? FALSE : TRUE;}
// is_write_err() returns TRUE when the error was a write error.boolean is_write_err(void) { return (is_read_err() == TRUE ? FALSE : TRUE);}
// handler() is the main function in this file. You cannot call any of // the functions defined above until after you call the _harderr() // function with the address of this handler. void handler(unsigned deverr, unsigned errcode, unsigned far *devhdr){ _hflags.deverr = deverr; _hflags.errcode = errcode; _hflags.devhdr = devhdr; _err = TRUE; _hardretn(1);}
HARDTEST.C
// This code example demonstrates using HARDERR.LIB. // // This program determines if the floppy drive door is open when the // program attempts to write to disk or it determines if the printer // is on or is out of paper. The program checks only the disk or the // printer each time it runs. // // To use this program, perform one of the following: // - Open the door to your floppy disk drive and run the program. // -or- // - Turn off your printer and run the program. // -or- // - Remove the paper from your printer and run the program. // // Compiler options needed: -AL -Od -W3 -Zi #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys\types.h> #include <sys\stat.h> #include <io.h> #include <dos.h> #include <graph.h> #include <conio.h> #include "harderr.h" #define _PATHLENGTH_ 64 #define _BUFFLENGTH_ 20 #define INT24 0x24 void (far *fptr)(); // Pointer to error-handler routine // defined in HARDERR.C. void (interrupt far *OldHandler)(); // Pointer to the original // error-handler routine. void main(void); void print_errmsg(unsigned errcode); void print_codeloc(unsigned codeloc); void p_deverr(char error); char path[_PATHLENGTH_], buffer[_BUFFLENGTH_] = "Hello, World\n"; void main(void){ int fh, ch; unsigned far *headptr; HEADER header; OldHandler = _dos_getvect(INT24); // Save original handler. fptr = handler; _harderr(fptr); // Set harderr to handler() printf("Do you wish to reset the harderr handler? [y/n] "); ch = getche(); if (toupper(ch) == 'Y') // Reset to original handler. _dos_setvect(INT24, OldHandler); _clearscreen(_GCLEARSCREEN); printf("\nPlease enter path: "); fscanf(stdin, "%s", path); fh = open(path, O_CREAT | O_TEXT | O_RDWR, S_IWRITE); printf("\nOpening %s....\n", path); if (!is_harderr()) // Was open successful? { puts("No hardware error detected."); fh = fileno(stdprn); printf("\nPrinting %s....\n", path); write(fh, buffer, _BUFFLENGTH_); // Write to the printer } if (is_harderr()) // Print hardware error diagnostics { puts("Hardware error!"); if (is_diskerr()) { printf("Drive = %c:\n", getdrv()); printf("Error code = "); print_errmsg(get_errcode()); printf("Code location = "); print_codeloc(get_codeloc()); } else { headptr = get_devhdr(&header); // Implemented for illustration and for viewing in CodeView. if (is_char_dev()) puts("Character device error!"); else puts("Block device error!"); printf("Error code = "); print_errmsg(get_errcode()); printf("Code location = "); print_codeloc(get_codeloc()); printf("Device name = %s\n", get_devname()); printf("Device: "); p_deverr(get_curr_dev()); } if (is_write_err()) puts("Write error!"); else puts("Read error!"); hardreset(); } else puts("No hardware error detected."); close(fh); exit(0);}
void print_errmsg(unsigned errcode){ switch (errcode) { case WRITE_PROTECT_ERR: puts("WRITE PROTECT ERROR!"); break; case UNKNOWN_UNIT: puts("UNKNOWN UNIT!"); break; case DRIVE_NOT_READY: puts("DRIVE NOT READY!"); break; case UNKNOWN_CMD: puts("UNKNOWN COMMAND!"); break; case CRC_ERR: puts("CYCLIC REDUNDANCY CHECK!"); break; case BAD_DRV_REQUEST: puts("BAD DRIVE REQUEST!"); break; case SEEK_ERR: puts("SEEK ERROR!"); break; case UNKNOWN_MEDIA: puts("UNKNOWN MEDIA!"); break; case SECTOR_NOT_FOUND: puts("SECTOR NOT FOUND!"); break; case OUT_OF_PAPER: puts("OUT OF PAPER!"); break; case WRITE_FAULT: puts("WRITE FAULT!"); break; case READ_FAULT: puts("READ FAULT!"); break; case GENERAL_FAILURE: puts("GENERAL FAILURE!"); break; default: puts("NO ERROR!"); break; }}
void print_codeloc(unsigned codeloc){ switch (codeloc) { case DOS: puts("MS-DOS"); break; case FAT: puts("FAT"); break; case DIRECTORY: puts("DIRECTORY"); break; case DATA: puts("DATA"); break; default: puts("ERROR PRINTING CODE LOCATION."); break; }}
// Call p_deverr only if an error occurred on a device other than a // disk drive and if the error occurred on a default device. This // program uses only the default selection of the switch statement. void p_deverr(char error){ switch ( error ) { case CURRENT_INPUT_DEVICE: puts("Current input device."); break; case CURRENT_OUTPUT_DEVICE: puts("Current output device."); break; case CURRENT_NULL_DEVICE: puts("Current null device."); break; case CURRENT_CLOCK_DEVICE: puts("Current clock device."); break; default: puts("No error on default device."); break; }}
|
Additional reference words: kbinf 1.00 1.50 5.10 6.00 6.00a 6.00ax 7.00
© 1998 Microsoft Corporation. All rights reserved. Terms of Use. |