1 // ByteFX.Data data access components for .Net
\r
2 // Copyright (C) 2002-2003 ByteFX, Inc.
\r
4 // This library is free software; you can redistribute it and/or
\r
5 // modify it under the terms of the GNU Lesser General Public
\r
6 // License as published by the Free Software Foundation; either
\r
7 // version 2.1 of the License, or (at your option) any later version.
\r
9 // This library is distributed in the hope that it will be useful,
\r
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
12 // Lesser General Public License for more details.
\r
14 // You should have received a copy of the GNU Lesser General Public
\r
15 // License along with this library; if not, write to the Free Software
\r
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
20 using System.Runtime.InteropServices;
\r
23 namespace ByteFX.Data.Common
\r
26 /// Summary description for API.
\r
28 internal class NamedPipeStream : Stream
\r
30 [DllImport("kernel32.dll", EntryPoint="CreateFile", SetLastError=true)]
\r
31 private static extern IntPtr CreateFile(String lpFileName,
\r
32 UInt32 dwDesiredAccess, UInt32 dwShareMode,
\r
33 IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition,
\r
34 UInt32 dwFlagsAndAttributes,
\r
35 IntPtr hTemplateFile);
\r
36 [DllImport("kernel32.dll", EntryPoint="PeekNamedPipe", SetLastError=true)]
\r
37 private static extern bool PeekNamedPipe( IntPtr handle,
\r
38 byte[] buffer, uint nBufferSize, ref uint bytesRead,
\r
39 ref uint bytesAvail, ref uint BytesLeftThisMessage);
\r
40 [DllImport("kernel32.dll", SetLastError=true)]
\r
41 private static extern bool ReadFile( IntPtr handle,
\r
42 byte[] buffer, uint toRead, ref uint read, IntPtr lpOverLapped);
\r
43 [DllImport("kernel32.dll", SetLastError=true)]
\r
44 private static extern bool WriteFile( IntPtr handle,
\r
45 byte[] buffer, uint count, ref uint written, IntPtr lpOverlapped );
\r
46 [DllImport("kernel32.dll", SetLastError=true)]
\r
47 private static extern bool CloseHandle( IntPtr handle );
\r
48 [DllImport("kernel32.dll", SetLastError=true)]
\r
49 private static extern bool FlushFileBuffers( IntPtr handle );
\r
51 //Constants for dwDesiredAccess:
\r
52 private const UInt32 GENERIC_READ = 0x80000000;
\r
53 private const UInt32 GENERIC_WRITE = 0x40000000;
\r
55 //Constants for return value:
\r
56 private const Int32 INVALID_HANDLE_VALUE = -1;
\r
58 //Constants for dwFlagsAndAttributes:
\r
59 private const UInt32 FILE_FLAG_OVERLAPPED = 0x40000000;
\r
60 private const UInt32 FILE_FLAG_NO_BUFFERING = 0x20000000;
\r
62 //Constants for dwCreationDisposition:
\r
63 private const UInt32 OPEN_EXISTING = 3;
\r
68 public NamedPipeStream(string host, FileAccess mode)
\r
70 _handle = IntPtr.Zero;
\r
74 public void Open( string host, FileAccess mode )
\r
79 if ((mode & FileAccess.Read) > 0)
\r
80 pipemode |= GENERIC_READ;
\r
81 if ((mode & FileAccess.Write) > 0)
\r
82 pipemode |= GENERIC_WRITE;
\r
83 _handle = CreateFile( host, pipemode,
\r
84 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero );
\r
87 public bool DataAvailable
\r
91 uint bytesRead=0, avail=0, thismsg=0;
\r
93 bool result = PeekNamedPipe( _handle,
\r
94 null, 0, ref bytesRead, ref avail, ref thismsg );
\r
95 return (result == true && avail > 0);
\r
99 public override bool CanRead
\r
101 get { return (_mode & FileAccess.Read) > 0; }
\r
104 public override bool CanWrite
\r
106 get { return (_mode & FileAccess.Write) > 0; }
\r
109 public override bool CanSeek
\r
111 get { throw new NotSupportedException("NamedPipeStream does not support seeking"); }
\r
114 public override long Length
\r
116 get { throw new NotSupportedException("NamedPipeStream does not support seeking"); }
\r
119 public override long Position
\r
121 get { throw new NotSupportedException("NamedPipeStream does not support seeking"); }
\r
125 public override void Flush()
\r
127 if (_handle == IntPtr.Zero)
\r
128 throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");
\r
129 FlushFileBuffers(_handle);
\r
132 public override int Read(byte[] buffer, int offset, int count)
\r
134 if (buffer == null)
\r
135 throw new ArgumentNullException("buffer", "The buffer to read into cannot be null");
\r
136 if (buffer.Length < (offset + count))
\r
137 throw new ArgumentException("Buffer is not large enough to hold requested data", "buffer");
\r
139 throw new ArgumentOutOfRangeException("offset", offset, "Offset cannot be negative");
\r
141 throw new ArgumentOutOfRangeException("count", count, "Count cannot be negative");
\r
143 throw new NotSupportedException("The stream does not support reading");
\r
144 if (_handle == IntPtr.Zero)
\r
145 throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");
\r
147 // first read the data into an internal buffer since ReadFile cannot read into a buf at
\r
148 // a specified offset
\r
150 byte[] buf = new Byte[count];
\r
151 ReadFile( _handle, buf, (uint)count, ref read, IntPtr.Zero );
\r
153 for (int x=0; x < read; x++)
\r
155 buffer[offset+x] = buf[x];
\r
160 public override void Close()
\r
162 CloseHandle(_handle);
\r
163 _handle = IntPtr.Zero;
\r
166 public override void SetLength(long length)
\r
168 throw new NotSupportedException("NamedPipeStream doesn't support SetLength");
\r
171 public override void Write(byte[] buffer, int offset, int count)
\r
173 if (buffer == null)
\r
174 throw new ArgumentNullException("buffer", "The buffer to write into cannot be null");
\r
175 if (buffer.Length < (offset + count))
\r
176 throw new ArgumentException("Buffer does not contain amount of requested data", "buffer");
\r
178 throw new ArgumentOutOfRangeException("offset", offset, "Offset cannot be negative");
\r
180 throw new ArgumentOutOfRangeException("count", count, "Count cannot be negative");
\r
182 throw new NotSupportedException("The stream does not support writing");
\r
183 if (_handle == IntPtr.Zero)
\r
184 throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");
\r
186 // copy data to internal buffer to allow writing from a specified offset
\r
187 byte[] buf = new Byte[count];
\r
188 for (int x=0; x < count; x++)
\r
190 buf[x] = buffer[offset+x];
\r
193 bool result = WriteFile( _handle, buf, (uint)count, ref written, IntPtr.Zero );
\r
196 throw new IOException("Writing to the stream failed");
\r
197 if (written < count)
\r
198 throw new IOException("Unable to write entire buffer to stream");
\r
201 public override long Seek( long offset, SeekOrigin origin )
\r
203 throw new NotSupportedException("NamedPipeStream doesn't support seeking");
\r