/*++

Routine Description:
    
    contains functions to format a floppy disk    

Arguments:

    

Return Value:

   

--*/
#include <windows.h>    // required for all Windows applications
#include <tchar.h>      // unicode definitions

#include "otnboot.h"    // application definitions
#include "otnbtdlg.h"   // dialog box constants
#include "fmifs.h"      // file manager IFS DLL functions

//
//  local windows messages
//
#define FS_CANCELUPDATE         (WM_USER+104)
//
//  Disk format information structure
//
#define FF_ONLYONE          0x1000
#define FF_RETRY            0x4000

typedef struct _CANCEL_INFO {
   HWND hCancelDlg;
   BOOL bCancel;
   HANDLE hThread;
   BOOL fmifsSuccess;
   UINT dReason;
   UINT fuStyle;                      // Message box style
   INT  nPercentDrawn;                // percent drawn so FAR
   enum _CANCEL_TYPE {
      CANCEL_NULL=0,
      CANCEL_FORMAT,
      CANCEL_COPY,
      CANCEL_BACKUP,
      CANCEL_RESTORE,
      CANCEL_COMPRESS,
      CANCEL_UNCOMPRESS
   } eCancelType;
   BOOL bModal;
   struct _INFO {
      struct _FORMAT {
         INT iFormatDrive;
         FMIFS_MEDIA_TYPE fmMediaType;
         BOOL fQuick;
         DWORD fFlags;                 // FF_ONLYONE = 0x1000
         TCHAR szLabel[MAXLABELLEN+1];
      } Format;
      struct _COPY {
         INT iSourceDrive;
         INT iDestDrive;
         BOOL bFormatDest;
      } Copy;
   } Info;
} CANCEL_INFO, *PCANCEL_INFO;

static HANDLE   hfmifsDll   = NULL;                     // dll w/ file system utils
static TCHAR    szFmifsDll[] = {TEXT("fmifs.dll")};     // dll for FAT file system
static TCHAR SZ_PERCENTFORMAT[] = {TEXT("%3d%%")};
//
//  pointers to DLL functions;
//
static PFMIFS_FORMAT_ROUTINE       lpfnFormat = NULL;
static PFMIFS_DISKCOPY_ROUTINE     lpfnDiskCopy = NULL;
static PFMIFS_SETLABEL_ROUTINE     lpfnSetLabel = NULL;
static PFMIFS_QSUPMEDIA_ROUTINE    lpfnQuerySupportedMedia = NULL;
//
//      Format dialog box information
//
static CANCEL_INFO  CancelInfo;
static BOOL         bDataInitialized = FALSE;

ULONG   ulSpaceAvail    = 0;
ULONG   ulTotalSpace    = 0;

static
LONG
GetFloppyDiskSize (
    IN  TCHAR   cDrive
)
/*++

Routine Description:
    
    Examines the specified floppy drive to determine if it
        supports 1.2M or 1.44M formats.

Arguments:

    IN  TCHAR   cDrive
        drive letter of floppy drive to examine

Return Value:

    0   if unable to read drive or drive does not support a HD format
    3   if the drive is a 3.5" drive that supports 1.44M-byte format
    5   if the drive is a 5.25" drive that supports the 1.2M-byte format

--*/
{
#define     DG_ELEMS    16      // accomodate up to 16 different formats
    TCHAR   szDrivePath[8];     // local drive spec. string
    HANDLE  hDrive;             // handle to drive device driver
    DWORD   dwError;            // local error code
    DWORD   dwBytesReturned;    // size of buffer returned
    LONG    lSize;              // disk size returned to calling fn.
    DWORD   dwCount;            // number of DISK_GEOMETRY structures in buffer
    DWORD   dwEntry;            // structure being evaluated
    DISK_GEOMETRY   dgArray[DG_ELEMS];  // buffer to put data in

    // check input argument
    switch (cDrive){
        case TEXT('A'):
        case TEXT('a'):
        case TEXT('B'):
        case TEXT('b'):
            break;

        default:
            SetLastError (ERROR_INVALID_PARAMETER);
            return 0;
    }
    
    // make NT device path for drive
    szDrivePath[0] = cBackslash;
    szDrivePath[1] = cBackslash;
    szDrivePath[2] = cPeriod;
    szDrivePath[3] = cBackslash;
    szDrivePath[4] = cDrive;
    szDrivePath[5] = cColon;
    szDrivePath[6] = 0;
    szDrivePath[7] = 0;

    // open drive
    hDrive = CreateFile (
        szDrivePath,            // drive to open
        0,                      // just talk to the driver, not the drive
        FILE_SHARE_READ | FILE_SHARE_WRITE, // allow sharing
        NULL,                   // default security
        OPEN_EXISTING,          // open existing device
        FILE_ATTRIBUTE_NORMAL,  // this is ignored
        NULL);                  // no template

    if (hDrive == INVALID_HANDLE_VALUE) {
        // unable to open drive so return error
        dwError = GetLastError ();
        return 0;
    }

    // get device information
    if (DeviceIoControl (hDrive,
        IOCTL_DISK_GET_MEDIA_TYPES,
        NULL, 0,                                    // no input buffer
        &dgArray[0], sizeof(DISK_GEOMETRY)*DG_ELEMS,// output buffer info
        &dwBytesReturned, NULL)) {                  // return information
        // see if at least one entry was returned
        if (dwBytesReturned >= sizeof(DISK_GEOMETRY)) {
            dwCount = dwBytesReturned / sizeof(DISK_GEOMETRY);
            // go through array to see if there's a desired entry
            // i.e. a HD format in the list of supported formats
            for (lSize = 0, dwEntry = 0;
                (dwEntry < dwCount) && (lSize == 0);
                dwEntry++) {
                switch (dgArray[dwEntry].MediaType) {
                    // only return a size if a supported
                    // format is allowed by this drive
                    case F5_1Pt2_512:
                        lSize = 5;
                        break;

                    case F3_1Pt44_512:
                        lSize = 3;
                        break;

                    case F5_360_512:
                    case F5_320_512:
                    case F5_320_1024:
                    case F5_180_512:
                    case F5_160_512:
                    case F3_2Pt88_512:
                    case F3_20Pt8_512:
                    case F3_720_512:
                    default:
                        lSize = 0;
                        break;
                }
            } 
        } else {
            // no data returned so return error
            dwError = GetLastError ();
            SetLastError (ERROR_NO_DATA);
            lSize = 0;
        }
    } else {
        // unable to read device driver info
        dwError = GetLastError ();
        lSize = 0;
    }
    // close handle and return data found.
    CloseHandle (hDrive);

    return lSize;
}

static
BOOL
DriveLoaded (
    IN  TCHAR   cDrive,
    IN  BOOL    bCheckFormat
)
/*++

Routine Description:
    
    formats call to MediaPresent function for use with just a drive letter    

Arguments:

    IN  TCHAR   cDrive
        drive letter to detect.

Return Value:

    TRUE if a disk (formatted or unformatted) is detected.
    FALSE if disk is not present in drive

--*/
{
    TCHAR szPath[4];
    szPath[0] = cDrive;
    szPath[1] = cColon;
    szPath[2] = cBackslash;
    szPath[3] = 0;

    return MediaPresent (szPath, bCheckFormat);
}

static
VOID
CancelDlgQuit(
    VOID
)
/////////////////////////////////////////////////////////////////////
//
// Name:     CancelDlgQuit
//
// Synopsis: Quits the cancel modeless dialog (status for diskcopy/format)
//
// IN: VOID
//
// Return:   VOID
//
// Assumes:  Called from worker thread only; CancelInfo.hThread valid
//
// Effects:  Kills calling thread
//
//
// Notes:
//
/////////////////////////////////////////////////////////////////////
{
   //
   // Close thread if successful
   //

   if (CancelInfo.hThread) {
      CloseHandle(CancelInfo.hThread);
      CancelInfo.hThread = NULL;
   } else {
      //
      // BUGBUG
      //
   }

   //
   // At this point, when we call FS_CANCELEND,
   // the other thread thinks that this one has died since
   // CancelInfo.hThread is NULL.
   // This is exactly what we want, since we will very shortly
   // exit after the SendMessage.
   //
   EndDialog (CancelInfo.hCancelDlg, IDOK);

   ExitThread(0L);
}

static
BOOL
Callback_Function(
    IN  FMIFS_PACKET_TYPE   PacketType,
    IN  DWORD PacketLength,
    IN  PVOID PacketData
)
/*++

Routine Description:
    
    Callback function used by IFS dll (stolen from Winfile code)

Arguments:

    

Return Value:

    

--*/
{
    TCHAR   szTemp[128];
    
       // Quit if told to do so..

    if (CancelInfo.bCancel)
        return FALSE;

    switch (PacketType) {
        case FmIfsPercentCompleted:
            //
            // If we are copying and we just finished a destination format,
            // then set the window text back to the original message
            //
            if (CANCEL_COPY == CancelInfo.eCancelType &&
                CancelInfo.Info.Copy.bFormatDest) {

                CancelInfo.Info.Copy.bFormatDest = FALSE;
                lstrcpy (szTemp,
                    GetStringResource (CancelInfo.Info.Copy.bFormatDest ?
                        IDS_FORMATTINGDEST : IDS_COPYINGDISKTITLE));

                SetWindowText(CancelInfo.hCancelDlg, szTemp);
            }
            CancelInfo.nPercentDrawn = ((PFMIFS_PERCENT_COMPLETE_INFORMATION)PacketData)->PercentCompleted;
            PostMessage(CancelInfo.hCancelDlg, FS_CANCELUPDATE, ((PFMIFS_PERCENT_COMPLETE_INFORMATION)PacketData)->PercentCompleted, 0L);

            break;

        case FmIfsFormatReport:
            ulTotalSpace = ((PFMIFS_FORMAT_REPORT_INFORMATION)PacketData)->KiloBytesTotalDiskSpace * 1024L;
            ulSpaceAvail = ((PFMIFS_FORMAT_REPORT_INFORMATION)PacketData)->KiloBytesAvailable * 1024L;
            break;

        case FmIfsInsertDisk:
            switch(((PFMIFS_INSERT_DISK_INFORMATION)PacketData)->DiskType) {
                case DISK_TYPE_GENERIC:
                    CancelInfo.fuStyle = MB_OK_TASK_INFO;
                    return DisplayMessageBox(CancelInfo.hCancelDlg,
                        IDS_INSERTSRC, IDS_COPYDISK, CancelInfo.fuStyle);

                case DISK_TYPE_SOURCE:
                    CancelInfo.fuStyle = MB_OK_TASK_INFO;
                    return DisplayMessageBox(CancelInfo.hCancelDlg,
                        IDS_INSERTSRC, IDS_COPYDISK, CancelInfo.fuStyle);

                case DISK_TYPE_TARGET:
                    CancelInfo.fuStyle = MB_OK_TASK_INFO;
                    return DisplayMessageBox(CancelInfo.hCancelDlg,
                        IDS_INSERTDEST, IDS_COPYDISK, CancelInfo.fuStyle);

                case DISK_TYPE_SOURCE_AND_TARGET:
                    CancelInfo.fuStyle = MB_OK_TASK_INFO;
                    return DisplayMessageBox(CancelInfo.hCancelDlg,
                        IDS_INSERTSRCDEST, IDS_COPYDISK, CancelInfo.fuStyle);
            }
            break;

        case FmIfsIncompatibleFileSystem:
            CancelInfo.dReason = IDS_FFERR_INCFS;
            break;

        case FmIfsFormattingDestination:
            CancelInfo.Info.Copy.bFormatDest = TRUE;
            lstrcpy (szTemp, GetStringResource (
                (CancelInfo.Info.Copy.bFormatDest ?
                    IDS_FORMATTINGDEST : IDS_COPYINGDISKTITLE)));
            SetWindowText(CancelInfo.hCancelDlg, szTemp);
            CancelInfo.nPercentDrawn = ((PFMIFS_PERCENT_COMPLETE_INFORMATION)PacketData)->PercentCompleted;
            PostMessage(CancelInfo.hCancelDlg, FS_CANCELUPDATE, ((PFMIFS_PERCENT_COMPLETE_INFORMATION)PacketData)->PercentCompleted, 0L);
            break;

        case FmIfsIncompatibleMedia:
            CancelInfo.fuStyle = MB_ICONHAND | MB_OK;
            return DisplayMessageBox(CancelInfo.hCancelDlg,
                IDS_COPYSRCDESTINCOMPAT, IDS_COPYDISK, CancelInfo.fuStyle);

        case FmIfsAccessDenied:
            CancelInfo.dReason = IDS_FFERR_ACCESSDENIED;
            break;

        case FmIfsMediaWriteProtected:
            CancelInfo.dReason = IDS_FFERR_DISKWP;
            break;

        case FmIfsCantLock:
            CancelInfo.dReason = IDS_FFERR_CANTLOCK;
            break;

        case FmIfsBadLabel:
            CancelInfo.fuStyle = MB_OK_TASK_EXCL;
            return DisplayMessageBox(CancelInfo.hCancelDlg,
                IDS_FFERR_BADLABEL, IDS_COPYERROR + FUNC_LABEL, CancelInfo.fuStyle);

        case FmIfsCantQuickFormat:
            // Can't quick format, ask if user wants to regular format:
            CancelInfo.fuStyle = MB_ICONEXCLAMATION | MB_YESNO;

            if (IDYES == DisplayMessageBox(
                CancelInfo.hCancelDlg, 
                IDS_FORMATQUICKFAILURE,
                IDS_FORMATERR,
                CancelInfo.fuStyle)) {

                CancelInfo.Info.Format.fQuick = FALSE;
                CancelInfo.Info.Format.fFlags |= FF_RETRY;

            } else {

                //
                // Just fake a cancel
                //
                CancelInfo.fmifsSuccess = FALSE;
                CancelInfo.bCancel = TRUE;
            }

            break;

        case FmIfsIoError:
            switch(((PFMIFS_IO_ERROR_INFORMATION)PacketData)->DiskType) {
                case DISK_TYPE_GENERIC:
                    CancelInfo.dReason = IDS_FFERR_GENIOERR;
                    break;

                case DISK_TYPE_SOURCE:
                    CancelInfo.dReason = IDS_FFERR_SRCIOERR;
                    break;

                case DISK_TYPE_TARGET:
                    CancelInfo.dReason = IDS_FFERR_DSTIOERR;
                    break;

                case DISK_TYPE_SOURCE_AND_TARGET:
                    CancelInfo.dReason = IDS_FFERR_SRCDSTIOERR;
                    break;
            }
            break;

        case FmIfsFinished:
            CancelInfo.fmifsSuccess = ((PFMIFS_FINISHED_INFORMATION)PacketData)->Success;
            break;

        default:
            break;
    }
    return TRUE;
}

static
VOID
FormatDrive(
    IN PVOID ThreadParameter
)
/*++

Routine Description:
    
    Thread routine to format the floppy diskette as described in the
        CancelInfo data structure.

Arguments:

    Not used    

Return Value:

    None    

--*/
{
   WCHAR wszDrive[3];
   WCHAR wszFileSystem[4] = L"FAT";

   wszDrive[0] = (WCHAR)(CancelInfo.Info.Format.iFormatDrive + cA);
   wszDrive[1] = cColon;
   wszDrive[2] = 0;

#define wszLabel CancelInfo.Info.Format.szLabel

   do {
      CancelInfo.Info.Format.fFlags &= ~FF_RETRY;

      (*lpfnFormat)(wszDrive,
         CancelInfo.Info.Format.fmMediaType,
         wszFileSystem,
         wszLabel,
         (BOOLEAN)CancelInfo.Info.Format.fQuick,
         (FMIFS_CALLBACK)&Callback_Function);
   } while (CancelInfo.Info.Format.fFlags & FF_RETRY);

   CancelDlgQuit();
}

static
FMIFS_MEDIA_TYPE
GetDriveTypeFromDriveLetter (
    IN  TCHAR   cDrive
)
/*++

Routine Description:
    
    returns the drive type of the drive specified in the path argument

Arguments:

    IN  LPCTSTR szPath
        path on drive to examine

Return Value:

    MEDIA_TYPE value identifying drive type in format compatible with
        IFS DLL

--*/
{
    HANDLE  hFloppy;
    DWORD   dwRetSize;
    DISK_GEOMETRY   dgFloppy;
    TCHAR   szDevicePath[16];
    UINT    nDriveType;
    UINT    nErrorMode;

    // make device name from drive letter

    szDevicePath[0] = cBackslash;
    szDevicePath[1] = cBackslash;
    szDevicePath[2] = cPeriod;
    szDevicePath[3] = cBackslash;
    szDevicePath[4] = cDrive;
    szDevicePath[5] = cColon; // colon
    szDevicePath[6] = cBackslash;    // null terminator
    szDevicePath[7] = 0;    // null terminator

    nDriveType = GetDriveType((LPTSTR)&szDevicePath[4]);
    // see if this is a remote disk and exit if it is.
    if (nDriveType == DRIVE_REMOTE) return FmMediaUnknown;

    if ((nDriveType == DRIVE_REMOVABLE) || (nDriveType == DRIVE_CDROM)) {
        // make device path into an NT device path
        szDevicePath[6] = 0;    // null terminator

        // disable windows error message popup
        nErrorMode = SetErrorMode  (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);

        // open device to get type
        hFloppy = CreateFile (
            szDevicePath,
            GENERIC_READ,
            (FILE_SHARE_READ | FILE_SHARE_WRITE),
            NULL,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            NULL);

        if (hFloppy != INVALID_HANDLE_VALUE) {
            // get drive information
            if (!DeviceIoControl (hFloppy,
                IOCTL_DISK_GET_DRIVE_GEOMETRY,
                NULL, 0,
                &dgFloppy,
                sizeof(DISK_GEOMETRY),
                &dwRetSize,
                NULL) ){
                // unable to get data so set to unknown
                dgFloppy.MediaType = Unknown;
            } // else return data from returned structure
            CloseHandle (hFloppy);
        } else {
            // unable to open handle to device
            dgFloppy.MediaType = Unknown;
        }
        SetErrorMode (nErrorMode); // reset error mode
    }
    // translate from MEDIA_TYPE to FMIFS_MEDIA_TYPE here

    switch (dgFloppy.MediaType) {
        case (F5_1Pt2_512):     return FmMediaF5_1Pt2_512;
        case (F3_1Pt44_512):    return FmMediaF3_1Pt44_512;
        case (F3_2Pt88_512):    return FmMediaF3_2Pt88_512;
        case (F3_20Pt8_512):    return FmMediaF3_20Pt8_512;
        case (F3_720_512):      return FmMediaF3_720_512;
        case (F5_360_512):      return FmMediaF5_360_512;
        case (F5_320_512):      return FmMediaF5_320_512;
        case (F5_320_1024):     return FmMediaF5_320_1024;
        case (F5_180_512):      return FmMediaF5_180_512;
        case (F5_160_512):      return FmMediaF5_160_512;
        case (FixedMedia):      return FmMediaFixed;
        case (Unknown):         return FmMediaUnknown;
        default:                return FmMediaUnknown;
    }
}

static
BOOL
FmifsLoaded(
    IN  HWND    hWnd
)
/*++

Routine Description:
    
    loads (if not already loaded) the File Manager IFS dll and initializes
        the pointers to it's functions

Arguments:

    IN  HWND    hWnd
        window handle of parent, used for MessageBox calls

Return Value:

    TRUE if file loaded
    FALSE if not

--*/
{
   // Load the fmifs dll.

   if (hfmifsDll < (HANDLE)32) {
      hfmifsDll = LoadLibrary(szFmifsDll);
      if (hfmifsDll < (HANDLE)32) {
         /* FMIFS not available. */
         DisplayMessageBox(hWnd,
            IDS_APP_NAME,
            IDS_FMIFSLOADERR,
            MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
         hfmifsDll = NULL;
         return FALSE;
      }
      else {
         lpfnFormat = (PVOID)GetProcAddress(hfmifsDll, "Format");
         lpfnQuerySupportedMedia = (PVOID)GetProcAddress(hfmifsDll, "QuerySupportedMedia");
         lpfnSetLabel = (PVOID)GetProcAddress(hfmifsDll, "SetLabel");
         lpfnDiskCopy = (PVOID)GetProcAddress(hfmifsDll, "DiskCopy");
         if (!lpfnFormat || !lpfnQuerySupportedMedia ||
            !lpfnSetLabel || !lpfnDiskCopy) {
            DisplayMessageBox(hWnd,
                IDS_APP_NAME,
                IDS_FMIFSLOADERR,
                MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
            FreeLibrary(hfmifsDll);
            hfmifsDll = NULL;
            return FALSE;
         }
      }
   }
   return TRUE;
}

static
VOID
DestroyCancelWindow(
    VOID
)
/*++

Routine Description:
    
    Destroys the CANCEL (i.e. Format) window.    

Arguments:

    None    

Return Value:

    None

--*/
{
   if (!CancelInfo.hCancelDlg)
      return;

   if (CancelInfo.bModal) {
      EndDialog(CancelInfo.hCancelDlg,0);
   } else {
      DestroyWindow(CancelInfo.hCancelDlg);
   }
   CancelInfo.hCancelDlg = NULL;
}

static
BOOL
CancelDlgProc(HWND hDlg,
   IN   UINT    message,
   IN   WPARAM  wParam,
   IN   LPARAM  lParam
)
/*-------------------------  CancelDlgProc
 *
 *  DESCRIPTION:
 *    dialog procedure for the modeless dialog. two main purposes
 *    here:
 *
 *      1. if the user chooses CANCEL we set bCancel to TRUE
 *         which will end the PeekMessage background processing loop
 *
 *      2. handle the private FS_CANCELUPDATE message and draw
 *         a "gas gauge" indication of how FAR the background job
 *         has progressed
 *
 *  ARGUMENTS:
 *      stock dialog proc arguments
 *
 *  RETURN VALUE:
 *      stock dialog proc return value - BOOL
 *
 *  GLOBALS READ:
 *      none
 *
 *  GLOBALS WRITTEN:
 *      CancelInfo structure
 *
 *  MESSAGES:
 *      WM_COMMAND      - handle IDCANCEL by setting bCancel to TRUE
 *                        and calling DestroyWindow to end the dialog
 *
 *      WM_INITDIALOG   - set control text, get coordinates of gas gauge,
 *                        disable main window so we look modal
 *
 *      WM_PAINT        - draw the "gas gauge" control
 *
 *      FS_CANCELUPDATE - the percentage done has changed, so update
 *                        nPercentDrawn and force a repaint
 *
 *  NOTES:
 *
 *    The bCancel global variable is used to communicate
 *    with the main window. If the user chooses to cancel
 *    we set bCancel to TRUE.
 *
 *    When we get the private message FS_CANCELUPDATE
 *    we update the "gas gauge" control that indicates
 *    what percentage of the rectangles have been drawn
 *    so FAR. This shows that we can draw in the dialog
 *    as the looping operation progresses.  (FS_CANCELUPDATE is sent
 *    first to hwndFrame, which sets %completed then sends message to us.)
 *
 */
{
   static RECT rectGG;              // GasGauge rectangle
   DWORD Ignore;
   TCHAR szTemp[128];
   static BOOL bLastQuick;

   switch (message) {
        case WM_COMMAND:
            switch (LOWORD(wParam)) {
                case IDCANCEL:
                    DestroyCancelWindow();
                    CancelInfo.bCancel = TRUE;
                    return TRUE;

                default:
                    return FALSE;
            }

        case WM_INITDIALOG:
            {
                CancelInfo.hCancelDlg = hDlg;
                bLastQuick = TRUE;

                switch(CancelInfo.eCancelType) {
                    case CANCEL_FORMAT:

                        //
                        // Formatting disk requires that we release any notification
                        // requests on this drive.
                        //
//                      NotifyPause(CancelInfo.Info.Format.iFormatDrive, DRIVE_REMOVABLE);

                        break;
                    case CANCEL_COPY:

                        //
                        // Pause notifications on dest drive.
                        //
//                      NotifyPause(CancelInfo.Info.Copy.iDestDrive, DRIVE_REMOVABLE);
                        lstrcpy (szTemp, GetStringResource(
                            CancelInfo.Info.Copy.bFormatDest ?
                                IDS_FORMATTINGDEST : IDS_COPYINGDISKTITLE));                
                        SetWindowText(hDlg, szTemp);

                        break;
                    default:
                        break;
                }

                if (!CancelInfo.hThread) {
                    switch (CancelInfo.eCancelType) {
                        case CANCEL_FORMAT:
                            CancelInfo.hThread = CreateThread( NULL,      // Security
                                0L,                                        // Stack Size
                                (LPTHREAD_START_ROUTINE)FormatDrive,
                                NULL,
                                0L,
                                &Ignore );
                            break;

                        default:
                            break;
                    }
                }

                // Get the coordinates of the gas gauge static control rectangle,
                // and convert them to dialog client area coordinates
                GetClientRect(GetDlgItem(hDlg, IDD_GASGAUGE), &rectGG);
                ClientToScreen(GetDlgItem(hDlg, IDD_GASGAUGE), (LPPOINT)&rectGG.left);
                ClientToScreen(GetDlgItem(hDlg, IDD_GASGAUGE), (LPPOINT)&rectGG.right);
                ScreenToClient(hDlg, (LPPOINT)&rectGG.left);
                ScreenToClient(hDlg, (LPPOINT)&rectGG.right);

                return TRUE;
            }

        case WM_PAINT:
            {
            HDC         hDC;
            PAINTSTRUCT ps;
            TCHAR       buffer[48];
            SIZE        size;
            INT         xText, yText;
            INT         nDivideRects;
            RECT        rectDone, rectLeftToDo;

            // The gas gauge is drawn by drawing a text string stating
            // what percentage of the job is done into the middle of
            // the gas gauge rectangle, and by separating that rectangle
            // into two parts: rectDone (the left part, filled in blue)
            // and rectLeftToDo(the right part, filled in white).
            // nDivideRects is the x coordinate that divides these two rects.
            //
            // The text in the blue rectangle is drawn white, and vice versa
            // This is easy to do with ExtTextOut()!

            hDC = BeginPaint(hDlg, &ps);

            //
            // If formatting quick, set this display
            //
            if (CancelInfo.Info.Format.fQuick &&
                CANCEL_FORMAT == CancelInfo.eCancelType) {
                lstrcpy (buffer, GetStringResource (IDS_QUICKFORMATTINGTITLE));
                SendDlgItemMessage(hDlg, IDD_TEXT, WM_SETTEXT, 0, (LPARAM)cszEmptyString);

                bLastQuick = TRUE;

            } else {

                if (bLastQuick) {
                    lstrcpy (buffer, GetStringResource (IDS_PERCENTCOMPLETE));
                    SendDlgItemMessage(hDlg, IDD_TEXT, WM_SETTEXT, 0, (LPARAM)buffer);

                    bLastQuick = FALSE;
                }

                wsprintf(buffer, SZ_PERCENTFORMAT, CancelInfo.nPercentDrawn);
            }

            GetTextExtentPoint32(hDC, buffer, lstrlen(buffer), &size);
            xText    = rectGG.left
                        + ((rectGG.right - rectGG.left) - size.cx) / 2;
            yText    = rectGG.top
                        + ((rectGG.bottom - rectGG.top) - size.cy) / 2;

            nDivideRects = ((rectGG.right - rectGG.left) * CancelInfo.nPercentDrawn) / 100;

            // Paint in the "done so FAR" rectangle of the gas
            // gauge with blue background and white text
            SetRect(&rectDone, rectGG.left, rectGG.top,
                                        rectGG.left + nDivideRects, rectGG.bottom);
            SetTextColor(hDC, RGB(255, 255, 255));
            SetBkColor(hDC, RGB(0, 0, 255));

            ExtTextOut(hDC, xText, yText, ETO_CLIPPED | ETO_OPAQUE,
                                &rectDone, buffer, lstrlen(buffer), NULL);

            // Paint in the "still left to do" rectangle of the gas
            // gauge with white background and blue text
            SetRect(&rectLeftToDo, rectGG.left+nDivideRects, rectGG.top,
                                        rectGG.right, rectGG.bottom);
            SetTextColor(hDC, RGB(0, 0, 255));
            SetBkColor(hDC, RGB(255, 255, 255));

            ExtTextOut(hDC, xText, yText, ETO_CLIPPED | ETO_OPAQUE,
                            &rectLeftToDo, buffer, lstrlen(buffer), NULL);

            EndPaint(hDlg, &ps);

            return TRUE;
            }

        case FS_CANCELUPDATE:
            InvalidateRect(hDlg, &rectGG, TRUE);
            UpdateWindow(hDlg);
            return TRUE;

        default:
            return FALSE;
   }
}

static
BOOL
InitUserData (
    IN  HWND    hWnd
)
/*++

Routine Description:
    
    initializes the CancelInfo data structure used to format the disk    

Arguments:

    Window handle of calling function    

Return Value:

    TRUE If library loaded and data initialized    

--*/
{
    CancelInfo.hCancelDlg = NULL;
    CancelInfo.bCancel = FALSE;
    CancelInfo.hThread = NULL;
    CancelInfo.fmifsSuccess = FmifsLoaded(hWnd);
    CancelInfo.dReason = 0;
    CancelInfo.fuStyle = 0;
    CancelInfo.nPercentDrawn = 0;
    CancelInfo.eCancelType = CANCEL_NULL;
    CancelInfo.bModal = TRUE;

    CancelInfo.Info.Format.iFormatDrive = 0;
    CancelInfo.Info.Format.fmMediaType = Unknown;
    CancelInfo.Info.Format.fQuick = FALSE;
    CancelInfo.Info.Format.fFlags = 0;
    CancelInfo.Info.Format.szLabel[0] = 0;

    CancelInfo.Info.Copy.iSourceDrive = 0;
    CancelInfo.Info.Copy.iDestDrive = 0;
    CancelInfo.Info.Copy.bFormatDest = FALSE;

    if (CancelInfo.fmifsSuccess) {
        bDataInitialized = TRUE;
        return TRUE;
    } else {
        return FALSE;
    }
}

BOOL
FormatDiskInDrive (
    IN  HWND    hWnd,           // owner window
    IN  TCHAR   cDrive,         // drive letter to format (only A or B)
    IN  LPCTSTR szLabel,        // label text
    IN  BOOL    bConfirmFormat  // prompt with "r-u-sure?" dialog
)
/*++

Routine Description:
    
    formats the floppy disk in the specified drive and labels it if desired.
        If the floppy has a valid format, then a Quick Format is performed.
        if there is no detectible format or a bad format, then a complete
        format is done.

Arguments:
    
    IN  HWND    hWnd,           // owner window
    IN  TCHAR   cDrive,         // drive letter to format (only A or B)
    IN  LPCTSTR szLabel,        // label text
    IN  BOOL    bConfirmFormat  // prompt with "r-u-sure?" dialog before formatting

Return Value:

    TRUE if disk is formatted
    FALSE if not

--*/
{
    UINT    nDlgBox;

    // check input argument
    switch (cDrive){
        case TEXT('A'):
        case TEXT('a'):
        case TEXT('B'):
        case TEXT('b'):
            break;

        default:
            SetLastError (ERROR_INVALID_PARAMETER);
            return FALSE;
    }

    if (lstrlen(szLabel) > MAXLABELLEN) {
            SetLastError (ERROR_INVALID_PARAMETER);
            return FALSE;
    }

    // make sure the DLL and data structures are initialized
    if (!bDataInitialized) {
        if (!InitUserData (hWnd)) {
            SetLastError (ERROR_FILE_NOT_FOUND);
            return FALSE;
        }
    }

    // set the remaining fields to format the diskette
    CancelInfo.hThread = NULL;
    CancelInfo.hCancelDlg = NULL;
    CancelInfo.eCancelType = CANCEL_FORMAT;
    CancelInfo.bCancel = FALSE;
    CancelInfo.dReason = 0;
    CancelInfo.nPercentDrawn = 0;
    CancelInfo.Info.Format.iFormatDrive = (cDrive - TEXT('A'));
    CancelInfo.Info.Format.fmMediaType = GetDriveTypeFromDriveLetter (cDrive);
    if (CancelInfo.Info.Format.fmMediaType == FmMediaUnknown) {
        switch (GetFloppyDiskSize(cDrive)) {
            case 3:
                CancelInfo.Info.Format.fmMediaType = FmMediaF3_1Pt44_512;
                break;

            case 5:
                CancelInfo.Info.Format.fmMediaType = FmMediaF5_1Pt2_512;
                break;

            default:
                return FALSE;
        }
        CancelInfo.Info.Format.fQuick = FALSE;
    } else {
        CancelInfo.Info.Format.fQuick = DriveLoaded(cDrive, TRUE);
    }
    CancelInfo.Info.Format.fFlags = FF_ONLYONE;
    lstrcpy (CancelInfo.Info.Format.szLabel, szLabel);
    if (bConfirmFormat) {
        if (DisplayMessageBox(hWnd,
            IDS_DISKCOPYCONFIRM,
            IDS_DISKCOPYCONFIRMTITLE,
            MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON1) != IDYES)
            // bail out here if they don't want to format the disk
            return FALSE;
    }

    // make sure disk is in drive and prompt if not
    while (!DriveLoaded (cDrive, FALSE)) {
        if (DisplayMessageBox (hWnd,
            IDS_INSERTDEST,
            FMT_INSERT_FLOPPY,
            MB_OKCANCEL_TASK_INFO) == IDCANCEL) {
            return FALSE;
        }
    }

    // display formatting... dialog box
    nDlgBox = DialogBox(GetModuleHandle(NULL), (LPTSTR) MAKEINTRESOURCE(CANCELDLG), hWnd, (DLGPROC) CancelDlgProc);

    if (nDlgBox == IDOK) {
        if (CancelInfo.dReason != 0) {
           // display reason for not being formatted if it didn't work
            DisplayMessageBox (hWnd,
                CancelInfo.dReason,
                IDS_APP_NAME,
                MB_OK_TASK_EXCL);
            return FALSE;
        } else {
            return TRUE;    
        }
    } else {
        return FALSE;
    }
}

BOOL
LabelDiskInDrive (
    IN  HWND    hWnd,           // owner window
    IN  TCHAR   cDrive,         // drive letter to format (only A or B)
    IN  LPCTSTR szLabel         // label text
)
/*++

Routine Description:
    
    labels the floppy disk in the specified drive. 

Arguments:
    
    IN  HWND    hWnd,           // owner window
    IN  TCHAR   cDrive,         // drive letter to label (only A or B)
    IN  LPCTSTR szLabel,        // label text

Return Value:

    TRUE if disk is formatted
    FALSE if not

--*/
{
    TCHAR   szDrive[4];

    // check input argument
    switch (cDrive){
        case TEXT('A'):
        case TEXT('a'):
        case TEXT('B'):
        case TEXT('b'):
            break;

        default:
            SetLastError (ERROR_INVALID_PARAMETER);
            return FALSE;
    }

    if (lstrlen(szLabel) > MAXLABELLEN) {
            SetLastError (ERROR_INVALID_PARAMETER);
            return FALSE;
    }

    // make sure the DLL and data structures are initialized
    if (!bDataInitialized) {
        if (!InitUserData (hWnd)) {
            SetLastError (ERROR_FILE_NOT_FOUND);
            return FALSE;
        }
    }

    szDrive[0] = cDrive;
    szDrive[1] = cColon;
    szDrive[2] = 0;

    // make sure disk is in drive and prompt if not
    while (!DriveLoaded (cDrive, FALSE)) {
        if (DisplayMessageBox (hWnd,
            IDS_INSERTDEST,
            FMT_INSERT_FLOPPY,
            MB_OKCANCEL_TASK_INFO) == IDCANCEL) {
            return FALSE;
        }
    }

    return (*lpfnSetLabel)(szDrive, (PWSTR)szLabel);
}

