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

📄 commbase.cs

📁 封装COM的操作的Windows API
💻 CS
📖 第 1 页 / 共 4 页
字号:
						ThrowException("Unexpected Failure");
				}
				else
				{
					if (Win32Com.EscapeCommFunction(hPort, Win32Com.CLRDTR))
						stateDTR = 0;
					else
						ThrowException("Unexpected Failure");
				}
			}
			get {
				return (stateDTR == 1);
			}
		}

		/// <summary>
		/// Assert or remove a break condition from the transmission line
		/// </summary>
		protected bool Break {
			set {
				if (stateBRK > 1) return;
				CheckOnline();
				if (value)
				{
					if (Win32Com.EscapeCommFunction(hPort, Win32Com.SETBREAK))
						stateBRK = 0;
					else
						ThrowException("Unexpected Failure");
				}
				else
				{
					if (Win32Com.EscapeCommFunction(hPort, Win32Com.CLRBREAK))
						stateBRK = 0;
					else
						ThrowException("Unexpected Failure");
				}
			}
			get {
				return (stateBRK == 1);
			}
		}

		/// <summary>
		/// Override this to provide settings. (NB this is called during Open method)
		/// </summary>
		/// <returns>CommBaseSettings, or derived object with required settings initialised</returns>
		protected virtual CommBaseSettings CommSettings() {return new CommBaseSettings();}

		/// <summary>
		/// Override this to provide processing after the port is openned (i.e. to configure remote
		/// device or just check presence).
		/// </summary>
		/// <returns>false to close the port again</returns>
		protected virtual bool AfterOpen() {return true;}

		/// <summary>
		/// Override this to provide processing prior to port closure.
		/// </summary>
		/// <param name="error">True if closing due to an error</param>
		protected virtual void BeforeClose(bool error) {}
		
		/// <summary>
		/// Override this to process received bytes.
		/// </summary>
		/// <param name="ch">The byte that was received</param>
		protected virtual void OnRxChar(byte ch) {}

		/// <summary>
		/// Override this to take action when transmission is complete (i.e. all bytes have actually
		/// been sent, not just queued).
		/// </summary>
		protected virtual void OnTxDone() {}

		/// <summary>
		/// Override this to take action when a break condition is detected on the input line.
		/// </summary>
		protected virtual void OnBreak() {}

		/// <summary>
		/// Override this to take action when a ring condition is signalled by an attached modem.
		/// </summary>
		protected virtual void OnRing() {}

		/// <summary>
		/// Override this to take action when one or more modem status inputs change state
		/// </summary>
		/// <param name="mask">The status inputs that have changed state</param>
		/// <param name="state">The state of the status inputs</param>
		protected virtual void OnStatusChange(ModemStatus mask, ModemStatus state) {}

		/// <summary>
		/// Override this to take action when the reception thread closes due to an exception being thrown.
		/// </summary>
		/// <param name="e">The exception which was thrown</param>
		protected virtual void OnRxException(Exception e) {}

		private void ReceiveThread() {
			byte[] buf = new Byte[1];
			uint gotbytes;

			AutoResetEvent sg = new AutoResetEvent(false);
			Win32Com.OVERLAPPED ov = new Win32Com.OVERLAPPED();
			IntPtr unmanagedOv = Marshal.AllocHGlobal(Marshal.SizeOf(ov));
			ov.Offset = 0; ov.OffsetHigh = 0;
			ov.hEvent = sg.Handle;
			Marshal.StructureToPtr(ov, unmanagedOv, true);

			uint eventMask = 0;
			IntPtr uMask = Marshal.AllocHGlobal(Marshal.SizeOf(eventMask));

			try
			{
				while(true) 
				{
					if (!Win32Com.SetCommMask(hPort, Win32Com.EV_RXCHAR | Win32Com.EV_TXEMPTY | Win32Com.EV_CTS | Win32Com.EV_DSR
						| Win32Com.EV_BREAK | Win32Com.EV_RLSD | Win32Com.EV_RING | Win32Com.EV_ERR))
					{
						throw new CommPortException("IO Error [001]");
					}
					Marshal.WriteInt32(uMask, 0);
					if (!Win32Com.WaitCommEvent(hPort, uMask, unmanagedOv)) 
					{
						if (Marshal.GetLastWin32Error() == Win32Com.ERROR_IO_PENDING) 
						{
							sg.WaitOne();
						}
						else
						{
							throw new CommPortException("IO Error [002]");
						}
					}
					eventMask = (uint)Marshal.ReadInt32(uMask);
					if ((eventMask & Win32Com.EV_ERR) != 0)
					{
						UInt32 errs;
						if (Win32Com.ClearCommError(hPort, out errs, IntPtr.Zero))
						{
							StringBuilder s = new StringBuilder("UART Error: ", 40);
							if ((errs & Win32Com.CE_FRAME) != 0) s = s.Append("Framing,");
							if ((errs & Win32Com.CE_IOE) != 0) s = s.Append("IO,");
							if ((errs & Win32Com.CE_OVERRUN) != 0) s = s.Append("Overrun,");
							if ((errs & Win32Com.CE_RXOVER) != 0) s = s.Append("Receive Cverflow,");
							if ((errs & Win32Com.CE_RXPARITY) != 0) s = s.Append("Parity,");
							if ((errs & Win32Com.CE_TXFULL) != 0) s = s.Append("Transmit Overflow,");
							s.Length = s.Length - 1;
							throw new CommPortException(s.ToString());
						}
						else
						{
							throw new CommPortException("IO Error [003]");
						}
					}
					if ((eventMask & Win32Com.EV_RXCHAR) != 0) 
					{
						do 
						{
							gotbytes = 0;
							if (!Win32Com.ReadFile(hPort, buf, 1, out gotbytes, unmanagedOv)) 
							{
								if (Marshal.GetLastWin32Error() == Win32Com.ERROR_IO_PENDING) 
								{
									Win32Com.CancelIo(hPort);
									gotbytes = 0;
								}
								else
								{
									throw new CommPortException("IO Error [004]");
								}
							}
							if (gotbytes == 1) OnRxChar(buf[0]);
						} while (gotbytes > 0);
					}
					if ((eventMask & Win32Com.EV_TXEMPTY) != 0)
					{
						OnTxDone();
					}
					if ((eventMask & Win32Com.EV_BREAK) != 0) OnBreak();
			
					uint i = 0;
					if ((eventMask & Win32Com.EV_CTS) != 0) i |= Win32Com.MS_CTS_ON;
					if ((eventMask & Win32Com.EV_DSR) != 0) i |= Win32Com.MS_DSR_ON;
					if ((eventMask & Win32Com.EV_RLSD) != 0) i |= Win32Com.MS_RLSD_ON;
					if ((eventMask & Win32Com.EV_RING) != 0) i |= Win32Com.MS_RING_ON;
					if (i != 0)
					{
						uint f;
						if (!Win32Com.GetCommModemStatus(hPort, out f)) throw new CommPortException("IO Error [005]");
						OnStatusChange(new ModemStatus(i), new ModemStatus(f));
					}
				}
			}
			catch (Exception e)
			{
				if (uMask != IntPtr.Zero) Marshal.FreeHGlobal(uMask);
				if (unmanagedOv != IntPtr.Zero) Marshal.FreeHGlobal(unmanagedOv);
				if (!(e is ThreadAbortException))
				{
					rxException = e;
					OnRxException(e);
				}
			}
		}

		private bool CheckOnline()
		{
			uint f;
			if ((rxException != null) && (!rxExceptionReported))
			{
				rxExceptionReported = true;
				ThrowException("rx");
			}
			if (online) 
			{
				if (Win32Com.GetHandleInformation(hPort, out f)) return true;
				ThrowException("Offline");
				return false;
			}
			else
			{
				if (auto) 
				{
					if (Open()) return true;
				}
				ThrowException("Offline");
				return false;
			}
		}

	}

	/// <summary>
	/// Overlays CommBase to provide line or packet oriented communications to derived classes. ASCII strings
	/// are sent and received and the Transact method is added which transmits a string and then blocks until
	/// a reply string has been received (subject to a timeout).
	/// </summary>
	public abstract class CommLine : CommBase {
		private byte[] RxBuffer;
		private uint RxBufferP = 0;
		private ASCII RxTerm;
		private ASCII[] TxTerm;
		private ASCII[] RxFilter;
		private string RxString = "";
		private ManualResetEvent TransFlag = new ManualResetEvent(true);
		private uint TransTimeout;

		/// <summary>
		/// Extends CommBaseSettings to add the settings used by CommLine.
		/// </summary>
		public class CommLineSettings : CommBase.CommBaseSettings 
		{
			/// <summary>
			/// Maximum size of received string (default: 256)
			/// </summary>
			public int rxStringBufferSize = 256;
			/// <summary>
			/// ASCII code that terminates a received string (default: CR)
			/// </summary>
			public ASCII rxTerminator = ASCII.CR;
			/// <summary>
			/// ASCII codes that will be ignored in received string (default: null)
			/// </summary>
			public ASCII[] rxFilter;
			/// <summary>
			/// Maximum time (ms) for the Transact method to complete (default: 500)
			/// </summary>
			public int transactTimeout = 500;
			/// <summary>
			/// ASCII codes transmitted after each Send string (default: null)
			/// </summary>
			public ASCII[] txTerminator;

			public static new CommLineSettings LoadFromXML(Stream s)
			{
				return (CommLineSettings)LoadFromXML(s, typeof(CommLineSettings));
			}
		}
	
		/// <summary>
		/// Queue the ASCII representation of a string and then the set terminator bytes for sending.
		/// </summary>
		/// <param name="toSend">String to be sent.</param>
		protected void Send(string toSend) 
		{
			ASCIIEncoding enc = new ASCIIEncoding();
			uint l = (uint)enc.GetByteCount(toSend);
			if (TxTerm != null) l += (uint)TxTerm.GetLength(0);
			byte[] b = new byte[l];
			byte[] s = enc.GetBytes(toSend);
			int i;
			for (i = 0; (i <= s.GetUpperBound(0)); i++) b[i] = s[i];
			if (TxTerm != null) for (int j = 0; (j <= TxTerm.GetUpperBound(0)); j++, i++) b[i] = (byte)TxTerm[j];
			Send(b);
		}

		/// <summary>
		/// Transmits the ASCII representation of a string followed by the set terminator bytes and then
		/// awaits a response string.
		/// </summary>
		/// <param name="toSend">The string to be sent.</param>
		/// <returns>The response string.</returns>
		protected string Transact(string toSend) {
			Send(toSend);
			TransFlag.Reset();
			if (!TransFlag.WaitOne((int)TransTimeout, false)) ThrowException("Timeout");
			string s;
			lock(RxString) {s = RxString;}
			return s;
		}
		
		/// <summary>
		/// If a derived class overrides ComSettings(), it must call this prior to returning the settings to
		/// the base class.
		/// </summary>
		/// <param name="s">Class containing the appropriate settings.</param>
		protected void Setup(CommLineSettings s) {
			RxBuffer = new byte[s.rxStringBufferSize];
			RxTerm = s.rxTerminator;
			RxFilter = s.rxFilter;
			TransTimeout = (uint)s.transactTimeout;
			TxTerm = s.txTerminator;
		}

		/// <summary>
		/// Override this to process unsolicited input lines (not a result of Transact).
		/// </summary>
		/// <param name="s">String containing the received ASCII text.</param>
		protected virtual void OnRxLine(string s) {}

		protected override void OnRxChar(byte ch) {
			ASCII ca = (ASCII)ch;
			if ((ca == RxTerm) || (RxBufferP > RxBuffer.GetUpperBound(0))) {
				ASCIIEncoding enc = new ASCIIEncoding();
				lock(RxString) {RxString = enc.GetString(RxBuffer, 0, (int)RxBufferP);}
				RxBufferP = 0;
				if (TransFlag.WaitOne(0,false)) {
					OnRxLine(RxString);
				} else {
					TransFlag.Set();
				}
			} else {
				bool wr = true;
				if (RxFilter != null) {
					for (int i=0; i <= RxFilter.GetUpperBound(0); i++) if (RxFilter[i] == ca) wr = false;
				}
				if (wr) {
					RxBuffer[RxBufferP] = ch;
					RxBufferP++;
				}
			}
		}
	}

	/// <summary>
	/// Exception used for all errors.
	/// </summary>
	public class CommPortException : ApplicationException
	{
		/// <summary>
		/// Constructor for raising direct exceptions
		/// </summary>
		/// <param name="desc">Description of error</param>
		public CommPortException(string desc) : base(desc) {}

		/// <summary>
		/// Constructor for re-raising exceptions from receive thread
		/// </summary>
		/// <param name="e">Inner exception raised on receive thread</param>
		public CommPortException(Exception e) : base("Receive Thread Exception", e) {}
	}

	public class Win32Com {

		/// <summary>
		/// Opening Testing and Closing the Port Handle.
		/// </summary>
		[DllImport("kernel32.dll", SetLastError=true)]
		public static extern IntPtr CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode,
			IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes,
			IntPtr hTemplateFile);

		//Constants for errors:
			public const UInt32 ERROR_FILE_NOT_FOUND = 2;
			public const UInt32 ERROR_INVALID_NAME = 123;
			public const UInt32 ERROR_ACCESS_DENIED = 5;
			public const UInt32 ERROR_IO_PENDING = 997;

		//Constants for return value:
			public const Int32 INVALID_HANDLE_VALUE = -1;

		//Constants for dwFlagsAndAttributes:
			public const UInt32 FILE_FLAG_OVERLAPPED = 0x40000000;

⌨️ 快捷键说明

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