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. |