⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serialstream.cs

📁 SerialPort 串口通讯用
💻 CS
📖 第 1 页 / 共 5 页
字号:
				InternalResources.WinIOError();
			}		
			
			if (!ThreadPool.BindHandle(_handleProtector.Handle)) 
			{
				throw new IOException(InternalResources.GetResourceString("IO.IO_BindHandleFailed"));
			}
		
			// prep. for starting event cycle.
			myWaitCommCallback = new WaitEventCallback(WaitForCommEvent);
			myAsyncCallback = new AsyncCallback(EndWaitForCommEvent);
			state = null;	// no need for new object, since we never use it.
			
			IAsyncResult ar = myWaitCommCallback.BeginInvoke(myAsyncCallback, state);
		}
	
		~SerialStream()
		{
			if (_handleProtector != null) 
			{
				Dispose(false);
			}
		}
		
		protected virtual void Dispose(bool disposing)
		{
		
			// Nothing will be done differently based on whether we are 
			// disposing vs. finalizing.
			
			// Signal the other side that we're closing.  Should do regardless of whether we've called
			// Close() or not Dispose() 
			if (_handleProtector != null) 
			{
				if (!_handleProtector.IsClosed) 
				{
					
					if(!UnsafeNativeMethods.EscapeCommFunction(_handleProtector.Handle, NativeMethods.CLRDTR)) 
					{
						// should not happen
						InternalResources.WinIOError();
					}
					Flush();
					_handleProtector.Close();
				}
			}
			
		
		}

		// -----SECTION: all public methods ------------------*
		
		// User-accessible async read method.  Returns AsyncSerialStream_AsyncResult : IAsyncResult
		public override IAsyncResult BeginRead(byte[] array, int offset,int numBytes, AsyncCallback userCallback, object stateObject)  
		{
			return BeginRead(array, offset, numBytes, userCallback, stateObject, ReadTimeout);
		}
		
		
		internal IAsyncResult BeginRead(byte[] array, int offset,int numBytes, 
			AsyncCallback userCallback, object stateObject, int timeout)  
		{	
			if (array==null)
				throw new ArgumentNullException("array");
			if (offset < 0)
				throw new ArgumentOutOfRangeException("offset", InternalResources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
			if (numBytes < 0)
				throw new ArgumentOutOfRangeException("numBytes", InternalResources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
			if (array.Length - offset < numBytes)
				throw new ArgumentException(InternalResources.GetResourceString("Argument_InvalidOffLen"));
			if (_handleProtector.IsClosed) InternalResources.FileNotOpen();
			return BeginReadCore(array, offset, numBytes, userCallback, stateObject, 0, timeout);
		}
		
		// User-accessible async write method.  Returns AsyncSerialStream_AsyncResult : IAsyncResult
		// Throws an exception if port is in break state.
		public override IAsyncResult BeginWrite(byte[] array, int offset, int numBytes, 
			AsyncCallback userCallback, object stateObject) 
		{
			return BeginWrite(array, offset, numBytes, userCallback, stateObject, WriteTimeout);
		}
			
		internal IAsyncResult BeginWrite(byte[] array, int offset, int numBytes, 
			AsyncCallback userCallback, object stateObject, int timeout) 
		{
			if (inBreak)
				throw new InvalidOperationException("BeginWrite in break");
			if (array==null)
				throw new ArgumentNullException("array");
			if (offset < 0)
				throw new ArgumentOutOfRangeException("offset", InternalResources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
			if (numBytes < 0)
				throw new ArgumentOutOfRangeException("numBytes", InternalResources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
			if (array.Length - offset < numBytes)
				throw new ArgumentException(InternalResources.GetResourceString("Argument_InvalidOffLen"));

			if (_handleProtector.IsClosed) InternalResources.FileNotOpen();
			return BeginWriteCore(array, offset, numBytes, userCallback, stateObject, timeout);
		}

		// Equivalent to MSComm's Break = false
		internal void ClearBreak()
		{
			if (UnsafeNativeMethods.ClearCommBreak(_handleProtector.Handle) == false) 
				InternalResources.WinIOError();
			inBreak = false;
		}

		// handle protector itself is closed in the Dispose() method, since we can Dispose() without calling
		// Close() in some cases.
		public override void Close()
		{
			if (_handleProtector.IsClosed) InternalResources.FileNotOpen();
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		// Uses Win32 method to dump out the receive buffer; analagous to MSComm's "InBufferCount = 0"
		internal void DiscardInBuffer()
		{
			
			if (UnsafeNativeMethods.PurgeComm(_handleProtector.Handle, NativeMethods.PURGE_RXCLEAR) == false)
				InternalResources.WinIOError();
		}

		// Uses Win32 method to dump out the xmit buffer; analagous to MSComm's "OutBufferCount = 0"
		internal void DiscardOutBuffer()
		{
			if (UnsafeNativeMethods.PurgeComm(_handleProtector.Handle, NativeMethods.PURGE_TXCLEAR) == false)
				InternalResources.WinIOError();
		}

		// Async companion to BeginRead.  
		// Note, assumed IAsyncResult argument is of derived type AsyncSerialStream_AsyncResult,
		// and throws an exception if untrue.
		public unsafe override int EndRead(IAsyncResult asyncResult) 
		{
			if (_handleProtector.IsClosed) InternalResources.FileNotOpen();
			if (asyncResult==null)
				throw new ArgumentNullException("asyncResult");

			AsyncSerialStream_AsyncResult afsar = asyncResult as AsyncSerialStream_AsyncResult;
			if (afsar==null || afsar._isWrite)
				InternalResources.WrongAsyncResult();

			// This sidesteps race conditions, avoids memory corruption after freeing the
			// NativeOverlapped class or GCHandle twice.  
			if (1 == Interlocked.CompareExchange(ref afsar._EndXxxCalled, 1, 0))
				InternalResources.EndReadCalledTwice();
			
			
			WaitHandle wh = afsar.AsyncWaitHandle;
				if (wh != null) 
				{
					
					if (!afsar.IsCompleted) 
					{
						do {
							// Since ReadFile() drops after a timeout (set above with SetCommTimeouts())
							// without a guarantee of setting the error property to indicate this, calculate
							// actual time elapsed here.
							// The granularity of the system is such that border cases may go either way,
							// but Windows makes no guarantees anyway.
							int beginTicks = SafeNativeMethods.GetTickCount();
							wh.WaitOne();
							// There's a subtle race condition here.  In AsyncFSCallback,
							// I must signal the WaitHandle then set _isComplete to be true,
							// to avoid closing the WaitHandle before AsyncFSCallback has
							// signalled it.  But with that behavior and the optimization
							// to call WaitOne only when IsCompleted is false, it's possible
							// to return from this method before IsCompleted is set to true.
							// This is currently completely harmless, so the most efficient
							// solution of just setting the field seems like the right thing
							// to do.     
							int currentTimeout = ReadTimeout;
							int endTicks = SafeNativeMethods.GetTickCount();
							if (endTicks - beginTicks >= currentTimeout && currentTimeout != SerialPort.InfiniteTimeout)
								lastOpTimedOut = true;		
							else 
								lastOpTimedOut = false;
						} while (afsar._numBytes == 0 && ReadTimeout == SerialPort.InfiniteTimeout);
						
						afsar._isComplete = true;
					}
					wh.Close();
				}

				// Free memory, GC handles.
				NativeOverlapped* overlappedPtr = afsar._overlapped;
				if (overlappedPtr != null)
					Overlapped.Free(overlappedPtr);
				afsar.UnpinBuffer();

				// Check for non-timeout errors during the read.
				if (afsar._errorCode != 0)
					InternalResources.WinIOError(afsar._errorCode, portName);
				
				// return to old timeout.  Note that this class is not thread-safe, and the timeout of read operation A 
				// is actually the minimum timeout of any read operation plus the time from A's invocation that B set a minimum timeout.
				// NOT THREAD SAFE. 
				ReadTimeout = afsar._oldTimeout;
				return afsar._numBytes + afsar._numBufferedBytes;
		}

		// Async companion to BeginWrite.  
		// Note, assumed IAsyncResult argument is of derived type AsyncSerialStream_AsyncResult,
		// and throws an exception if untrue.
		// Also fails if called in port's break state.
		public unsafe override void EndWrite(IAsyncResult asyncResult) 
		{		
			if (_handleProtector.IsClosed) InternalResources.FileNotOpen();
			if (inBreak)
				throw new InvalidOperationException("EndWrite in break");
			if (asyncResult==null)
				throw new ArgumentNullException("asyncResult");

			AsyncSerialStream_AsyncResult afsar = asyncResult as AsyncSerialStream_AsyncResult;
			if (afsar==null || !afsar._isWrite)
				InternalResources.WrongAsyncResult();

			// This sidesteps race conditions, avoids memory corruption after freeing the
			// NativeOverlapped class or GCHandle twice.  
			if (1 == Interlocked.CompareExchange(ref afsar._EndXxxCalled, 1, 0))
				InternalResources.EndWriteCalledTwice();

			WaitHandle wh = afsar.AsyncWaitHandle;
			if (wh != null) 
			{
				if (!afsar.IsCompleted) 
				{
					int beginTicks = SafeNativeMethods.GetTickCount();
					// Since WriteFile() drops after a timeout (set above with SetCommTimeouts())
					// without a guarantee of setting the error property to indicate this, calculate
					// actual time elapsed here.
					// The granularity of the system is such that border cases may go either way,
					// but Windows makes no guarantees anyway.  Plus, write timeouts should be extremely rare. 
					
					wh.WaitOne();
					// There's a subtle race condition here.  In AsyncFSCallback,
					// I must signal the WaitHandle then set _isComplete to be true,
					// to avoid closing the WaitHandle before AsyncFSCallback has
					// signalled it.  But with that behavior and the optimization
					// to call WaitOne only when IsCompleted is false, it's possible
					// to return from this method before IsCompleted is set to true.
					// This is currently completely harmless, so the most efficient
					// solution of just setting the field seems like the right thing
					// to do.    
					int currentTimeout = WriteTimeout;
					int endTicks = SafeNativeMethods.GetTickCount();
					if (endTicks - beginTicks >= currentTimeout && currentTimeout != SerialPort.InfiniteTimeout)
						throw new TimeoutException("Write Timed Out: " + (endTicks - beginTicks) + " > " + currentTimeout);
					afsar._isComplete = true;
				}
				wh.Close();
			}

			// Free memory, GC handles.
			NativeOverlapped* overlappedPtr = afsar._overlapped;
			if (overlappedPtr != null)
				Overlapped.Free(overlappedPtr);
			afsar.UnpinBuffer();

			// Now check for any error during the write.
			if (afsar._errorCode != 0)
				InternalResources.WinIOError(afsar._errorCode, portName);
			
			// return to old timeout. See read timeout commentary on race conditions.
			
			WriteTimeout = afsar._oldTimeout;
			// Number of bytes written is afsar._numBytes + afsar._numBufferedBytes.
			return;
		}

		// Flush dumps the contents of the serial driver's internal read and write buffers.
		// We actually expose the functionality for each, but fulfilling Stream's contract
		// requires a Flush() method.  Fails if handle closed.
		// Note: Serial driver's write buffer is *already* attempting to write it, so we can only wait until it finishes.
		public override void Flush() 
		{ 
			if (_handleProtector.Handle == NativeMethods.NULL) throw new InvalidOperationException("Flush - Stream not open!");
			DiscardInBuffer();
			DiscardOutBuffer();
			return;
		}

		// Blocking read operation, returning the number of bytes read from the stream.  
		
		public override int Read([In, Out] byte[] array, int offset, int count) 
		{
			return Read(array, offset, count, ReadTimeout);
		} 
		
		internal int Read([In, Out] byte[] array, int offset, int count, int timeout) 
		{
			if (array==null)
				throw new ArgumentNullException("array", InternalResources.GetResourceString("ArgumentNull_Buffer"));
			if (offset < 0)
				throw new ArgumentOutOfRangeException("offset", InternalResources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
			if (count < 0)
				throw new ArgumentOutOfRangeException("count", InternalResources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
			if (array.Length - offset < count)
				throw new ArgumentException(InternalResources.GetResourceString("Argument_InvalidOffLen"));
            if (count == 0) return 0; // return immediately if no bytes requested; no need for overhead.
            
            Debug.Assert(timeout == SerialPort.InfiniteTimeout || timeout >= 0, "Serial Stream Read - called with timeout " + timeout);
            
			// Check to see we have no handle-related error, since the port's always supposed to be open.
			if (_handleProtector.IsClosed) InternalResources.FileNotOpen();
            
			IAsyncResult result = BeginReadCore(array, offset, count, null, null, 0, timeout);
			return EndRead(result);
			
		}
		

		public override int ReadByte() 
		{
			return ReadByte(ReadTimeout);
		}
		
		internal int ReadByte(int timeout) 
		{
			if (_handleProtector.IsClosed) InternalResources.FileNotOpen();			
			
			IAsyncResult result = BeginReadCore(tempBuf, 0, 1, null, null, 0, timeout);
			int res = EndRead(result);
			
			if (lastOpTimedOut)
				return -1;
			else 
				return tempBuf[0];
		}

		public override long Seek(long offset, SeekOrigin origin) 
		{
			throw new NotSupportedException(InternalResources.GetResourceString("NotSupported_UnseekableStream")); 
		}

		// Equivalent to MSComm's Break = true		
		internal void SetBreak() 
		{
			
			if (UnsafeNativeMethods.SetCommBreak(_handleProtector.Handle) == false) 
				InternalResources.WinIOError();
			inBreak = true;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -