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

📄 serialstream.cs

📁 SerialPort 串口通讯用
💻 CS
📖 第 1 页 / 共 5 页
字号:
					else
						InternalResources.WinIOError(hr, String.Empty);
				}
			}
			return asyncResult;
		}


		// Internal method, wrapping the PInvoke to ReadFile().
		internal unsafe int ReadFileNative(HandleProtector hp, byte[] bytes, int offset, int count, NativeOverlapped* overlapped, out int hr)
		{
		
			// Don't corrupt memory when multiple threads are erroneously writing
			// to this stream simultaneously.
			if (bytes.Length - offset < count)
				throw new IndexOutOfRangeException(InternalResources.GetResourceString("IndexOutOfRange_IORaceCondition"));

			// You can't use the fixed statement on an array of length 0.
			if (bytes.Length==0) 
			{
				hr = 0;
				return 0;
			}

			int r = 0;
			int numBytesRead = 0;

			bool incremented = false;
			try 
			{
				if (hp.TryAddRef(ref incremented)) 
				{
					fixed(byte* p = bytes) 
					{		
						r = UnsafeNativeMethods.ReadFile(hp.Handle, p + offset, count, NativeMethods.NULL, overlapped);
					}
				}
				else
					hr = NativeMethods.ERROR_INVALID_HANDLE;  // Handle was closed.
			}
			finally 
			{
				if (incremented) hp.Release();
			}

			if (r==0) 
			{
				hr = Marshal.GetLastWin32Error();
				
				// Note: we should never silently swallow an error here without some
				// extra work.  We must make sure that BeginReadCore won't return an 
				// IAsyncResult that will cause EndRead to block, since the OS won't
				// call AsyncFSCallback for us.  
			
				// For invalid handles, detect the error and mark our handle
				// as closed to give slightly better error messages.  Also
				// help ensure we avoid handle recycling bugs.
				if (hr == NativeMethods.ERROR_INVALID_HANDLE)
					_handleProtector.ForciblyMarkAsClosed();

				return -1;
			}
			else
				hr = 0;
			return numBytesRead;
		}
			
		internal unsafe int WriteFileNative(HandleProtector hp, byte[] bytes, int offset, int count, NativeOverlapped* overlapped, out int hr) 
		{

			// Don't corrupt memory when multiple threads are erroneously writing
			// to this stream simultaneously.  (Note that the OS is reading from
			// the array we pass to WriteFile, but if we read beyond the end and
			// that memory isn't allocated, we could get an AV.)
			if (bytes.Length - offset < count)
				throw new IndexOutOfRangeException(InternalResources.GetResourceString("IndexOutOfRange_IORaceCondition"));

			// You can't use the fixed statement on an array of length 0.
			if (bytes.Length==0) 
			{
				hr = 0;
				return 0;
			}

			int numBytesWritten = 0;
			int r = 0;
            
			bool incremented = false;
			try 
			{
				if (hp.TryAddRef(ref incremented)) 
				{
					fixed(byte* p = bytes) 
					{
						r = UnsafeNativeMethods.WriteFile(hp.Handle, p + offset, count, NativeMethods.NULL, overlapped);
					}
				}
				else
					hr = NativeMethods.ERROR_INVALID_HANDLE;  // Handle was closed.
			}
			finally 
			{
				if (incremented) hp.Release();
			}

			if (r==0) 
			{
				hr = Marshal.GetLastWin32Error();
				// Note: we should never silently swallow an error here without some
				// extra work.  We must make sure that BeginWriteCore won't return an 
				// IAsyncResult that will cause EndWrite to block, since the OS won't
				// call AsyncFSCallback for us.  

				// For invalid handles, detect the error and mark our handle
				// as closed to give slightly better error messages.  Also
				// help ensure we avoid handle recycling bugs.
				if (hr == NativeMethods.ERROR_INVALID_HANDLE)
					_handleProtector.ForciblyMarkAsClosed();

				return -1;
			}
			else
				hr = 0;
			return numBytesWritten;          
		}

		// ----SUBSECTION: internal methods supporting events/async operation------*
		
		// This is the blocking method that waits for an event to occur.  It wraps the SDK's WaitCommEvent function.
		private unsafe int WaitForCommEvent() 
		{
			int eventsOccurred = 0;
			// monitor all events except TXEMPTY
			UnsafeNativeMethods.SetCommMask(_handleProtector.Handle, NativeMethods.ALL_EVENTS);
			
			AsyncSerialStream_AsyncResult asyncResult = new AsyncSerialStream_AsyncResult();
			asyncResult._userCallback = null;
			asyncResult._userStateObject = null;
			asyncResult._isWrite = false;
			asyncResult._oldTimeout = -1;
			asyncResult._numBufferedBytes = 0;
			ManualResetEvent waitHandle = new ManualResetEvent(false);
			asyncResult._waitHandle = waitHandle;
			
			Overlapped overlapped = new Overlapped(0, 0, 0, asyncResult);

			// Pack the Overlapped class, and store it in the async result
			NativeOverlapped* intOverlapped = overlapped.Pack(IOCallback);
			
			if (UnsafeNativeMethods.WaitCommEvent(_handleProtector.Handle, ref eventsOccurred, intOverlapped) == false) 
			{
				int hr = Marshal.GetLastWin32Error();
				if (hr == NativeMethods.ERROR_IO_PENDING) 
				{
					int temp = UnsafeNativeMethods.WaitForSingleObject(waitHandle.Handle, -1);
					if(temp == 0) // no error
						return eventsOccurred;
					else
						InternalResources.WinIOError();
				}		
				else
					InternalResources.WinIOError();
				
			}  
			return eventsOccurred;
		}
		
		// This is the cleanup method called when WaitCommEvent() has returned.
		[OneWayAttribute()]
		private void EndWaitForCommEvent(IAsyncResult ar)
		{
	      
			int errorEvents = (int) (SerialEvents.Frame | SerialEvents.Overrun 
				| SerialEvents.RxOver | SerialEvents.RxParity | SerialEvents.TxFull);
			int receivedEvents = (int) (SerialEvents.ReceivedChars | SerialEvents.EofReceived);	
			int pinChangedEvents = (int) (SerialEvents.Break | SerialEvents.CDChanged | SerialEvents.CtsChanged |
				SerialEvents.Ring | SerialEvents.DsrChanged);
			
			// Extract the delegate from the AsynchResult.
			WaitEventCallback myWaitCommCallback = 
				(WaitEventCallback) ((AsyncResult)ar).AsyncDelegate;
			// Obtain the result. 
			// The EV_CTS, EV_RLSD, EV_DSR, EV_BREAK, EV_RING, EV_RXCHAR match up with SerialEvents constants
			int nativeEvents = myWaitCommCallback.EndInvoke(ar);
			int errors = 0;
			int events = 0;
			
			if ((nativeEvents & NativeMethods.EV_ERR) != 0) 
			{
				if (UnsafeNativeMethods.ClearCommError(_handleProtector.Handle, ref errors, ref comStat) == false) 
				{
					InternalResources.WinIOError();
				}
				
				if ((errors & NativeMethods.CE_RXOVER) != 0) events |= (int) SerialEvents.RxOver;
				if ((errors & NativeMethods.CE_OVERRUN)  != 0) events |= (int)  SerialEvents.Overrun;
				if ((errors & NativeMethods.CE_PARITY) != 0) events |= (int) SerialEvents.RxParity;
				if ((errors & NativeMethods.CE_FRAME) != 0) events|= (int) SerialEvents.Frame;
				if ((errors & NativeMethods.CE_TXFULL) != 0) events |= (int) SerialEvents.TxFull;
				if ((errors & NativeMethods.CE_BREAK) != 0) events |= (int) SerialEvents.Break;

			}
			if ((nativeEvents & NativeMethods.EV_RXCHAR) != 0) events |= (int) SerialEvents.ReceivedChars;
			if ((nativeEvents & NativeMethods.EV_RXFLAG) != 0) events |= (int) SerialEvents.EofReceived;
			if ((nativeEvents & NativeMethods.EV_CTS) != 0) events |= (int) SerialEvents.CtsChanged;
			if ((nativeEvents & NativeMethods.EV_DSR) != 0) events |= (int) SerialEvents.DsrChanged;
			if ((nativeEvents & NativeMethods.EV_RLSD) != 0) events |= (int) SerialEvents.CDChanged;
			if ((nativeEvents & NativeMethods.EV_RING) != 0) events |= (int) SerialEvents.Ring;
			if ((nativeEvents & NativeMethods.EV_BREAK) != 0) events |= (int) SerialEvents.Break;
			
			
			// errors are corresponding SerialEvents shifted right 8 bits 
			if ((events & errorEvents) != 0) 
				ErrorEvent(this, new SerialEventArgs((SerialEvents) (events & errorEvents))); 
			if ((events & pinChangedEvents) != 0)
				PinChangedEvent(this, new SerialEventArgs((SerialEvents) (events & pinChangedEvents)));
			if ((events & receivedEvents) != 0) 
				ReceivedEvent(this, new SerialEventArgs((SerialEvents) (events & receivedEvents)));
				
			myWaitCommCallback.BeginInvoke(myAsyncCallback, state); // start it over again.	
		}
		
		
		// This is a the callback prompted when a thread completes any async I/O operation.  
		unsafe private static void AsyncFSCallback(uint errorCode, uint numBytes, NativeOverlapped* pOverlapped)
		{
			// Unpack overlapped
			Overlapped overlapped = Overlapped.Unpack(pOverlapped);
		    
			// Extract async the result from overlapped structure
			AsyncSerialStream_AsyncResult asyncResult = 
				(AsyncSerialStream_AsyncResult)overlapped.AsyncResult;
			asyncResult._numBytes = (int)numBytes;
            
			asyncResult._errorCode = (int)errorCode;

			// Pull waitHandle (here a ManualResetEvent) out of the asyncResult
			WaitHandle wh = asyncResult._waitHandle;
			if (wh != null) 
			{
				bool r = NativeMethods.SetEvent(wh.Handle);
				if (!r) InternalResources.WinIOError();
			}
			// Set IsCompleted after WaitHandle signaled in case SetEvent fails.
			asyncResult._isComplete = true;

			// Call the user-provided callback.  Note that it can and often should
			// call EndRead or EndWrite.  There's no reason to use an async 
			// delegate here - we're already on a threadpool thread.  
			// Note the IAsyncResult's completedSynchronously property must return
			// false here, saying the user callback was called on another thread.
		
			asyncResult._completedSynchronously = false;
			AsyncCallback userCallback = asyncResult._userCallback;
			if (userCallback!=null)
				userCallback(asyncResult);
		}
		
		
		// ----SECTION: internal classes --------*
		
		// This is an internal object implementing IAsyncResult with fields
		// for all of the relevant data necessary to complete the IO operation.
		// This is used by AsyncFSCallback and all async methods.
		unsafe internal class AsyncSerialStream_AsyncResult : IAsyncResult
		{
			// User code callback
			internal AsyncCallback _userCallback;
            
			internal Object _userStateObject;
			internal WaitHandle _waitHandle;
			internal GCHandle _bufferHandle;  // GCHandle to pin byte[].

			internal bool _isWrite;     // Whether this is a read or a write
			internal bool _isComplete;
			internal bool _completedSynchronously;  // Which thread called callback
			internal bool _bufferIsPinned;   // Whether our _bufferHandle is valid.
			internal int _EndXxxCalled;   // Whether we've called EndXxx already.
			internal int _numBytes;     // number of bytes read OR written
			internal int _numBufferedBytes;
			internal int _errorCode;
			internal NativeOverlapped* _overlapped;
				
			internal int _oldTimeout;	// added to preserve default timeouts on calls to specific timeouts
			/// <include file='doc\ModFileStream.uex' path='docs/doc[@for="ModFileStream.AsyncSerialStream_AsyncResult.AsyncState"]/*' />
			public virtual Object AsyncState
			{
				get { return _userStateObject; }
			}

			/// <include file='doc\ModFileStream.uex' path='docs/doc[@for="ModFileStream.AsyncSerialStream_AsyncResult.IsCompleted"]/*' />
			public bool IsCompleted
			{
				get { return _isComplete; }
				set { _isComplete = value; }
			}

			/// <include file='doc\ModFileStream.uex' path='docs/doc[@for="ModFileStream.AsyncSerialStream_AsyncResult.AsyncWaitHandle"]/*' />
			public WaitHandle AsyncWaitHandle
			{
				get { return _waitHandle; }
			}

			// Returns true iff the user callback was called by the thread that 
			// called BeginRead or BeginWrite.  If we use an async delegate or
			// threadpool thread internally, this will be false.  This is used
			// by code to determine whether a successive call to BeginRead needs 
			// to be done on their main thread or in their callback to avoid a
			// stack overflow on many reads or writes.
			public bool CompletedSynchronously
			{
				get { return _completedSynchronously; }
			}

			internal static AsyncSerialStream_AsyncResult CreateBufferedReadResult(int numBufferedBytes, AsyncCallback userCallback, Object userStateObject) 
			{
				AsyncSerialStream_AsyncResult asyncResult = new AsyncSerialStream_AsyncResult();
				asyncResult._userCallback = userCallback;
				asyncResult._userStateObject = userStateObject;
				asyncResult._isComplete = true;
				asyncResult._isWrite = false;
				asyncResult._numBufferedBytes = numBufferedBytes;
				return asyncResult;
			}
            
			// An internal convenience method
			internal void CallUserCallback()
			{
			
				if (_userCallback != null) 
				{
					// Call user's callback on a threadpool thread.  
					// we must set this to false, since this happens on another thread.
					_completedSynchronously = false;
					_userCallback.BeginInvoke(this, null, null);
					
					// note that we needn't call EndInvoke, since the IAsyncResult finalizer does cleanup.
				}
			}

			// Methods to ensure that if we somehow return from Win32 ReadFile() or WriteFile() 
			// and fill the buffer 

⌨️ 快捷键说明

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