/****************************************************************************/ /* */ /* WFDCOPY.C - */ /* */ /* File Manager Diskette Copying Routines */ /* */ /****************************************************************************/ #include "winfile.h" LONG APIENTRY LongPtrAdd(LPSTR, DWORD); PBPB GetBootBPB(INT nSrceDrive); PBPB GetBPB(INT nDrive, PDevPB pDevicePB); BOOL CheckBPBCompatibility(PBPB pSrceBPB, int nSrcDriveType, PBPB pDestBPB, int nDestDriveType); BOOL ModifyDeviceParams( INT nDrive, PDevPB pdpbParams, HANDLE *phSaveParams, PBPB pDriveBPB, PBPB pMediaBPB); BOOL FormatAllTracks( PDISKINFO pDisketteInfo, WORD wStartCylinder, WORD wStartHead, LPSTR lpDiskBuffer); BOOL AllocDiskCopyBuffers(PDISKINFO pDisketteInfo); VOID FreeBuffers(VOID); VOID GetDisketteInfo(PDISKINFO pDisketteInfo, PBPB pBPB); VOID DCopyMessageBox(HWND hwnd, WORD idString, WORD wFlags); VOID PromptDisketteChange(HWND hwnd, BOOL bWrite); INT ReadWriteMaxPossible(BOOL bWrite, WORD wStartCylinder, PDISKINFO pDisketteInfo); INT ReadWrite(BOOL bWrite, WORD wStartCylinder, PDISKINFO pDisketteInfo); BOOL RestoreDPB(INT nDisk, HANDLE hSavedParams); INT ReadWriteCylinder(BOOL bWrite, WORD wCylinder, PDISKINFO pDisketteInfo); /* The following structure is the Parameter block for the read-write * operations using the IOCTL calls in DOS */ struct RW_PARMBLOCK { BYTE bSplFn; WORD wHead; WORD wCylinder; WORD wStSector; WORD wCount; LPSTR lpBuffer; }; /* Global Variables */ BOOL bFormatDone; BOOL bSingleDrive = TRUE; WORD wCompletedCylinders = 0; DWORD dwDisketteBufferSize; LPSTR lpDosMemory; LPSTR lpFormatBuffer; LPSTR lpReadWritePtr; LPSTR hpDisketteBuffer; HANDLE hFormatBuffer; HANDLE hDosMemory; HANDLE hDisketteBuffer; PDevPB pTrackLayout; /* DevPB with the track layout */ BOOTSEC BootSec; /* External Variables */ extern BPB bpbList[]; /*--------------------------------------------------------------------------*/ /* */ /* GetBootBPB() - */ /* */ /*--------------------------------------------------------------------------*/ /* This reads the boot sector of a floppy and returns a ptr to * the BIOS PARAMETER BLOCK in the Boot sector. */ PBPB GetBootBPB( INT nSrceDrive ) { INT rc; /* Make sure that the source diskette's boot sector is valid. */ rc = GenericReadWriteSector((LPSTR)&BootSec, INT13_READ, (WORD)nSrceDrive, 0, 0, 1); if ((rc < 0) || ((BootSec.jump[0] != 0xE9) && (BootSec.jump[0] != 0xEB))) return (PBPB)NULL; return (PBPB)&(BootSec.BPB); } /*--------------------------------------------------------------------------*/ /* */ /* GetBPB() - */ /* */ /*--------------------------------------------------------------------------*/ /* Gets get the BPB of the Physical Drive. * * This uses the IOCTL calls if DOS ver >= 3.2; Otherwise it uses the * BIOS calls to find out the drive type and picks us the BPB from a table. * It also returns the DeviceParameterBlock thro params if DOS >= 3.2. * Sets devType field of DeviceParameterBlock in any case (11.12.91) v-dougk */ PBPB GetBPB( INT nDrive, PDevPB pDevicePB ) { INT iDisketteType; PBPB pBPB = NULL; /* Check the DOS version */ if (wDOSversion >= DOS_320) { /* All fields in pDevicePB must be initialized to zero. */ memset(pDevicePB, 0, sizeof(DevPB)); /* Spl Function field must be set to get parameters */ pDevicePB->SplFunctions = 0; pBPB = &(pDevicePB->BPB); } else { /* Find out the Drive type using the BIOS. */ if ((iDisketteType = GetDriveCapacity((WORD)nDrive)) == 0) goto GBPB_Error; /* Lookup this drive's default BPB. */ pBPB = &bpbList[iDisketteType+2]; switch (iDisketteType) { case 1: pDevicePB->devType = 0; // 360K break; case 2: pDevicePB->devType = 1; // 1.2M break; } } GBPB_Error: return (pBPB); } /*--------------------------------------------------------------------------*/ /* */ /* CheckBPBCompatibility() - */ /* */ /*--------------------------------------------------------------------------*/ /* Checks whether the two BPB are compatible for the purpose of performing * the diskcopy operation. */ BOOL CheckBPBCompatibility( PBPB pSrceBPB, int nSrcDriveType, PBPB pDestBPB, int nDestDriveType ) { /* Let us compare the media byte */ if (pSrceBPB->bMedia == 0xF9) { /* If the source and dest have the same number of sectors, * or if srce is 720KB and Dest is 1.44MB floppy drive, * thnigs are kosher. */ if ((pSrceBPB->cSec == pDestBPB->cSec) || ((pSrceBPB->secPerTrack == 9) && (pDestBPB -> bMedia == 0xF0))) return (TRUE); } else { /* If they have the same media byte */ if ((pSrceBPB->bMedia == pDestBPB->bMedia) && (pSrceBPB->cbSec == pDestBPB->cbSec) && // bytes per sector are the same (pSrceBPB->cSec == pDestBPB->cSec)) // total sectors on drive are the same return (TRUE); /* They are compatible */ else if /* srce is 160KB and dest is 320KB drive */ (((pSrceBPB->bMedia == MEDIA_160) && (pDestBPB->bMedia == MEDIA_320)) || /* or if srce is 180KB and dest is 360KB drive */ ((pSrceBPB->bMedia == MEDIA_180) && (pDestBPB->bMedia == MEDIA_360)) || /* or if srce is 1.44MB and dest is 2.88MB drive */ ((pSrceBPB->bMedia == MEDIA_1440) && (pDestBPB->bMedia == MEDIA_2880) && ((nSrcDriveType == 7) || (nSrcDriveType == 9)) && (nDestDriveType == 9)) || /* or if srce is 360KB and dest is 1.2MB drive */ ((pSrceBPB->bMedia == MEDIA_360) && (pDestBPB->secPerTrack == 15))) return (TRUE); /* They are compatible */ } /* All other combinations are currently incompatible. */ return (FALSE); } /*--------------------------------------------------------------------------*/ /* */ /* ModifyDeviceParams() - */ /* */ /*--------------------------------------------------------------------------*/ /* Saves a copy of the drive parameters block and * Checks if the BPB of Drive and BPB of disk are different and if * so, modifies the drive parameter block accordingly. */ BOOL ModifyDeviceParams( INT nDrive, PDevPB pdpbParams, HANDLE *phSaveParams, PBPB pDriveBPB, PBPB pMediaBPB) { INT iDriveCode; HANDLE hNewDPB; PDevPB pNewDPB; if (!(*phSaveParams = BuildDevPB(pdpbParams))) return FALSE; /* Check if the Disk and Drive have the same parameters */ if (pMediaBPB->bMedia != pDriveBPB->bMedia) { /* They are not equal; So, it must be a 360KB floppy in a 1.2MB drive * or a 720KB floppy in a 1.44MB drive kind of situation!. * So, modify the DriveParameterBlock's BPB. */ *(PBPB)&(pdpbParams->BPB) = *pMediaBPB; } if (wDOSversion >= DOS_320) { /* Build a DPB with TrackLayout */ if (!(hNewDPB = BuildDevPB(pdpbParams))) goto MDP_Error; pNewDPB = (PDevPB)LocalLock(hNewDPB); pNewDPB->SplFunctions = 4; /* To Set parameters */ /* Check if this is a 360KB floppy; And if it is a 1.2MB drive, the * number of cylinders and mediatype field are wrong; So, we modify * these fields here anyway; * This is required to format a 360KB floppy on a NCR PC916 machine; * Fix for Bug #6894 --01-10-90-- SANKAR */ if (pMediaBPB->bMedia == MEDIA_360) { pNewDPB->NumCyls = 40; pNewDPB->bMediaType = 1; } LocalUnlock(hNewDPB); LocalFree(hNewDPB); } else { iDriveCode = 0; switch (pMediaBPB->bMedia) { case MEDIA_360: case MEDIA_320: if ((pDriveBPB->bMedia == MEDIA_360) || (pDriveBPB->bMedia == MEDIA_320)) iDriveCode = 1; /* Must be 360/320KB in 360KB drive */ else iDriveCode = 2; /* Must be 360/320Kb in 1.2MB drive */ break; case MEDIA_1200: iDriveCode = 3; /* Must be 1.2MB in 1.2MB drive */ break; } if (iDriveCode) SetDASD((WORD)nDrive, (BYTE)iDriveCode); } return (TRUE); /* Error handling */ MDP_Error: if (hNewDPB) LocalFree(hNewDPB); if (*phSaveParams) { LocalFree(*phSaveParams); *phSaveParams = NULL; } return (FALSE); } /*--------------------------------------------------------------------------*/ /* */ /* FormatAllTracks() - */ /* */ /*--------------------------------------------------------------------------*/ BOOL FormatAllTracks( PDISKINFO pDisketteInfo, WORD wStartCylinder, WORD wStartHead, LPSTR lpDiskBuffer) { INT iErrCode; BOOL bRetValue = TRUE; WORD wTotalCylinders; WORD wSecPerTrack; WORD wHeads; WORD wDrive; LoadString(hAppInstance, IDS_FORMATTINGDEST, szMessage, 128); SendDlgItemMessage(hdlgProgress, IDD_PROGRESS, WM_SETTEXT, 0, (LPARAM)szMessage); bFormatDone = TRUE; wDrive = pDisketteInfo->wDrive; if (wDOSversion >= DOS_320) { pTrackLayout->SplFunctions = 5; } else { if ((pTrackLayout->BPB.bMedia == 0xF9) && /* high density */ (pTrackLayout->BPB.secPerTrack == 15)) /* 1.2 Meg Drive */ SetDASD(wDrive, 3); /* 1.2 MB floppy in 1.2MB drive */ } wTotalCylinders = pDisketteInfo->wLastCylinder + 1; wSecPerTrack = pDisketteInfo->wSectorsPerTrack; wHeads = pDisketteInfo->wHeads; /* Format tracks one by one, checking if the user has "Aborted" * after each track is formatted; DlgProgreeProc() will set the global * bUserAbort, if the user has aborted; */ while (wStartCylinder < wTotalCylinders) { /* Has the user aborted? */ if (WFQueryAbort()) { bRetValue = FALSE; break; } /* If no message is pending, go ahead and format one track */ if ((iErrCode = GenericFormatTrack(wDrive, wStartCylinder, wStartHead, wSecPerTrack, lpDiskBuffer))) { /* Check if it is a fatal error */ if (iErrCode == -1) { bRetValue = FALSE; break; } } if (++wStartHead >= wHeads) { wStartHead = 0; wStartCylinder++; } } if (wDOSversion >= DOS_320) { pTrackLayout->SplFunctions = 4; } return (bRetValue); } /*--------------------------------------------------------------------------*/ /* */ /* GenericReadWriteSector() - */ /* */ /*--------------------------------------------------------------------------*/ /* Checks the DOS version number; If it is >= 3.2, then IOCTL * calls are made to read/write; Else it calls int13 read/write. */ INT APIENTRY GenericReadWriteSector( LPSTR lpBuffer, WORD wFunction, WORD wDrive, WORD wCylinder, WORD wHead, WORD wCount) { struct RW_PARMBLOCK RW_ParmBlock; /* If the DOS version is >= 3.2, we use DOS IOCTL function calls. */ if (wDOSversion >= DOS_320) { RW_ParmBlock.bSplFn = 0; RW_ParmBlock.wHead = wHead; RW_ParmBlock.wCylinder = wCylinder; RW_ParmBlock.wStSector = 0; RW_ParmBlock.wCount = wCount; RW_ParmBlock.lpBuffer = lpBuffer; return (0); } else /* Use Int13 function calls. */ return (MyReadWriteSector(lpBuffer, wFunction, wDrive, wCylinder, wHead, wCount)); } /*--------------------------------------------------------------------------*/ /* */ /* AllocDiskCopyBuffers() - */ /* */ /*--------------------------------------------------------------------------*/ BOOL AllocDiskCopyBuffers( PDISKINFO pDisketteInfo ) { HANDLE hMemTemp; ENTER("AllocDiskCopyBuffers"); hFormatBuffer = LocalAlloc(LHND, (LONG)(2*CBSECTORSIZE)); if (!hFormatBuffer) return FALSE; lpFormatBuffer = (LPSTR)LocalLock(hFormatBuffer); // We will try to reserve 16K for dialog boxes that comeup during diskcopy hMemTemp = LocalAlloc(LHND, (16 * 1024)); if (!hMemTemp) goto Failure; hDosMemory = (HANDLE)NULL; // now, lets try to allocate a buffer for the whole disk, and // if that fails try smaller // note, standard mode will only give us 1M chuncks dwDisketteBufferSize = pDisketteInfo->wCylinderSize * (pDisketteInfo->wLastCylinder + 1); // we will try down to 8 cylinders worth, less than that means // there will be too much disk swapping so don't bother do { hDisketteBuffer = LocalAlloc(LHND, dwDisketteBufferSize); if (hDisketteBuffer) { hpDisketteBuffer = (LPSTR)LocalLock(hDisketteBuffer); break; } else { // reduce request by 4 cylinders. dwDisketteBufferSize -= pDisketteInfo->wCylinderSize * 4; } } while (dwDisketteBufferSize > (DWORD)(8 * pDisketteInfo->wCylinderSize)); LocalFree(hMemTemp); // now free this up for user if (hDisketteBuffer) return TRUE; // fall through here to the failure case Failure: if (lpFormatBuffer) { LocalUnlock(hFormatBuffer); LocalFree(hFormatBuffer); } if (hDosMemory) // +++GlobalDosFree - NO 32BIT FORM+++(hDosMemory); LocalFree(hDosMemory); LEAVE("AllocDiskCopyBuffers"); return FALSE; } /*--------------------------------------------------------------------------*/ /* */ /* FreeBuffers() - */ /* */ /*--------------------------------------------------------------------------*/ VOID FreeBuffers() { if (lpFormatBuffer) { LocalUnlock(hFormatBuffer); LocalFree(hFormatBuffer); } if (hDosMemory) // +++GlobalDosFree - NO 32BIT FORM+++(hDosMemory); LocalFree(hDosMemory); if (hpDisketteBuffer) { LocalUnlock(hDisketteBuffer); LocalFree(hDisketteBuffer); } } /*--------------------------------------------------------------------------*/ /* */ /* GetDisketteInfo() - */ /* */ /*--------------------------------------------------------------------------*/ VOID GetDisketteInfo( PDISKINFO pDisketteInfo, PBPB pBPB ) { WORD secPerTrack; secPerTrack = pBPB->secPerTrack; /* Fill the DisketteInfo with the info from the default BPB. */ pDisketteInfo->wCylinderSize = secPerTrack * pBPB->cbSec * pBPB->cHead; pDisketteInfo->wLastCylinder = (pBPB->cSec / (secPerTrack * pBPB->cHead))-1; pDisketteInfo->wHeads = pBPB->cHead; pDisketteInfo->wSectorsPerTrack = secPerTrack; pDisketteInfo->wSectorSize = pBPB->cbSec; } /*--------------------------------------------------------------------------*/ /* */ /* DCopyMessageBox() - */ /* */ /*--------------------------------------------------------------------------*/ VOID DCopyMessageBox( HWND hwnd, WORD idString, WORD wFlags ) { LoadString(hAppInstance, IDS_COPYDISK, szTitle, sizeof(szTitle)); LoadString(hAppInstance, idString, szMessage, sizeof(szMessage)); MessageBox(hwnd, szMessage, szTitle, wFlags); } /*--------------------------------------------------------------------------*/ /* */ /* PromptDisketteChange() - */ /* */ /*--------------------------------------------------------------------------*/ VOID PromptDisketteChange( HWND hwnd, BOOL bWrite ) { WORD idString; if (bWrite) idString = IDS_INSERTDEST; else idString = IDS_INSERTSRC; /* These dialogs have to be sysmodal because the DiskCopy progress dialog * is now made a SysModal one; The following messagebox will hang if it * is NOT sysmodal; * A part of the Fix for Bug #10075 --SANKAR-- 03-05-90 */ DCopyMessageBox(hwnd, idString, MB_OK | MB_SYSTEMMODAL | MB_ICONINFORMATION); } /*--------------------------------------------------------------------------*/ /* */ /* ReadWriteCylinder() - */ // BOOL bWrite; TRUE for Write, FALSE for Read /* */ /*--------------------------------------------------------------------------*/ INT ReadWriteCylinder( BOOL bWrite, WORD wCylinder, PDISKINFO pDisketteInfo ) { register INT rc; WORD wHead; WORD wDrive; WORD wSectorCount; WORD wTrackSize; LPSTR lpBuffer; wDrive = pDisketteInfo->wDrive; wSectorCount = pDisketteInfo->wSectorsPerTrack; wTrackSize = (wSectorCount * pDisketteInfo->wSectorSize); if (hDosMemory) lpBuffer = lpDosMemory; /* Perform the operation for all the heads for a given cylinder */ for (wHead=0; wHead < pDisketteInfo->wHeads; wHead++) { if (!hDosMemory) lpBuffer = lpReadWritePtr; if (bWrite) { if (hDosMemory) memcpy(lpBuffer, lpReadWritePtr, wTrackSize); rc = GenericReadWriteSector((LPSTR)lpBuffer, INT13_WRITE, wDrive, wCylinder, wHead, wSectorCount); if (rc) { /* Format all tracks starting from the given track */ if (!bFormatDone) { if (!FormatAllTracks(pDisketteInfo, wCylinder, wHead, lpFormatBuffer)) return (-1); /* Failure */ rc = GenericReadWriteSector((LPSTR)lpBuffer, INT13_WRITE, wDrive, wCylinder, wHead, wSectorCount); } else break; } } else { rc = GenericReadWriteSector((LPSTR)lpBuffer, INT13_READ, wDrive, wCylinder, wHead, wSectorCount); if (hDosMemory) memcpy(lpReadWritePtr, lpBuffer, wTrackSize); /*** FIX30: What about the DOS 4.0 volume stuff??? ***/ } if (rc) return (-1); lpReadWritePtr += wTrackSize; } return (0); } /*--------------------------------------------------------------------------*/ /* */ /* ReadWriteMaxPossible() - */ // BOOL bWrite TRUE for Write, FALSE for Read /* */ /*--------------------------------------------------------------------------*/ /* This reads or writes as many cylinders as possible into the hpDisketteBuffer. * It returns the next cylinder to be read. */ INT ReadWriteMaxPossible( BOOL bWrite, WORD wStartCylinder, PDISKINFO pDisketteInfo ) { MSG msg; WORD wPercentDone; DWORD dwBufferSize; dwBufferSize = dwDisketteBufferSize; /* We will read a cylinder only if we can read the entire cylinder. */ while (dwBufferSize >= pDisketteInfo->wCylinderSize) { /* Check if any messages are pending */ if (!PeekMessage((LPMSG)&msg, (HWND)NULL, 0, 0, PM_REMOVE)) { /* No message; So, go ahead with read/write */ if (ReadWriteCylinder(bWrite, wStartCylinder, pDisketteInfo)) return (-1); wStartCylinder++; wCompletedCylinders++; /* Have we read/written all the cylinders? */ if (wStartCylinder > pDisketteInfo->wLastCylinder) break; /* Since each cylinder is counted once during read and once during * write, number of cylinders is multiplied by 50 and not 100. */ wPercentDone = (wCompletedCylinders * 50) / (pDisketteInfo->wLastCylinder + 1); if (LoadString(hAppInstance, IDS_PERCENTCOMP, szTitle, 32)) { wsprintf(szMessage, szTitle, wPercentDone); SendDlgItemMessage(hdlgProgress, IDD_PROGRESS, WM_SETTEXT, 0, (LPARAM)szMessage); } dwBufferSize -= pDisketteInfo->wCylinderSize; } else { /* Check if this is a message for the ProgressDlg */ if (!IsDialogMessage(hdlgProgress, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { /* That message might have resulted in a Abort */ if (bUserAbort) return (-1); } } } return (wStartCylinder); } /*--------------------------------------------------------------------------*/ /* */ /* ReadWrite() - */ // BOOL bWrite TRUE for Write, FALSE for Read /* */ /*--------------------------------------------------------------------------*/ /* This reads or writes as many cylinders as possible into the hpDisketteBuffer. * It returns the next cylinder to be read. */ INT ReadWrite( BOOL bWrite, WORD wStartCylinder, PDISKINFO pDisketteInfo ) { INT iRetVal = 0; return (iRetVal); } /*--------------------------------------------------------------------------*/ /* */ /* RestoreDPB() - */ /* */ /*--------------------------------------------------------------------------*/ BOOL RestoreDPB( INT nDisk, HANDLE hSavedParams ) { register PDevPB pDevPB; if (!(pDevPB = (PDevPB)LocalLock(hSavedParams))) return (FALSE); pDevPB->SplFunctions = 4; LocalUnlock(hSavedParams); LocalFree(hSavedParams); return (TRUE); } /*--------------------------------------------------------------------------*/ /* */ /* CopyDiskette() - */ /* */ /*--------------------------------------------------------------------------*/ /* NOTE: Returns positive value for success otherwise failure. */ INT APIENTRY CopyDiskette( HWND hwnd, WORD nSourceDisk, WORD nDestDisk ) { INT rc = -1; register WORD wCylinder; WORD wNextCylinder; PBPB pIoctlBPB; /* Source Drive's BPB (taken from DevicePB) */ PBPB pBootBPB; /* Boot Drive's BPB (taken from Boot sector) */ PBPB pDestBPB; DevPB dpbSrceParams; DevPB dpbDestParams; HANDLE hTrackLayout = NULL; HANDLE hSaveSrceParams; HANDLE hSaveDestParams; FARPROC lpfnDialog; DISKINFO SourceDisketteInfo; DISKINFO DestDisketteInfo; /* Check if it is a two drive system; put message to insert both floppies */ if (nSourceDisk != nDestDisk) { bSingleDrive = FALSE; DCopyMessageBox(hwnd, IDS_INSERTSRCDEST, MB_OK); } else { bSingleDrive = TRUE; DCopyMessageBox(hwnd, IDS_INSERTSRC, MB_OK); } /* Get the BiosParameterBlock of source drive */ if (!(pIoctlBPB = GetBPB(nSourceDisk, &dpbSrceParams))) return (0); /* Get the BiosParameterBlock of the Source Diskette */ if (!(pBootBPB = GetBootBPB(nSourceDisk))) return (0); /* Get the BPB and DPB for the Destination drive also; */ if (!bSingleDrive) { if (!(pDestBPB = GetBPB(nDestDisk, &dpbDestParams))) return (0); /* Compare BPB of source and Dest to see if they are compatible */ if (!(CheckBPBCompatibility(pIoctlBPB, dpbSrceParams.devType, pDestBPB, dpbDestParams.devType))) { DCopyMessageBox(hwnd, IDS_COPYSRCDESTINCOMPAT, MB_ICONHAND | MB_OK); return (0); } } if (!ModifyDeviceParams(nSourceDisk, &dpbSrceParams, &hSaveSrceParams, pIoctlBPB, pBootBPB)) return (0); if (!bSingleDrive) { if (!ModifyDeviceParams(nDestDisk, &dpbDestParams, &hSaveDestParams, pDestBPB, pBootBPB)) { RestoreDPB(nSourceDisk, hSaveSrceParams); return (0); } } GetDisketteInfo((PDISKINFO)&SourceDisketteInfo, pBootBPB); /* The Destination Diskette must have the same format as the source */ DestDisketteInfo = SourceDisketteInfo; /* Except the drive number */ SourceDisketteInfo.wDrive = nSourceDisk; DestDisketteInfo.wDrive = nDestDisk; /* In case we need to format the destination diskette, we need to know the * track layout; So, build a DPB with the required track layout; */ if (wDOSversion >= DOS_320) { if (!(hTrackLayout = BuildDevPB(&dpbSrceParams))) goto Failure0; pTrackLayout = (PDevPB)LocalLock(hTrackLayout); /* The following is required to format a 360KB floppy in a 1.2MB * drive of NCR PC916 machine; We do formatting, if the destination * floppy is an unformatted one; * Fix for Bug #6894 --01-10-90-- SANKAR -- */ if (pTrackLayout->BPB.bMedia == MEDIA_360) { pTrackLayout->NumCyls = 40; pTrackLayout->bMediaType = 1; } } /* We wish we could do the following allocation at the begining of this * function, but we can not do so, because we need SourceDisketteInfo * and we just got it; */ if (!AllocDiskCopyBuffers((PDISKINFO)&SourceDisketteInfo)) { DCopyMessageBox(hwnd, IDS_REASONS+DE_INSMEM, MB_ICONHAND | MB_OK); goto Failure0; } bUserAbort = FALSE; wCompletedCylinders = 0; hdlgProgress = CreateDialog(hAppInstance, (LPSTR)MAKEINTRESOURCE(DISKCOPYPROGRESSDLG), hwnd, ProgressDlgProc); if (!hdlgProgress) goto Failure2; EnableWindow(hwnd, FALSE); /* Start with the first cylinder. */ wCylinder = 0; while (wCylinder <= SourceDisketteInfo.wLastCylinder) { /* If this is a single drive system, ask the user to insert * the source diskette. * Do not prompt for the first time, because the Source diskette is * already in the drive. */ if (bSingleDrive && (wCylinder > 0)) PromptDisketteChange(hdlgProgress, FALSE); /* Read in the current cylinder. */ rc = ReadWrite(FALSE, wCylinder, (PDISKINFO)&SourceDisketteInfo); if (rc < 0) break; else wNextCylinder = (WORD)rc; /* If this is a single drive system, ask the user to insert * the destination diskette. */ if (bSingleDrive) PromptDisketteChange(hdlgProgress, TRUE); /* Write out the current cylinder. */ bFormatDone = FALSE; rc = ReadWrite(TRUE, wCylinder, (PDISKINFO)&DestDisketteInfo); if (rc < 0) break; wCylinder = wNextCylinder; } EnableWindow(hwnd, TRUE); DestroyWindow(hdlgProgress); hdlgProgress = NULL; Failure2: FreeBuffers(); Failure0: if (wDOSversion >= DOS_320) { /* Reset the Source drive parameters to the same as old */ RestoreDPB(nSourceDisk, hSaveSrceParams); if (!bSingleDrive) { /* Reset the Dest drive parameters to the same as old */ RestoreDPB(nDestDisk, hSaveDestParams); } } if ((wDOSversion >= DOS_320) && hTrackLayout) { LocalUnlock(hTrackLayout); LocalFree(hTrackLayout); } return (rc); }