[Image] [Image] [Image] [Image] [Image] [Image] [Image] [Return] Backup Tape Capacity [Return] --------------------------------------------------------------------------- The tape backup API is not really difficult...it's more or less like reading and writing to a file in sequential order, but it took more effort than I thought was really needed because of the surreal documentation. The function below is for my own good as much as anyone else's. The function, called by a dialog box in my little example, opens a tape, prepares the tape and waits for it to stabilize, then obtains the full and remaining capacity of the tape along with a couple other values of interest and displays the whole thing in a listbox. In the event of an error, the error code is also displayed in the listbox and the function ends. The main thing to note is the PrepareTape() function. Practically nothing can be done without calling it, and that's what burned me for a few hours. // === Obtain capacity and remaining space on a tape ========================== BOOL DoTapeSize( HWND hWnd ) { HANDLE hFile; DWORD dwSize, dwStatus; TAPE_GET_MEDIA_PARAMETERS tgmp; char szOutput[ 64 ]; hFile = CreateFile( "\\\\.\\TAPE0", // Open the tape drive GENERIC_READ | GENERIC_WRITE, // This defaults to the 0, 0, OPEN_EXISTING, 0, NULL ); // first tape drive if( hFile == INVALID_HANDLE_VALUE ) return( FALSE ); // Exit if open failed // This is important...nothing really works if not called dwStatus = PrepareTape( hFile, TAPE_LOCK, FALSE ); if( dwStatus != NO_ERROR && dwStatus != ERROR_MEDIA_CHANGED ) // Media change is apparently common { // so don't fail if that's the error wsprintf( szOutput, "Error %d with PrepareTape()", dwStatus ); SendDlgItemMessage( hWnd, 100, LB_ADDSTRING, 0, (LPARAM)szOutput ); CloseHandle( hFile ); return( FALSE ); } dwStatus = GetTapeStatus( hFile ); // Wait for the tape to be ready if( dwStatus != NO_ERROR ) // Which it should be after PrepareTape() { wsprintf( szOutput, "Error %d with GetTapeStatus()", dwStatus ); SendDlgItemMessage( hWnd, 100, LB_ADDSTRING, 0, (LPARAM)szOutput ); CloseHandle( hFile ); return( FALSE ); } memset( &tgmp, 0, sizeof(TAPE_GET_MEDIA_PARAMETERS) ); dwSize = sizeof(TAPE_GET_MEDIA_PARAMETERS); // Get tape parameters dwStatus = GetTapeParameters( hFile, GET_TAPE_MEDIA_INFORMATION, &dwSize, &tgmp ); if( dwStatus == NO_ERROR ) // If no error, show tape parameters { wsprintf( szOutput, "Block Size: %d", tgmp.BlockSize ); SendDlgItemMessage( hWnd, 100, LB_ADDSTRING, 0, (LPARAM)szOutput ); wsprintf( szOutput, "Partition Count: %d", tgmp.PartitionCount ); SendDlgItemMessage( hWnd, 100, LB_ADDSTRING, 0, (LPARAM)szOutput ); wsprintf( szOutput, "Write Protected: %d", tgmp.WriteProtected ); SendDlgItemMessage( hWnd, 100, LB_ADDSTRING, 0, (LPARAM)szOutput ); wsprintf( szOutput, "Capacity (lowpart): %d", tgmp.Capacity.LowPart ); SendDlgItemMessage( hWnd, 100, LB_ADDSTRING, 0, (LPARAM)szOutput ); wsprintf( szOutput, "Remaining (lowpart): %d", tgmp.Remaining.LowPart ); SendDlgItemMessage( hWnd, 100, LB_ADDSTRING, 0, (LPARAM)szOutput ); } else { wsprintf( szOutput, "Error %d with GetTapeParameters()", dwStatus ); SendDlgItemMessage( hWnd, 100, LB_ADDSTRING, 0, (LPARAM)szOutput ); CloseHandle( hFile ); return( FALSE ); } CloseHandle( hFile ); // Don't forget to close the handle and exit return( TRUE ); } . .