2006-02-29 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[mono.git] / mcs / class / ByteFX.Data / Common / NamedPipeStream.cs
1 // ByteFX.Data data access components for .Net\r
2 // Copyright (C) 2002-2003  ByteFX, Inc.\r
3 //\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
8 // \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
13 // \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
17 \r
18 using System;\r
19 using System.IO;\r
20 using System.Runtime.InteropServices;\r
21 \r
22 \r
23 namespace ByteFX.Data.Common\r
24 {\r
25         /// <summary>\r
26         /// Summary description for API.\r
27         /// </summary>\r
28         internal class NamedPipeStream : Stream\r
29         {\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
50 \r
51                 //Constants for dwDesiredAccess:\r
52                 private const UInt32 GENERIC_READ = 0x80000000;\r
53                 private const UInt32 GENERIC_WRITE = 0x40000000;\r
54 \r
55                 //Constants for return value:\r
56                 private const Int32 INVALID_HANDLE_VALUE = -1;\r
57 \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
61 \r
62                 //Constants for dwCreationDisposition:\r
63                 private const UInt32 OPEN_EXISTING = 3;\r
64 \r
65                 IntPtr          _handle;\r
66                 FileAccess      _mode;\r
67 \r
68                 public NamedPipeStream(string host, FileAccess mode)\r
69                 {\r
70                         _handle = IntPtr.Zero;\r
71                         Open(host, mode);\r
72                 }\r
73 \r
74                 public void Open( string host, FileAccess mode )\r
75                 {\r
76                         _mode = mode;\r
77                         uint pipemode = 0;\r
78 \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
85                 }\r
86 \r
87                 public bool DataAvailable\r
88                 {\r
89                         get \r
90                         {\r
91                                 uint bytesRead=0, avail=0, thismsg=0;\r
92 \r
93                                 bool result = PeekNamedPipe( _handle, \r
94                                         null, 0, ref bytesRead, ref avail, ref thismsg );\r
95                                 return (result == true && avail > 0);\r
96                         }\r
97         }\r
98 \r
99                 public override bool CanRead\r
100                 {\r
101                         get { return (_mode & FileAccess.Read) > 0; }\r
102                 }\r
103 \r
104                 public override bool CanWrite\r
105                 {\r
106                         get { return (_mode & FileAccess.Write) > 0; }\r
107                 }\r
108 \r
109                 public override bool CanSeek\r
110                 {\r
111                         get { throw new NotSupportedException("NamedPipeStream does not support seeking"); }\r
112                 }\r
113 \r
114                 public override long Length\r
115                 {\r
116                         get { throw new NotSupportedException("NamedPipeStream does not support seeking"); }\r
117                 }\r
118 \r
119                 public override long Position \r
120                 {\r
121                         get { throw new NotSupportedException("NamedPipeStream does not support seeking"); }\r
122                         set { }\r
123                 }\r
124 \r
125                 public override void Flush() \r
126                 {\r
127                         if (_handle == IntPtr.Zero)\r
128                                 throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");\r
129                         FlushFileBuffers(_handle);\r
130                 }\r
131 \r
132                 public override int Read(byte[] buffer, int offset, int count)\r
133                 {\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
138                         if (offset < 0) \r
139                                 throw new ArgumentOutOfRangeException("offset", offset, "Offset cannot be negative");\r
140                         if (count < 0)\r
141                                 throw new ArgumentOutOfRangeException("count", count, "Count cannot be negative");\r
142                         if (! CanRead)\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
146 \r
147                         // first read the data into an internal buffer since ReadFile cannot read into a buf at\r
148                         // a specified offset\r
149                         uint read=0;\r
150                         byte[] buf = new Byte[count];\r
151                         ReadFile( _handle, buf, (uint)count, ref read, IntPtr.Zero );\r
152                         \r
153                         for (int x=0; x < read; x++) \r
154                         {\r
155                                 buffer[offset+x] = buf[x];\r
156                         }\r
157                         return (int)read;\r
158                 }\r
159 \r
160                 public override void Close()\r
161                 {\r
162                         CloseHandle(_handle);\r
163                         _handle = IntPtr.Zero;\r
164                 }\r
165 \r
166                 public override void SetLength(long length)\r
167                 {\r
168                         throw new NotSupportedException("NamedPipeStream doesn't support SetLength");\r
169                 }\r
170 \r
171                 public override void Write(byte[] buffer, int offset, int count)\r
172                 {\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
177                         if (offset < 0) \r
178                                 throw new ArgumentOutOfRangeException("offset", offset, "Offset cannot be negative");\r
179                         if (count < 0)\r
180                                 throw new ArgumentOutOfRangeException("count", count, "Count cannot be negative");\r
181                         if (! CanWrite)\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
185                         \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
189                         {\r
190                                 buf[x] = buffer[offset+x];\r
191                         }\r
192                         uint written=0;\r
193                         bool result = WriteFile( _handle, buf, (uint)count, ref written, IntPtr.Zero );\r
194 \r
195                         if (! result)\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
199                 }\r
200 \r
201                 public override long Seek( long offset, SeekOrigin origin )\r
202                 {\r
203                         throw new NotSupportedException("NamedPipeStream doesn't support seeking");\r
204                 }\r
205         }\r
206 }\r
207 \r
208 \r