/*********************************************************************/
/*                                                                   */
/*    Name:    HANDLEST.C                                            */
/*                                                                   */
/*    Copyright (c) Stewart A. Berman 1992, All rights reserved      */
/*                                                                   */
/*********************************************************************/
#pragma warning (disable:4001)
#include <Windows.h>
#pragma warning (default:4001)

#include <String.h>

#include "HandleSt.h"
#include "IOStatus.h"

#ifdef DEBUG
#include "DebugOut.h"
#endif

#ifdef _cplusplus
extern "C" {
#endif /* _cplusplus */

BOOL bTimerInterval ;

int  FAR PASCAL HandleStatus ( UINT nStatus1, UINT nStatus2, UINT nParam1, UINT nParam2, LONG lParam1, LONG lParam2 )
{
/********************************************************************/
/*                                                                  */
/* This is the callback function for disk activity status           */
/*                                                                  */
/* 1. Determine the type of callback (based on nStatus1)            */
/*                                                                  */
/* nStatus                  Action                                  */
/* -------                  ------                                  */
/* STATUS1_INIT              Save hWnd and hInstance                */
/* STATUS1_START             Send USR_ACTIVE message                */
/* STATUS1_BOOT_SECTOR       Send USR_ACTIVE message                */
/* STATUS1_DIRECTORY         Send USR_ACTIVE message                */
/* STATUS1_FAT               Send USR_ACTIVE message                */
/* STATUS1_SYSTEM_FILE       Send USR_ACTIVE message                */
/* STATUS1_CYLINDER          Send USR_UPDATE message                */
/* STATUS1_HEAD              Ignore                                 */
/* STATUS1_END               Beep and/or Flash if option selected   */
/* STATUS1_ERROR             Error type dependent                   */
/*                                                                  */
/********************************************************************/

    static BOOL bFlash = FALSE ;
    static BOOL bSound = FALSE ;

    static HINSTANCE hInstance = NULL ;

    static HWND      hWnd      = NULL;

    static UINT nTimerInterval ;

    static TIMERPROC lpfnSABDUTimerFunc ;

    char czBuffer1[512] ;
    char czBuffer2[512] ;

    char czIconMessage[512] ;
    char czNormalMessage[512] ;

    STMESSAGE stMessage ;
    STMESSAGE far *lpstMessage ;

    MSG msg ;

/********************************************************************/
/*                                                                  */
/* We want to be a well behaved Windows application so we need to   */
/* let go of the CPU and let other applications get some work done. */
/*                                                                  */
/********************************************************************/

    while ( PeekMessage ( &msg, NULL, NULL, NULL, PM_REMOVE ) )
          {
          TranslateMessage ( &msg ) ;
          DispatchMessage  ( &msg ) ;
          }

/********************************************************************/
/*                                                                  */
/* The following is a multilevel switch for processing callback     */
/* requests.                                                        */
/*                                                                  */
/* The first level is seperates the major areas.  Most of them are  */
/* normal operation and are provided so the application can keep    */
/* the user informed on the progress of long running tasks.         */
/* Most of the first level messages are sent via SendMessage.       */
/* The response is passed back to the routine issuing the callback  */
/* requests.  This allows the application to stop a long running    */
/* process by returning an IDCANCEL in response to the SendMessage  */
/* request.                                                         */
/*                                                                  */
/* The second level is used to seperate the various types of error  */
/* notifications.  Some of them prompt the user for a decision as   */
/* to whether or not a retry should be attempted.  Others simply    */
/* notify the user of a problem.                                    */
/*                                                                  */
/* The general method used to kept the user informed is to update   */
/* two messages used by our WM_PAINT routine.  One is used when the */
/* application is running in Iconic state and the other is for when */
/* it is not running in Iconic state.  The messages are built here  */
/* and passed in a structure via a SendMessage call to a routine    */
/* that stores them where the WM_PAINT routine can access them.     */
/* This maintains complete independence between this routine and    */
/* the WM_PAINT routine.                                            */
/*                                                                  */
/********************************************************************/

#ifdef DEBUG
    if ( pCDebugOut!=NULL )
       {
       wsprintf (
                 (LPSTR)DebugOutczDebugBuffer(),
                 (LPSTR)"Status1: %4.4X\n"
                        "Status2: %4.4X\n"
                        "nParam1: %4.4X\n"
                        "nParam2: %4.4X\n"
                        "lParam1: %8.8lX\n"
                        "lParam2: %8.8lX",
                 nStatus1,
                 nStatus2,
                 nParam1,
                 nParam2,
                 lParam1,
                 lParam2
                ) ;
       DebugOutOutputIf ( 0x00000001, DebugOutczDebugBuffer(), "HandleStatus", MB_ICONINFORMATION|MB_OK ) ;
       }
#endif

    switch ( nStatus1 )
       {
       case STATUS1_INIT:              /* User is passing hWnd, hInstance, and timer controls */
          {
          hWnd      = (HWND)nParam1 ;
          hInstance = (HINSTANCE)nParam2 ;
          nTimerInterval = LOWORD ( lParam1 ) ;
          bFlash = HIWORD ( lParam2 ) ;
          bSound = LOWORD ( lParam2 ) ;
          return ( FALSE ) ;
          break ;
          }
       case STATUS1_START:             /* We are starting a long running process */
          {
          wsprintf ( (LPSTR)czIconMessage,   (LPCSTR)"%2.2d  %3.2d%%", 0, 0 ) ;
          stMessage.pIconMessage = czIconMessage ;
          wsprintf ( (LPSTR)czNormalMessage, (LPCSTR)"Cylinder %2.2d (%3.2d%%)", 0, 0 ) ;
          stMessage.pNormalMessage = czNormalMessage ;
          stMessage.nPercentageToColor = 0 ;
          lpstMessage = (STMESSAGE far *) &stMessage ;
          return ( LOWORD (SendMessage ( hWnd, USR_ACTIVE, 0, (LONG)lpstMessage ) ) ) ;
          break ;
          }
       case STATUS1_BOOT_SECTOR:       /* We are installing a new boot sector */
          {
          _fstrcpy ( (LPSTR)czIconMessage,   (LPCSTR)"Boot" ) ;
          stMessage.pIconMessage = czIconMessage ;
          _fstrcpy ( (LPSTR)czNormalMessage, (LPCSTR)"Installing Boot Sector" ) ;
          stMessage.pNormalMessage = czNormalMessage ;
          stMessage.nPercentageToColor = 100 ;
          lpstMessage = (STMESSAGE far *) &stMessage ;
          return ( LOWORD ( SendMessage ( hWnd, USR_ACTIVE, 0, (LONG)lpstMessage ) ) ) ;
          break ;
          }
       case STATUS1_DIRECTORY:         /* We are building a diskette directory */
          {
          _fstrcpy ( (LPSTR)czIconMessage,   (LPCSTR)"DIR" ) ;
          stMessage.pIconMessage = czIconMessage ;
          _fstrcpy ( (LPSTR)czNormalMessage, (LPCSTR)"Creating Directory" ) ;
          stMessage.pNormalMessage = czNormalMessage ;
          stMessage.nPercentageToColor = 100 ;
          lpstMessage = (STMESSAGE far *) &stMessage ;
          return ( LOWORD ( SendMessage ( hWnd, USR_ACTIVE, 0, (LONG)lpstMessage ) ) ) ;
          break ;
          }
       case STATUS1_FAT:               /* We are building a diskette File Allocation Table */
          {
          _fstrcpy ( (LPSTR)czIconMessage,   (LPCSTR)"FAT" ) ;
          stMessage.pIconMessage = czIconMessage ;
          _fstrcpy ( (LPSTR)czNormalMessage, (LPCSTR)"Creating File Allocation Table" ) ;
          stMessage.pNormalMessage = czNormalMessage ;
          stMessage.nPercentageToColor = 100 ;
          lpstMessage = (STMESSAGE far *) &stMessage ;
          return ( LOWORD ( SendMessage ( hWnd, USR_ACTIVE, 0, (LONG)lpstMessage ) ) ) ;
          break ;
          }
       case STATUS1_SYSTEM_FILE:       /* We are copying a system file */
          {
          _fstrcpy ( (LPSTR)czIconMessage, (LPSTR)(_fstrrchr ( (LPCSTR)lParam1, '\\' ) + 1 ) ) ;
          *(strrchr( czIconMessage, '.' )) = '\n' ;
          stMessage.pIconMessage = czIconMessage ;
          _fstrcpy ( (LPSTR)czNormalMessage, (LPCSTR)"Copying System File: " ) ;
          _fstrcat ( (LPSTR)czNormalMessage, (LPCSTR)lParam1 ) ;
          stMessage.pNormalMessage = czNormalMessage ;
          stMessage.nPercentageToColor = 100 ;
          lpstMessage = (STMESSAGE far *) &stMessage ;
          return ( LOWORD ( SendMessage ( hWnd, USR_ACTIVE, 0, (LONG)lpstMessage ) ) ) ;
          break ;
          }
       case STATUS1_CYLINDER:          /* We are about to start a new cylinder */
          {
          /**********************************************************/
          /*                                                        */
          /* We will check to see if the user has specified a       */
          /* minimum amount of time to wait between cylinders.  If  */
          /* they have we will start a timer and wait for it to     */
          /* complete before going on.                              */
          /*                                                        */
          /* Note that the PeekMessage loop is needed for two       */
          /* reasons.  It is the way we can release control so      */
          /* other applications can run and it is needed so our     */
          /* own WM_TIMER message can be processed.                 */
          /*                                                        */
          /**********************************************************/
          bTimerInterval = FALSE ;
          lpfnSABDUTimerFunc = MakeProcInstance ( (FARPROC)SABDUTimerFunc, hInstance ) ;
          SetTimer ( hWnd, TIMER_INTERVAL, nTimerInterval, lpfnSABDUTimerFunc ) ;
          while ( !bTimerInterval )
             {
             while ( PeekMessage ( &msg, NULL, NULL, NULL, PM_REMOVE ) )
                   {
                   TranslateMessage ( &msg ) ;
                   DispatchMessage  ( &msg ) ;
                   }
             }
          KillTimer ( hWnd, TIMER_INTERVAL ) ;
          FreeProcInstance ( lpfnSABDUTimerFunc ) ;
          wsprintf ( (LPSTR)czIconMessage,   (LPCSTR)"%2.2d  %3.2d%%",   nParam1, nParam2 ) ;
          stMessage.pIconMessage = czIconMessage ;
          wsprintf ( (LPSTR)czNormalMessage, (LPCSTR)"Cylinder %2.2d (%3.2d%%)", nParam1, nParam2 ) ;
          stMessage.pNormalMessage = czNormalMessage ;
          stMessage.nPercentageToColor = nParam2 ;
          lpstMessage = (STMESSAGE far *) &stMessage ;
          return ( LOWORD ( SendMessage ( hWnd, USR_UPDATE, 0, (LONG)lpstMessage ) ) ) ;
          break ;
          }
       case STATUS1_HEAD:              /* We are about to start a new head */
          {
          break ;
          }
       case STATUS1_END:               /* We have completed a long running task */
          {
          if ( (bFlash) && (hWnd!=GetActiveWindow()))
             {
             lpfnSABDUTimerFunc = MakeProcInstance ( (FARPROC)SABDUTimerFunc, hInstance ) ;
             SetTimer ( hWnd, TIMER_INTERVAL, 1000, lpfnSABDUTimerFunc ) ;
             while ( hWnd != GetActiveWindow() )
                {
                FlashWindow ( hWnd, TRUE ) ;
                if (bSound) MessageBeep ( 0 ) ;
                bTimerInterval = FALSE ;
                while ( !bTimerInterval )
                   {
                   while ( PeekMessage ( &msg, NULL, NULL, NULL, PM_REMOVE ) )
                         {
                         TranslateMessage ( &msg ) ;
                         DispatchMessage  ( &msg ) ;
                         }
                   }
                }
             FlashWindow ( hWnd, FALSE ) ;
             KillTimer ( hWnd, TIMER_INTERVAL ) ;
             FreeProcInstance ( lpfnSABDUTimerFunc ) ;
             }
          else
             {
             if ( bSound ) MessageBeep ( 0 ) ;
             }
          PostMessage ( hWnd, USR_INACTIVE, 0, 0L ) ;
          break ;
          }
       case STATUS1_ERROR:             /* We have an error that needs to be dealt with */
          {
          switch (nStatus2)
             {
             case STATUS2_FILE:             /* It is a file error */
                {
                /****************************************************/
                /*                                                  */
                /* All file errors are unrecoverable.  That is the  */
                /* file operation will terminate and control will   */
                /* return to the main routine.                      */
                /*                                                  */
                /* The nParam1 indicates the type of file error.    */
                /* A message is built for that particular error.    */
                /* At the end of the switch statement a MessageBox  */
                /* call is used to display the message              */
                /*                                                  */
                /****************************************************/
                switch ( nParam1 )
                   {
                   case STATUS3_OPEN_FAIL:            /* We could not open the file */
                      {
                      wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"Open failed for: %s", (LPCSTR)lParam1 ) ;
                      break ;
                      }
                   case STATUS3_OPEN_FILE_IO_ERROR:   /* We had an I/O error */
                      {
                      wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"File I/O Error: %s", (LPCSTR)lParam1 ) ;
                      break ;
                      }
                   case STATUS3_OPEN_INPUT_BAD:       /* The file is not one of ours */
                      {
                      wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"Input file ID is invalid: %s", (LPCSTR)lParam1 ) ;
                      break ;
                      }
                   case STATUS3_OPEN_FLAGS_BAD:       /* We don't support a flagged option */
                      {
                      wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"Input file has unsupport option: %4.4X", nParam2 ) ;
                      break ;
                      }
                   case STATUS3_OPEN_NOT_SUPPORTED:   /* We don't support the device type */
                      {
                      wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"Device type, %4.4X, is not supported", nParam2 ) ;
                      break ;
                      }
                   default:                           /* We don't know what went wrong */
                      {
                      czBuffer1[0] = '\0' ;
                      break ;
                      }
                   }
                GetWindowText ( hWnd, czBuffer1, 511) ;
                return (MessageBox ( hWnd, czBuffer2, czBuffer1, MB_ICONEXCLAMATION|MB_OK )) ;
                break ;
                }
             case STATUS2_READ:             /* It was a read error */
                {
                /****************************************************/
                /*                                                  */
                /* We will tell the user about the error and let    */
                /* them decided if we should retry.  The response   */
                /* from the user will be returned to the routine    */
                /* that issued the callback address.  Hopefully,    */
                /* it will know what to do with it.                 */
                /*                                                  */
                /****************************************************/
                wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"%s Error at Cylinder %d, Head %d", (LPCSTR)"Read", nParam1, nParam2 ) ;
                _fstrcat ( czBuffer2, "\nPossible causes:" ) ;
                _fstrcat ( czBuffer2, "\nDiskette is not positioned properly in drive" ) ;
                _fstrcat ( czBuffer2, "\nDiskette drive door is not closed" ) ;
                _fstrcat ( czBuffer2, "\nDiskette is not formatted" ) ;
                GetWindowText ( hWnd, czBuffer1, 255 ) ;
                return ( MessageBox ( hWnd, czBuffer2, czBuffer1, MB_ICONSTOP|MB_RETRYCANCEL ) ) ;
                break ;
                }
             case STATUS2_WRITE:            /* It was a write error */
                {
                /****************************************************/
                /*                                                  */
                /* We will tell the user about the error and let    */
                /* them decided if we should retry.  The response   */
                /* from the user will be returned to the routine    */
                /* that issued the callback address.  Hopefully,    */
                /* it will know what to do with it.                 */
                /*                                                  */
                /****************************************************/
                wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"%s Error at Cylinder %d, Head %d", (LPCSTR)"Write", nParam1, nParam2 ) ;
                _fstrcat ( czBuffer2, "\nPossible causes:" ) ;
                _fstrcat ( czBuffer2, "\nDiskette is not positioned properly in drive" ) ;
                _fstrcat ( czBuffer2, "\nDiskette drive door is not closed" ) ;
                _fstrcat ( czBuffer2, "\nDiskette has write protect tab" ) ;
                _fstrcat ( czBuffer2, "\nDiskette is not formatted" ) ;
                GetWindowText ( hWnd, czBuffer1, 255 ) ;
                return ( MessageBox ( hWnd, czBuffer2, czBuffer1, MB_ICONSTOP|MB_RETRYCANCEL ) ) ;
                break ;
                }
             case STATUS2_FORMAT:           /* It was a format error */
                {
                /****************************************************/
                /*                                                  */
                /* We will tell the user about the error and let    */
                /* them decided if we should retry.  The response   */
                /* from the user will be returned to the routine    */
                /* that issued the callback address.  Hopefully,    */
                /* it will know what to do with it.                 */
                /*                                                  */
                /****************************************************/
                wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"%s Error at Cylinder %d, Head %d", (LPCSTR)"Format", nParam1, nParam2 ) ;
                _fstrcat ( czBuffer2, "\nPossible causes:" ) ;
                _fstrcat ( czBuffer2, "\nDiskette is not positioned properly in drive" ) ;
                _fstrcat ( czBuffer2, "\nDiskette drive door is not closed" ) ;
                _fstrcat ( czBuffer2, "\nDiskette has write protect tab" ) ;
                GetWindowText ( hWnd, czBuffer1, 255 ) ;
                return ( MessageBox ( hWnd, czBuffer2, czBuffer1, MB_ICONSTOP|MB_ABORTRETRYIGNORE ) ) ;
                break ;
                }
             case STATUS2_FILE_READ:        /* It was a file read error */
             case STATUS2_FILE_WRITE:       /* It was a file write error */
                {
                /****************************************************/
                /*                                                  */
                /* We will tell the user about the error and let    */
                /* them decided if we should retry.  The response   */
                /* from the user will be returned to the routine    */
                /* that issued the callback address.  Hopefully,    */
                /* it will know what to do with it.                 */
                /*                                                  */
                /****************************************************/
                wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"File I/O Error: %s", (LPCSTR)lParam1 ) ;
                GetWindowText ( hWnd, czBuffer1, 255 ) ;
                return ( MessageBox ( hWnd, czBuffer2, czBuffer1, MB_ICONSTOP|MB_RETRYCANCEL ) ) ;
                break ;
                }
             case STATUS2_DISK_SPACE:       /* We don't have enough disk space */
                {
                wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"Drive does not have enough space available for file\n%10ld Bytes Required\n%10ld Bytes Available", lParam1, lParam2 ) ;
                GetWindowText ( hWnd, czBuffer2, 511) ;
                return (MessageBox ( hWnd, czBuffer1, czBuffer2, MB_ICONEXCLAMATION|MB_OK )) ;
                break ;
                }
             case STATUS2_HEAD:             /* We had an I/O error at the track (head) level */
                {
                wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"%s Error at Cylinder %d, Head %d", (LPSTR)"", nParam1, nParam2 ) ;
                _fstrcat ( czBuffer2, "\nPossible causes:" ) ;
                _fstrcat ( czBuffer2, "\nDiskette is not positioned properly in drive" ) ;
                _fstrcat ( czBuffer2, "\nDiskette drive door is not closed" ) ;
                GetWindowText ( hWnd, czBuffer1, 511) ;
                return (MessageBox ( hWnd, czBuffer2, czBuffer1, MB_ICONSTOP|MB_RETRYCANCEL )) ;
                break ;
                }
             case STATUS2_MEMORY:           /* We don't have enough memory */
                {
                GetWindowText ( hWnd, czBuffer1, 511) ;
                return (MessageBox ( hWnd, "Unable to Allocate Memory", czBuffer1, MB_ICONEXCLAMATION|MB_OK )) ;
                break ;
                }
             case STATUS2_SYSTEM:           /* We have a bad sector in the system are of the diskette */
             case STATUS2_FAT:              /* We have a bad sector in the File Allocation Table area of a diskette */
             case STATUS2_DIRECTORY:        /* We have a bad sector in the root directory area of a diskette */
                {
                GetWindowText ( hWnd, czBuffer1, 511) ;
                return (MessageBox ( hWnd, "Bad Sector in System Area - Disk is unusable", czBuffer1, MB_ICONEXCLAMATION|MB_OK )) ;
                break ;
                }
             case STATUS2_BOOT_SECTOR:      /* We couldn't write out a boot sector */
                {
                wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"Unable to Write the Boot Sector on the %c Drive", ' ' ) ;
                _fstrcat ( czBuffer2, "\nPossible causes:" ) ;
                _fstrcat ( czBuffer2, "\nDiskette is not positioned properly in drive" ) ;
                _fstrcat ( czBuffer2, "\nDiskette drive door is not closed" ) ;
                _fstrcat ( czBuffer2, "\nDiskette has write protect tab" ) ;
                _fstrcat ( czBuffer2, "\nDiskette is not formatted" ) ;
                GetWindowText ( hWnd, czBuffer1, 255 ) ;
                return ( MessageBox ( hWnd, czBuffer2, czBuffer1, MB_ICONSTOP|MB_RETRYCANCEL ) ) ;
                break ;
                }
             case STATUS2_SYSTEM_FILE_MISSING:   /* We couldn't find one of the system files */
                {
                GetWindowText ( hWnd, czBuffer1, 511) ;
                return (MessageBox ( hWnd, "Unable to Find System Files", czBuffer1, MB_ICONEXCLAMATION|MB_OK )) ;
                break ;
                }
             case STATUS2_SYSTEM_FILE_OPEN: /* We couldn't open one of the system files */
                {
                wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"Unable to Open System File: %s", (LPCSTR)lParam1 ) ;
                GetWindowText ( hWnd, czBuffer1, 511) ;
                return (MessageBox ( hWnd, czBuffer2, czBuffer1, MB_ICONEXCLAMATION|MB_OK )) ;
                break ;
                }
             case STATUS2_COMPARE:          /* We were doing a compare and something didn't */
                {
                _fstrcpy ( czBuffer1, "Difference found at Cylinder %d, head %d" ) ;
                _fstrcat ( czBuffer1, "\nContinue with %s?" ) ;
                wsprintf ( (LPSTR)czBuffer2, (LPCSTR)czBuffer1, nParam1, nParam2, (LPCSTR)"Compare" ) ;
                GetWindowText ( hWnd, czBuffer1, 511) ;
                return ( MessageBox ( hWnd, czBuffer2, czBuffer1, MB_ICONSTOP|MB_YESNO ) ) ;
                break ;
                }
             case STATUS2_DPT:              /* It was a DPT error */
                {
                /****************************************************/
                /*                                                  */
                /* We will tell the user about the error and let    */
                /* them decided if we should retry.  The response   */
                /* from the user will be returned to the routine    */
                /* that issued the callback address.  Hopefully,    */
                /* it will know what to do with it.                 */
                /*                                                  */
                /****************************************************/
                wsprintf ( (LPSTR)czBuffer2, (LPCSTR)"Unable to Read Device Parameter Table of Diskette in Drive %c:", nParam1 ) ;
                _fstrcat ( czBuffer2, "\nPossible causes:" ) ;
                _fstrcat ( czBuffer2, "\nDiskette is not positioned properly in drive" ) ;
                _fstrcat ( czBuffer2, "\nDiskette drive door is not closed" ) ;
                _fstrcat ( czBuffer2, "\nDiskette is not formatted" ) ;
                GetWindowText ( hWnd, czBuffer1, 255 ) ;
                return ( MessageBox ( hWnd, czBuffer2, czBuffer1, MB_ICONEXCLAMATION|MB_OK ) ) ;
                break ;
                }
             case STATUS2_SECTORS:          /* Target diskette does not have the same sectors/track as the source image */
                {
                /****************************************************/
                /*                                                  */
                /* We will tell the user about the error and let    */
                /* them decided if we should continue. The response */
                /* from the user will be returned to the routine    */
                /* that issued the callback address.  Hopefully,    */
                /* it will know what to do with it.                 */
                /*                                                  */
                /****************************************************/
                _fstrcpy ( czBuffer2, "The source image has a different structure than the target diskette:\n" ) ;
                wsprintf ( (LPSTR)czBuffer1, (LPCSTR)"%3.3u Sectors per track and %3.3u Cylinders in target diskette\n%3.3u Sectors per track and %3.3u Cylinders in source image",
                                             nParam1, LOWORD ( lParam1 ), nParam2, LOWORD ( lParam2 ) ) ;
                _fstrcat ( czBuffer2, czBuffer1 ) ;
                _fstrcat ( czBuffer2, "\nPress OK to continue or Cancel to stop" ) ;
                GetWindowText ( hWnd, czBuffer1, 255 ) ;
                return ( MessageBox ( hWnd, czBuffer2, czBuffer1, MB_ICONEXCLAMATION|MB_OKCANCEL ) ) ;
                break ;
                }
             default:                       /* We are confused */
                {
                break ;
                }
             }
          break ;
          }
       default:                        /* We are confused */
          {
          break ;
          }
       }

    return ( TRUE ) ;                  /* We are confused but the truth will stop most things from continuing to go wrong. */
}

int  FAR PASCAL SABDUTimerFunc ( HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime )
{
    /* Kill unreferenced formal parameter warnings */
    if (hWnd) ;
    if (nMsg) ;
    if (nIDEvent) ;
    if (dwTime) ;

    bTimerInterval = TRUE ;
    return ( FALSE ) ;
}

#ifdef _cplusplus
           }
#endif /* _cplusplus */

