Microsoft KB Archive/32309

= Using _harderr to Capture Critical Error Interrupt 24h =

Article ID: 32309

Article Last Modified on 12/11/2003

-

APPLIES TO

 The C Run-Time (CRT), when used with:  Microsoft C Professional Development System 5.1

 Microsoft C Professional Development System 6.0

 Microsoft C Professional Development System 6.0a

 Microsoft C Professional Development System 6.0a</li></ul>

 Microsoft C Professional Development System 5.1</li></ul>

 Microsoft C Professional Development System 6.0</li></ul>

 Microsoft C Professional Development System 6.0a</li></ul>

 Microsoft C/C++ Professional Development System 7.0</li></ul>

 Microsoft Visual C++ 1.0 Professional Edition</li></ul>

 Microsoft Visual C++ 1.5 Professional Edition</li></ul> </li></ul>

-

<div class="notice_section">

This article was previously published under Q32309

<div class="notice_section">

<div class="summary_section">

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

<div class="moreinformation_section">

MORE INFORMATION
The 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

typedef signed boolean;
 * 1) define TRUE -1
 * 2) define FALSE 0

// Manifest constants for get_codeloc


 * 1) define DOS      0x0
 * 2) define FAT      0x1
 * 3) define DIRECTORY 0x2
 * 4) define DATA     0x3

// Manifest constants for get_errcode


 * 1) define WRITE_PROTECT_ERR 0x0
 * 2) define UNKNOWN_UNIT      0x1
 * 3) define DRIVE_NOT_READY   0x2
 * 4) define UNKNOWN_CMD       0x3
 * 5) define CRC_ERR           0x4
 * 6) define BAD_DRV_REQUEST   0x5
 * 7) define SEEK_ERR          0x6
 * 8) define UNKNOWN_MEDIA     0x7
 * 9) define SECTOR_NOT_FOUND  0x8
 * 10) define OUT_OF_PAPER      0x9
 * 11) define WRITE_FAULT       0xA
 * 12) define READ_FAULT        0xB
 * 13) define GENERAL_FAILURE   0xC

// Manifest constants for get_curr_dev


 * 1) define CURRENT_INPUT_DEVICE   0x1
 * 2) define CURRENT_OUTPUT_DEVICE  0x2
 * 3) define CURRENT_NULL_DEVICE    0x4
 * 4) define CURRENT_CLOCK_DEVICE   0x8
 * 5) define BAD_MEM_IMAGE          0xF

// Type definitions

extern HEADER {  long     far *devptr; unsigned far *attrib; unsigned far *stratptr; unsigned far *intrptr; char    far *devname; };
 * 1) define HEADER struct _device_header

// Function prototypes

unsigned 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
 * 1) include <dos.h>
 * 2) include <malloc.h>
 * 3) define TRUE -1
 * 4) define FALSE 0

// Type definition typedef 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. typedef HEADER {  long     far *devptr; unsigned far *attrib; unsigned far *stratptr; unsigned far *intrptr; char    far *devname; };
 * 1) define HEADER struct _device_header

// Global data static 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 error unsigned 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 &quot;PRN&quot;. 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


 * 1) include <stdio.h>
 * 2) include <stdlib.h>
 * 3) include <fcntl.h>
 * 4) include <sys\types.h>
 * 5) include <sys\stat.h>
 * 6) include <io.h>
 * 7) include <dos.h>
 * 8) include <graph.h>
 * 9) include <conio.h>
 * 10) include &quot;harderr.h&quot;


 * 1) define _PATHLENGTH_ 64
 * 2) define _BUFFLENGTH_ 20
 * 3) 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_] = &quot;Hello, World\n&quot;;

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(&quot;Do you wish to reset the harderr handler? [y/n] &quot;); ch = getche;

if (toupper(ch) == 'Y')  // Reset to original handler. _dos_setvect(INT24, OldHandler);

_clearscreen(_GCLEARSCREEN); printf(&quot;\nPlease enter path: &quot;); fscanf(stdin, &quot;%s&quot;, path);

fh = open(path, O_CREAT | O_TEXT | O_RDWR, S_IWRITE); printf(&quot;\nOpening %s....\n&quot;, path);

if (!is_harderr)   // Was open successful? {     puts(&quot;No hardware error detected.&quot;);

fh = fileno(stdprn); printf(&quot;\nPrinting %s....\n&quot;, path); write(fh, buffer, _BUFFLENGTH_);   // Write to the printer }

if (is_harderr)  // Print hardware error diagnostics {     puts(&quot;Hardware error!&quot;); if (is_diskerr) {        printf(&quot;Drive         = %c:\n&quot;, getdrv); printf(&quot;Error code   = &quot;); print_errmsg(get_errcode); printf(&quot;Code location = &quot;); print_codeloc(get_codeloc); }     else {        headptr = get_devhdr(&header); // Implemented for illustration and for viewing in CodeView.

if (is_char_dev) puts(&quot;Character device error!&quot;); else puts(&quot;Block device error!&quot;); printf(&quot;Error code = &quot;); print_errmsg(get_errcode); printf(&quot;Code location = &quot;); print_codeloc(get_codeloc); printf(&quot;Device name = %s\n&quot;, get_devname); printf(&quot;Device: &quot;); p_deverr(get_curr_dev); }     if (is_write_err) puts(&quot;Write error!&quot;); else puts(&quot;Read error!&quot;); hardreset; }  else puts(&quot;No hardware error detected.&quot;); close(fh); exit(0); }

void print_errmsg(unsigned errcode) {  switch (errcode) {  case WRITE_PROTECT_ERR: puts(&quot;WRITE PROTECT ERROR!&quot;); break; case UNKNOWN_UNIT: puts(&quot;UNKNOWN UNIT!&quot;); break; case DRIVE_NOT_READY: puts(&quot;DRIVE NOT READY!&quot;); break; case UNKNOWN_CMD: puts(&quot;UNKNOWN COMMAND!&quot;); break; case CRC_ERR: puts(&quot;CYCLIC REDUNDANCY CHECK!&quot;); break; case BAD_DRV_REQUEST: puts(&quot;BAD DRIVE REQUEST!&quot;); break; case SEEK_ERR: puts(&quot;SEEK ERROR!&quot;); break; case UNKNOWN_MEDIA: puts(&quot;UNKNOWN MEDIA!&quot;); break; case SECTOR_NOT_FOUND: puts(&quot;SECTOR NOT FOUND!&quot;); break; case OUT_OF_PAPER: puts(&quot;OUT OF PAPER!&quot;); break; case WRITE_FAULT: puts(&quot;WRITE FAULT!&quot;); break; case READ_FAULT: puts(&quot;READ FAULT!&quot;); break; case GENERAL_FAILURE: puts(&quot;GENERAL FAILURE!&quot;); break; default: puts(&quot;NO ERROR!&quot;); break; } }

void print_codeloc(unsigned codeloc) {  switch (codeloc) {  case DOS: puts(&quot;MS-DOS&quot;); break; case FAT: puts(&quot;FAT&quot;); break; case DIRECTORY: puts(&quot;DIRECTORY&quot;); break; case DATA: puts(&quot;DATA&quot;); break; default: puts(&quot;ERROR PRINTING CODE LOCATION.&quot;); 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(&quot;Current input device.&quot;); break; case CURRENT_OUTPUT_DEVICE: puts(&quot;Current output device.&quot;); break; case CURRENT_NULL_DEVICE: puts(&quot;Current null device.&quot;); break; case CURRENT_CLOCK_DEVICE: puts(&quot;Current clock device.&quot;); break; default: puts(&quot;No error on default device.&quot;); break; } }

Additional query words: kbinf 1.00 1.50 5.10 6.00 6.00a 6.00ax 7.00

Keywords: kb16bitonly KB32309

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.