I appreciate your effort.
Here is my modified code. I checked that the device is OK and I called the function Load first. but the problem still exists.
Also, I tried your original class in .Net 2.0 environment and reached the same problem.
when write and flush, the error is: "IO operation will not work. Most likely the file will become too long or the handle was not opened to support synchronous IO operations"
when read, the error is "Handle does not support synchronous operations. The parameters to the FileStream constructor may need to be changed to indicate that the handle was opened asynchronously"
i.e. when write, it need synchronous (where it is already so). when read, it needs asynchronous (which gives an error in constructor if I tried).
Also here is my consuming code
For write:
TapeOperator tape = new TapeOperator();
tape.Load(@"\\.\Tape0");
byte[] BS = new byte[n];
FileStream fs = new FileStream("c:\\Mos.txt",FileMode.Open,FileAccess.Read);
fs.Read(BS,0,(int)fs.Length);
fs.Close();
tape.Write(0, BS);
tape.Close();
For read :
TapeOperator tape = new TapeOperator();
tape.Load(@"\\.\Tape0");
byte[] BS = tape.Read(0);
FileStream fs = new FileStream("c:\\result.txt",FileMode.Open, FileAccess.Write);
fs.Write(BS,0,BS.Length);
fs.Close();
tape.Close();
The class after .Net 1.1 modifications:
using System;<br />
using System.IO;<br />
using System.Runtime.InteropServices;<br />
<br />
<br />
using System.Text;<br />
<br />
namespace Tape<br />
{<br />
#region Typedefenitions<br />
using BOOL = System.Int32;<br />
#endregion<br />
<br />
public class TapeOperator<br />
{<br />
#region Types<br />
<br />
[StructLayout(LayoutKind.Sequential)] <br />
private struct MediaInfo<br />
{<br />
public long Capacity;<br />
public long Remaining;<br />
<br />
public uint BlockSize;<br />
public uint PartitionCount;<br />
<br />
public byte IsWriteProtected;<br />
}<br />
<br />
[StructLayout( LayoutKind.Sequential )]<br />
private class DriveInfo<br />
{<br />
public byte ECC;<br />
public byte Compression;<br />
public byte DataPadding;<br />
public byte ReportSetMarks;<br />
<br />
public uint DefaultBlockSize;<br />
public uint MaximumBlockSize;<br />
public uint MinimumBlockSize;<br />
public uint PartitionCount;<br />
<br />
public uint FeaturesLow;<br />
public uint FeaturesHigh;<br />
public uint EATWarningZone;<br />
}<br />
#endregion<br />
<br />
#region Public constnts<br />
private const short FILE_ATTRIBUTE_NORMAL = 0x80;<br />
private const short INVALID_HANDLE_VALUE = -1;<br />
private const uint GENERIC_READ = 0x80000000;<br />
private const uint GENERIC_WRITE = 0x40000000;<br />
private const uint CREATE_NEW = 1;<br />
private const uint CREATE_ALWAYS = 2;<br />
private const uint OPEN_EXISTING = 3;<br />
private const uint FILE_ATTRIBUTE_ARCHIVE = 0x00000020;<br />
private const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;<br />
<br />
private const uint NO_ERROR = 0;<br />
private const int TAPE_LOAD = 0;<br />
private const int TAPE_UNLOAD = 1;<br />
<br />
<br />
private const int TAPE_RELATIVE_BLOCKS = 5;<br />
<br />
private const int TAPE_LOGICAL_BLOCK = 2;<br />
private const int TAPE_LOGICAL_POSITION = 1;<br />
<br />
private const int FALSE = 0;<br />
private const int TRUE = 0;<br />
<br />
private const int MEDIA_PARAMS = 0;<br />
private const int DRIVE_PARAMS = 1;<br />
#endregion<br />
<br />
#region PInvoke<br />
[DllImport( "kernel32.dll", SetLastError = true )]<br />
private static extern IntPtr CreateFile(<br />
string lpFileName,<br />
uint dwDesiredAccess,<br />
uint dwShareMode,<br />
IntPtr lpSecurityAttributes,<br />
uint dwCreationDisposition,<br />
uint dwFlagsAndAttributes,<br />
IntPtr hTemplateFile<br />
);<br />
<br />
[DllImport( "kernel32", SetLastError = true )]<br />
private static extern int PrepareTape(<br />
IntPtr handle,<br />
int prepareType,<br />
BOOL isImmediate<br />
);<br />
<br />
<br />
[DllImport( "kernel32", SetLastError = true )]<br />
private static extern int SetTapePosition(<br />
IntPtr handle,<br />
int positionType,<br />
int partition,<br />
int offsetLow,<br />
int offsetHigh,<br />
BOOL isImmediate<br />
);<br />
<br />
[DllImport( "kernel32", SetLastError = true )]<br />
private static extern int GetTapePosition(<br />
IntPtr handle,<br />
int positionType,<br />
out int partition,<br />
out int offsetLow,<br />
out int offsetHigh<br />
);<br />
<br />
[DllImport( "kernel32", SetLastError = true )]<br />
private static extern int GetTapeParameters(<br />
IntPtr handle,<br />
int operationType,<br />
ref int size,<br />
IntPtr mediaInfo<br />
);<br />
<br />
[DllImport( "kernel32", SetLastError = true )]<br />
private static extern int GetLastError();<br />
#endregion<br />
<br />
#region Private variables<br />
private FileStream m_stream;<br />
<br />
private IntPtr m_handleValue = IntPtr.Zero;<br />
private DriveInfo m_driveInfo = null; <br />
#endregion<br />
<br />
#region Public methods<br />
<br />
public void Load( string tapeName )<br />
{<br />
m_handleValue = CreateFile(<br />
tapeName,<br />
GENERIC_READ | GENERIC_WRITE,<br />
0,<br />
IntPtr.Zero,<br />
OPEN_EXISTING,<br />
FILE_ATTRIBUTE_ARCHIVE | FILE_FLAG_BACKUP_SEMANTICS,<br />
IntPtr.Zero<br />
);<br />
<br />
if ( m_handleValue == IntPtr.Zero )<br />
{<br />
throw new TapeOperatorWin32Exception(<br />
"CreateFile", Marshal.GetLastWin32Error() );<br />
}<br />
<br />
int result = PrepareTape(<br />
m_handleValue,<br />
TAPE_LOAD,<br />
TRUE<br />
);<br />
<br />
if ( result != NO_ERROR )<br />
{<br />
throw new TapeOperatorWin32Exception(<br />
"PrepareTape", Marshal.GetLastWin32Error() );<br />
}<br />
<br />
m_stream = new FileStream(<br />
m_handleValue,<br />
FileAccess.ReadWrite,<br />
true,<br />
65536,<br />
false<br />
);<br />
}<br />
<br />
public void Write( long startPos, byte[] stream )<br />
{<br />
uint numberOfBlocks = GetBlocksNumber( stream.Length );<br />
<br />
SetTapePosition( startPos );<br />
<br />
byte[] arrayToWrite = new byte[ numberOfBlocks * BlockSize ];<br />
Array.Copy( stream, arrayToWrite, stream.Length );<br />
<br />
m_stream.Write( stream, 0, stream.Length );<br />
m_stream.Flush();<br />
}<br />
<br />
public byte[] Read( long startPosition )<br />
{<br />
byte[] buffer = new byte[ BlockSize ];<br />
<br />
SetTapePosition( startPosition );<br />
<br />
m_stream.Read( buffer, 0, buffer.Length );<br />
m_stream.Flush();<br />
<br />
return buffer;<br />
}<br />
<br />
public byte[] Read( long startPosition, long bytes )<br />
{<br />
uint blocksNumber = GetBlocksNumber( bytes );<br />
int module = Convert.ToInt32( bytes % BlockSize ); <br />
<br />
byte[] buffer = new byte[ bytes ];<br />
<br />
for ( uint i = 0; i < blocksNumber; i++ )<br />
{<br />
byte[] temp = Read( i + startPosition );<br />
<br />
if ( i + 1 != blocksNumber )<br />
{<br />
Array.Copy( temp, 0, buffer, BlockSize * i, BlockSize );<br />
}<br />
else<br />
{<br />
Array.Copy( temp, 0, buffer, BlockSize * i, module ); <br />
}<br />
<br />
}
<br />
return buffer;<br />
}<br />
<br />
public bool CanRead( long startPosition )<br />
{<br />
bool status = true;<br />
long pos = GetTapePosition();<br />
<br />
try<br />
{<br />
Read( startPosition );<br />
}<br />
catch<br />
{<br />
status = false;<br />
}<br />
finally<br />
{<br />
SetTapePosition( pos );<br />
}<br />
<br />
return status;<br />
}<br />
<br />
public bool CanRead( long startPosition, long bytes )<br />
{<br />
bool status = true;<br />
long pos = GetTapePosition();<br />
<br />
try<br />
{<br />
Read( startPosition, bytes );<br />
}<br />
catch<br />
{<br />
status = false;<br />
}<br />
finally<br />
{<br />
SetTapePosition( pos );<br />
}<br />
<br />
return status;<br />
}<br />
<br />
public void Close()<br />
{<br />
if (m_handleValue != IntPtr.Zero)<br />
{<br />
m_handleValue = IntPtr.Zero;<br />
}<br />
}<br />
<br />
public void SetTapePosition( long logicalBlock )<br />
{<br />
int errorCode = 0;<br />
<br />
if ( ( errorCode = SetTapePosition(<br />
m_handleValue,<br />
TAPE_LOGICAL_BLOCK,<br />
0,<br />
( int )logicalBlock,<br />
0,<br />
TRUE ) ) != NO_ERROR )<br />
{<br />
throw new TapeOperatorWin32Exception(<br />
"SetTapePosition", Marshal.GetLastWin32Error() );<br />
}<br />
}<br />
<br />
public long GetTapePosition()<br />
{<br />
int partition;<br />
int offsetLow;<br />
int offsetHigh;<br />
<br />
if ( GetTapePosition(<br />
m_handleValue,<br />
TAPE_LOGICAL_POSITION,<br />
out partition,<br />
out offsetLow,<br />
out offsetHigh ) != NO_ERROR )<br />
{<br />
throw new TapeOperatorWin32Exception(<br />
"GetTapePosition", Marshal.GetLastWin32Error() );<br />
}<br />
<br />
long offset = ( long )( offsetHigh * Math.Pow( 2, 32 ) + offsetLow );<br />
<br />
return offset;<br />
}<br />
#endregion<br />
<br />
#region Public properties<br />
<br />
public IntPtr Handle<br />
{<br />
get<br />
{<br />
if ( m_handleValue != IntPtr.Zero )<br />
{<br />
return m_handleValue;<br />
}<br />
else<br />
{<br />
return IntPtr.Zero;<br />
}<br />
}
}<br />
<br />
public uint BlockSize<br />
{<br />
get<br />
{<br />
IntPtr ptr = IntPtr.Zero;<br />
try<br />
{<br />
if ( m_driveInfo== null )<br />
{<br />
m_driveInfo = new DriveInfo();<br />
<br />
int size = Marshal.SizeOf( m_driveInfo );<br />
ptr = Marshal.AllocHGlobal( size );<br />
<br />
Marshal.StructureToPtr(<br />
m_driveInfo,<br />
ptr,<br />
false<br />
);<br />
<br />
<br />
int result = 0;<br />
if ( ( result = GetTapeParameters(<br />
m_handleValue,<br />
DRIVE_PARAMS,<br />
ref size,<br />
ptr ) ) != NO_ERROR )<br />
{<br />
throw new TapeOperatorWin32Exception(<br />
"GetTapeParameters", Marshal.GetLastWin32Error() ); <br />
}<br />
<br />
m_driveInfo = ( DriveInfo )<br />
Marshal.PtrToStructure( ptr, typeof( DriveInfo ) );<br />
}<br />
<br />
<br />
return m_driveInfo.DefaultBlockSize;<br />
}<br />
finally<br />
{<br />
if ( ptr != IntPtr.Zero )<br />
{<br />
Marshal.FreeHGlobal( ptr );<br />
}<br />
}<br />
}<br />
}<br />
#endregion<br />
<br />
#region Private methods<br />
<br />
private uint GetBlocksNumber(long bytes)<br />
{<br />
uint numberOfBlocks = ( uint )bytes / BlockSize;<br />
uint bytesInLastBlock = ( uint )bytes % BlockSize;<br />
<br />
if ( bytesInLastBlock > 0 ) numberOfBlocks++;<br />
<br />
return numberOfBlocks;<br />
}<br />
#endregion<br />
}<br />
<br />
public class TapeOperatorWin32Exception : ApplicationException<br />
{<br />
public TapeOperatorWin32Exception( string methodName, int win32ErroCode ):<br />
base( string.Format(<br />
"WIN32 API method failed : {0} failed with error code {1}",<br />
methodName,<br />
win32ErroCode<br />
) ){}<br />
}<br />
<br />
}
-- modified at 6:56 Tuesday 12th September, 2006
|