diff --git a/CommBase2.cs b/CommBase2.cs new file mode 100644 index 0000000..a8e7be5 --- /dev/null +++ b/CommBase2.cs @@ -0,0 +1,1517 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Collections.Concurrent; + +//JH 1.1: Version 1.1 changes labelled thus. +//JH 1.2: Version 1.2 changes labelled thus. +//JH 1.3: Version 1.3 changes labelled thus. + +namespace JHCommBase +{ + + /// + /// Lowest level Com driver handling all Win32 API calls and processing send and receive in terms of + /// individual bytes. Used as a base class for higher level drivers. + /// + public class CommBase : IDisposable + { + private IntPtr hPort; + private IntPtr ptrUWO = IntPtr.Zero; + private Thread rxThread = null; + private bool online = false; + private bool auto = false; + private bool checkSends = true; + private Exception rxException = null; + private bool rxExceptionReported = false; + private int writeCount = 0; + private ManualResetEvent writeEvent = new ManualResetEvent(false); + //JH 1.2: Added below to improve robustness of thread start-up. + private ManualResetEvent startEvent = new ManualResetEvent(false); + private int stateRTS = 2; + private int stateDTR = 2; + private int stateBRK = 2; + //JH 1.3: Added to support the new congestion detection scheme (following two lines): + private bool[] empty = new bool[1]; + private bool dataQueued = false; + + private ConcurrentQueue Que = null; + + public delegate void OnSend(); + public static OnSend onTx; + public delegate void OnRecv(byte ch); + public static OnRecv onRx; + public delegate void OnRecvPack(Byte[] arr); + public static OnRecvPack onRxPack; + + public CommBase(String port, int bitrate, Parity parity = Parity.none, StopBits stopbits = StopBits.one, int databits = 8) + { + CommSet.port = port; + CommSet.baudRate = bitrate; + CommSet.parity = parity; + CommSet.dataBits = databits; + CommSet.stopBits = stopbits; + CommSet.autoReopen = true; + } + + /// + /// Parity settings + /// + public enum Parity + { + /// + /// Characters do not have a parity bit. + /// + none = 0, + /// + /// If there are an odd number of 1s in the data bits, the parity bit is 1. + /// + odd = 1, + /// + /// If there are an even number of 1s in the data bits, the parity bit is 1. + /// + even = 2, + /// + /// The parity bit is always 1. + /// + mark = 3, + /// + /// The parity bit is always 0. + /// + space = 4 + }; + + /// + /// Stop bit settings + /// + public enum StopBits + { + /// + /// Line is asserted for 1 bit duration at end of each character + /// + one = 0, + /// + /// Line is asserted for 1.5 bit duration at end of each character + /// + onePointFive = 1, + /// + /// Line is asserted for 2 bit duration at end of each character + /// + two = 2 + }; + + /// + /// Uses for RTS or DTR pins + /// + public enum HSOutput + { + /// + /// Pin is asserted when this station is able to receive data. + /// + handshake = 2, + /// + /// Pin is asserted when this station is transmitting data (RTS on NT, 2000 or XP only). + /// + gate = 3, + /// + /// Pin is asserted when this station is online (port is open). + /// + online = 1, + /// + /// Pin is never asserted. + /// + none = 0 + }; + + /// + /// Standard handshake methods + /// + public enum Handshake + { + /// + /// No handshaking + /// + none, + /// + /// Software handshaking using Xon / Xoff + /// + XonXoff, + /// + /// Hardware handshaking using CTS / RTS + /// + CtsRts, + /// + /// Hardware handshaking using DSR / DTR + /// + DsrDtr + } + + /// + /// Set the public fields to supply settings to CommBase. + /// + private static class CommSet + { + /// + /// Port Name (default: "COM1:") + /// + public static string port = "COM1:"; + /// + /// Baud Rate (default: 2400) unsupported rates will throw "Bad settings" + /// + public static int baudRate = 2400; + /// + /// The parity checking scheme (default: none) + /// + public static Parity parity = Parity.none; + /// + /// Number of databits 1..8 (default: 8) unsupported values will throw "Bad settings" + /// + public static int dataBits = 8; + /// + /// Number of stop bits (default: one) + /// + public static StopBits stopBits = StopBits.one; + /// + /// If true, transmission is halted unless CTS is asserted by the remote station (default: false) + /// + public static bool txFlowCTS = false; + /// + /// If true, transmission is halted unless DSR is asserted by the remote station (default: false) + /// + public static bool txFlowDSR = false; + /// + /// If true, transmission is halted when Xoff is received and restarted when Xon is received (default: false) + /// + public static bool txFlowX = false; + /// + /// If false, transmission is suspended when this station has sent Xoff to the remote station (default: true) + /// Set false if the remote station treats any character as an Xon. + /// + public static bool txWhenRxXoff = true; + /// + /// If true, received characters are ignored unless DSR is asserted by the remote station (default: false) + /// + public static bool rxGateDSR = false; + /// + /// If true, Xon and Xoff characters are sent to control the data flow from the remote station (default: false) + /// + public static bool rxFlowX = false; + /// + /// Specifies the use to which the RTS output is put (default: none) + /// + public static HSOutput useRTS = HSOutput.none; + /// + /// Specidies the use to which the DTR output is put (default: none) + /// + public static HSOutput useDTR = HSOutput.none; + /// + /// The character used to signal Xon for X flow control (default: DC1) + /// + public static ASCII XonChar = ASCII.DC1; + /// + /// The character used to signal Xoff for X flow control (default: DC3) + /// + public static ASCII XoffChar = ASCII.DC3; + //JH 1.2: Next two defaults changed to 0 to use new defaulting mechanism dependant on queue size. + /// + /// The number of free bytes in the reception queue at which flow is disabled + /// (Default: 0 = Set to 1/10th of actual rxQueue size) + /// + public static int rxHighWater = 0; + /// + /// The number of bytes in the reception queue at which flow is re-enabled + /// (Default: 0 = Set to 1/10th of actual rxQueue size) + /// + public static int rxLowWater = 0; + /// + /// Multiplier. Max time for Send in ms = (Multiplier * Characters) + Constant + /// (default: 0 = No timeout) + /// + public static uint sendTimeoutMultiplier = 0; + /// + /// Constant. Max time for Send in ms = (Multiplier * Characters) + Constant (default: 0) + /// + public static uint sendTimeoutConstant = 0; + /// + /// Requested size for receive queue (default: 0 = use operating system default) + /// + public static int rxQueue = 0; + /// + /// Requested size for transmit queue (default: 0 = use operating system default) + /// + public static int txQueue = 0; + /// + /// If true, the port will automatically re-open on next send if it was previously closed due + /// to an error (default: false) + /// + public static bool autoReopen = false; + + /// + /// If true, subsequent Send commands wait for completion of earlier ones enabling the results + /// to be checked. If false, errors, including timeouts, may not be detected, but performance + /// may be better. + /// + public static bool checkAllSends = true; + + /// + /// Pre-configures settings for most modern devices: 8 databits, 1 stop bit, no parity and + /// one of the common handshake protocols. Change individual settings later if necessary. + /// + /// The port to use (i.e. "COM1:") + /// The baud rate + /// The handshake protocol + public static void SetStandard(string Port, int Baud, Handshake Hs) + { + dataBits = 8; stopBits = StopBits.one; parity = Parity.none; + port = Port; baudRate = Baud; + switch (Hs) + { + case Handshake.none: + txFlowCTS = false; txFlowDSR = false; txFlowX = false; + rxFlowX = false; useRTS = HSOutput.online; useDTR = HSOutput.online; + txWhenRxXoff = true; rxGateDSR = false; + break; + case Handshake.XonXoff: + txFlowCTS = false; txFlowDSR = false; txFlowX = true; + rxFlowX = true; useRTS = HSOutput.online; useDTR = HSOutput.online; + txWhenRxXoff = true; rxGateDSR = false; + XonChar = ASCII.DC1; XoffChar = ASCII.DC3; + break; + case Handshake.CtsRts: + txFlowCTS = true; txFlowDSR = false; txFlowX = false; + rxFlowX = false; useRTS = HSOutput.handshake; useDTR = HSOutput.online; + txWhenRxXoff = true; rxGateDSR = false; + break; + case Handshake.DsrDtr: + txFlowCTS = false; txFlowDSR = true; txFlowX = false; + rxFlowX = false; useRTS = HSOutput.online; useDTR = HSOutput.handshake; + txWhenRxXoff = true; rxGateDSR = false; + break; + } + } + } + + //JH 1.3: Corrected STH -> STX (Thanks - Johan Thelin!) + /// + /// Byte type with enumeration constants for ASCII control codes. + /// + public enum ASCII : byte + { + NULL = 0x00,SOH = 0x01,STX = 0x02,ETX = 0x03,EOT = 0x04,ENQ = 0x05,ACK = 0x06,BELL = 0x07, + BS = 0x08,HT = 0x09,LF = 0x0A,VT = 0x0B,FF = 0x0C,CR = 0x0D,SO = 0x0E,SI = 0x0F,DC1 = 0x11, + DC2 = 0x12,DC3 = 0x13,DC4 = 0x14,NAK = 0x15,SYN = 0x16,ETB = 0x17,CAN = 0x18,EM = 0x19, + SUB = 0x1A,ESC = 0x1B,FS = 0x1C,GS = 0x1D,RS = 0x1E,US = 0x1F,SP = 0x20,DEL = 0x7F + } + + + //JH 1.3: Added AltName function, PortStatus enum and IsPortAvailable function. + + /// + /// Returns the alternative name of a com port i.e. \\.\COM1 for COM1: + /// Some systems require this form for double or more digit com port numbers. + /// + /// Name in form COM1 or COM1: + /// Name in form \\.\COM1 + private string AltName(string s) + { + string r = s.Trim(); + if (s.EndsWith(":")) s = s.Substring(0, s.Length - 1); + if (s.StartsWith(@"\")) return s; + return @"\\.\" + s; + } + + /// + /// Availability status of a port + /// + public enum PortStatus + { + /// + /// Port exists but is unavailable (may be open to another program) + /// + unavailable = 0, + /// + /// Available for use + /// + available = 1, + /// + /// Port does not exist + /// + absent = -1 + } + + /// + /// Tests the availability of a named comm port. + /// + /// Name of port + /// Availability of port + public PortStatus IsPortAvailable(string s) + { + IntPtr h; + + h = Win32Com.CreateFile(s, Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero, + Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero); + if (h == (IntPtr)Win32Com.INVALID_HANDLE_VALUE) + { + if (Marshal.GetLastWin32Error() == Win32Com.ERROR_ACCESS_DENIED) + { + return PortStatus.unavailable; + } + else + { + //JH 1.3: Automatically try AltName if supplied name fails: + h = Win32Com.CreateFile(AltName(s), Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero, + Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero); + if (h == (IntPtr)Win32Com.INVALID_HANDLE_VALUE) + { + if (Marshal.GetLastWin32Error() == Win32Com.ERROR_ACCESS_DENIED) + { + return PortStatus.unavailable; + } + else + { + return PortStatus.absent; + } + } + } + } + Win32Com.CloseHandle(h); + return PortStatus.available; + } + + /// + /// Opens the com port and configures it with the required settings + /// + /// false if the port could not be opened + public bool Open() + { + Win32Com.DCB PortDCB = new Win32Com.DCB(); + Win32Com.COMMTIMEOUTS CommTimeouts = new Win32Com.COMMTIMEOUTS(); + Win32Com.OVERLAPPED wo = new Win32Com.OVERLAPPED(); + Win32Com.COMMPROP cp; + Que = new ConcurrentQueue(); + + if (online) return false; + + hPort = Win32Com.CreateFile(CommSet.port, Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero, + Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero); + if (hPort == (IntPtr)Win32Com.INVALID_HANDLE_VALUE) + { + if (Marshal.GetLastWin32Error() == Win32Com.ERROR_ACCESS_DENIED) + { + return false; + } + else + { + //JH 1.3: Try alternative name form if main one fails: + hPort = Win32Com.CreateFile(AltName(CommSet.port), Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero, + Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero); + if (hPort == (IntPtr)Win32Com.INVALID_HANDLE_VALUE) + { + if (Marshal.GetLastWin32Error() == Win32Com.ERROR_ACCESS_DENIED) + { + return false; + } + else + { + throw new CommPortException("Port Open Failure"); + } + } + } + } + + online = true; + + //JH1.1: Changed from 0 to "magic number" to give instant return on ReadFile: + CommTimeouts.ReadIntervalTimeout = Win32Com.MAXDWORD; + CommTimeouts.ReadTotalTimeoutConstant = 0; + CommTimeouts.ReadTotalTimeoutMultiplier = 0; + + //JH1.2: 0 does not seem to mean infinite on non-NT platforms, so default it to 10 + //seconds per byte which should be enough for anyone. + if (CommSet.sendTimeoutMultiplier == 0) + { + if (System.Environment.OSVersion.Platform == System.PlatformID.Win32NT) + { + CommTimeouts.WriteTotalTimeoutMultiplier = 0; + } + else + { + CommTimeouts.WriteTotalTimeoutMultiplier = 10000; + } + } + else + { + CommTimeouts.WriteTotalTimeoutMultiplier = CommSet.sendTimeoutMultiplier; + } + CommTimeouts.WriteTotalTimeoutConstant = CommSet.sendTimeoutConstant; + + PortDCB.init(((CommSet.parity == Parity.odd) || (CommSet.parity == Parity.even)), CommSet.txFlowCTS, CommSet.txFlowDSR, + (int)CommSet.useDTR, CommSet.rxGateDSR, !CommSet.txWhenRxXoff, CommSet.txFlowX, CommSet.rxFlowX, (int)CommSet.useRTS); + PortDCB.BaudRate = CommSet.baudRate; + PortDCB.ByteSize = (byte)CommSet.dataBits; + PortDCB.Parity = (byte)CommSet.parity; + PortDCB.StopBits = (byte)CommSet.stopBits; + PortDCB.XoffChar = (byte)CommSet.XoffChar; + PortDCB.XonChar = (byte)CommSet.XonChar; + if ((CommSet.rxQueue != 0) || (CommSet.txQueue != 0)) + if (!Win32Com.SetupComm(hPort, (uint)CommSet.rxQueue, (uint)CommSet.txQueue)) ThrowException("Bad queue settings"); + + //JH 1.2: Defaulting mechanism for handshake thresholds - prevents problems of setting specific + //defaults which may violate the size of the actually granted queue. If the user specifically sets + //these values, it's their problem! + if ((CommSet.rxLowWater == 0) || (CommSet.rxHighWater == 0)) + { + if (!Win32Com.GetCommProperties(hPort, out cp)) cp.dwCurrentRxQueue = 0; + if (cp.dwCurrentRxQueue > 0) + { + //If we can determine the queue size, default to 1/10th, 8/10ths, 1/10th. + //Note that HighWater is measured from top of queue. + PortDCB.XoffLim = PortDCB.XonLim = (short)((int)cp.dwCurrentRxQueue / 10); + } + else + { + //If we do not know the queue size, set very low defaults for safety. + PortDCB.XoffLim = PortDCB.XonLim = 8; + } + } + else + { + PortDCB.XoffLim = (short)CommSet.rxHighWater; + PortDCB.XonLim = (short)CommSet.rxLowWater; + } + + if (!Win32Com.SetCommState(hPort, ref PortDCB)) ThrowException("Bad com settings"); + if (!Win32Com.SetCommTimeouts(hPort, ref CommTimeouts)) ThrowException("Bad timeout settings"); + + stateBRK = 0; + if (CommSet.useDTR == HSOutput.none) stateDTR = 0; + if (CommSet.useDTR == HSOutput.online) stateDTR = 1; + if (CommSet.useRTS == HSOutput.none) stateRTS = 0; + if (CommSet.useRTS == HSOutput.online) stateRTS = 1; + + checkSends = CommSet.checkAllSends; + wo.Offset = 0; + wo.OffsetHigh = 0; + if (checkSends) + wo.hEvent = writeEvent.Handle; + else + wo.hEvent = IntPtr.Zero; + + ptrUWO = Marshal.AllocHGlobal(Marshal.SizeOf(wo)); + + Marshal.StructureToPtr(wo, ptrUWO, true); + writeCount = 0; + //JH1.3: + empty[0] = true; + dataQueued = false; + + rxException = null; + rxExceptionReported = false; + rxThread = new Thread(new ThreadStart(this.ReceiveThread)); + rxThread.Name = "CommBaseRx"; + rxThread.Priority = ThreadPriority.AboveNormal; + rxThread.Start(); + + //JH1.2: More robust thread start-up wait. + startEvent.WaitOne(500, false); + + auto = false; + if (AfterOpen()) + { + auto = CommSet.autoReopen; + return true; + } + else + { + Close(); + return false; + } + + } + + /// + /// Closes the com port. + /// + public void Close() + { + if (online) + { + auto = false; + BeforeClose(false); + InternalClose(); + rxException = null; + } + } + + private void InternalClose() + { + Win32Com.CancelIo(hPort); + if (rxThread != null) + { + rxThread.Abort(); + //JH 1.3: Improve robustness of Close in case were followed by Open: + rxThread.Join(100); + rxThread = null; + } + Win32Com.CloseHandle(hPort); + if (ptrUWO != IntPtr.Zero) Marshal.FreeHGlobal(ptrUWO); + stateRTS = 2; + stateDTR = 2; + stateBRK = 2; + online = false; + } + + /// + /// For IDisposable + /// + public void Dispose() {Close();} + + /// + /// Destructor (just in case) + /// + ~CommBase() {Close();} + + /// + /// True if online. + /// + public bool Online {get {if (!online) return false; else return CheckOnline();}} + + /// + /// Block until all bytes in the queue have been transmitted. + /// + public void Flush() { + CheckOnline(); + CheckResult(); + } + + /// + /// Use this to throw exceptions in derived classes. Correctly handles threading issues + /// and closes the port if necessary. + /// + /// Description of fault + protected void ThrowException(string reason) + { + if (Thread.CurrentThread == rxThread) + { + throw new CommPortException(reason); + } + else + { + if (online) + { + BeforeClose(true); + InternalClose(); + } + if (rxException == null) + { + throw new CommPortException(reason); + } + else + { + throw new CommPortException(rxException); + } + } + } + + /// + /// Queues bytes for transmission. + /// + /// Array of bytes to be sent + public void Send(byte[] tosend) { + uint sent = 0; + CheckOnline(); + CheckResult(); + writeCount = tosend.GetLength(0); + if (Win32Com.WriteFile(hPort, tosend, (uint)writeCount, out sent, ptrUWO)) + { + writeCount -= (int)sent; + OnTxDone(); + } + else + { + if (Marshal.GetLastWin32Error() != Win32Com.ERROR_IO_PENDING) ThrowException("Send failed"); + //JH1.3: + dataQueued = true; + } + } + + /// + /// Queues a single byte for transmission. + /// + /// Byte to be sent + public void Send(byte tosend) + { + byte[] b = new byte[1]; + b[0] = tosend; + Send(b); + } + + private void CheckResult() + { + uint sent = 0; + + //JH 1.3: Fixed a number of problems working with checkSends == false. Byte counting was unreliable because + //occasionally GetOverlappedResult would return true with a completion having missed one or more previous + //completions. The test for ERROR_IO_INCOMPLETE was incorrectly for ERROR_IO_PENDING instead. + + if (writeCount > 0) + { + if (Win32Com.GetOverlappedResult(hPort, ptrUWO, out sent, checkSends)) + { + if (checkSends) + { + writeCount -= (int)sent; + if (writeCount != 0) ThrowException("Send Timeout"); + writeCount = 0; + } + } + else + { + if (Marshal.GetLastWin32Error() != Win32Com.ERROR_IO_INCOMPLETE) ThrowException("Write Error"); + } + } + } + + /// + /// Sends a protocol byte immediately ahead of any queued bytes. + /// + /// Byte to send + public void SendImmediate(byte tosend) { + CheckOnline(); + if (!Win32Com.TransmitCommChar(hPort, tosend)) + ThrowException("Transmission failure"); + else + OnTxDone(); + } + + /// + /// Delay processing. + /// + /// Milliseconds to delay by + protected void Sleep(int milliseconds) + { + Thread.Sleep(milliseconds); + } + + /// + /// Represents the status of the modem control input signals. + /// + public struct ModemStatus + { + private uint status; + internal ModemStatus(uint val) {status = val;} + /// + /// Condition of the Clear To Send signal. + /// + public bool cts {get{return ((status & Win32Com.MS_CTS_ON) != 0);}} + /// + /// Condition of the Data Set Ready signal. + /// + public bool dsr {get{return ((status & Win32Com.MS_DSR_ON) != 0);}} + /// + /// Condition of the Receive Line Status Detection signal. + /// + public bool rlsd {get{return ((status & Win32Com.MS_RLSD_ON) != 0);}} + /// + /// Condition of the Ring Detection signal. + /// + public bool ring {get{return ((status & Win32Com.MS_RING_ON) != 0);}} + } + + /// + /// Gets the status of the modem control input signals. + /// + /// Modem status object + protected ModemStatus GetModemStatus() { + uint f; + + CheckOnline(); + if (!Win32Com.GetCommModemStatus(hPort, out f)) ThrowException("Unexpected failure"); + return new ModemStatus(f); + } + + /// + /// Represents the current condition of the port queues. + /// + public struct QueueStatus + { + private uint status; + private uint inQueue; + private uint outQueue; + private uint inQueueSize; + private uint outQueueSize; + + internal QueueStatus(uint stat, uint inQ, uint outQ, uint inQs, uint outQs) + {status = stat; inQueue = inQ; outQueue = outQ; inQueueSize = inQs; outQueueSize = outQs;} + /// + /// Output is blocked by CTS handshaking. + /// + public bool ctsHold {get{return ((status & Win32Com.COMSTAT.fCtsHold) != 0);}} + /// + /// Output is blocked by DRS handshaking. + /// + public bool dsrHold {get{return ((status & Win32Com.COMSTAT.fDsrHold) != 0);}} + /// + /// Output is blocked by RLSD handshaking. + /// + public bool rlsdHold {get{return ((status & Win32Com.COMSTAT.fRlsdHold) != 0);}} + /// + /// Output is blocked because software handshaking is enabled and XOFF was received. + /// + public bool xoffHold {get{return ((status & Win32Com.COMSTAT.fXoffHold) != 0);}} + /// + /// Output was blocked because XOFF was sent and this station is not yet ready to receive. + /// + public bool xoffSent {get{return ((status & Win32Com.COMSTAT.fXoffSent) != 0);}} + + /// + /// There is a character waiting for transmission in the immediate buffer. + /// + public bool immediateWaiting {get{return ((status & Win32Com.COMSTAT.fTxim) != 0);}} + + /// + /// Number of bytes waiting in the input queue. + /// + public long InQueue {get{return (long)inQueue;}} + /// + /// Number of bytes waiting for transmission. + /// + public long OutQueue {get{return (long)outQueue;}} + /// + /// Total size of input queue (0 means information unavailable) + /// + public long InQueueSize {get{return (long)inQueueSize;}} + /// + /// Total size of output queue (0 means information unavailable) + /// + public long OutQueueSize {get{return (long)outQueueSize;}} + + public override string ToString() + { + StringBuilder m = new StringBuilder("The reception queue is ", 60); + if (inQueueSize == 0) + { + m.Append("of unknown size and "); + } + else + { + m.Append(inQueueSize.ToString() + " bytes long and "); + } + if (inQueue == 0) + { + m.Append("is empty."); + } + else if (inQueue == 1) + { + m.Append("contains 1 byte."); + } + else + { + m.Append("contains "); + m.Append(inQueue.ToString()); + m.Append(" bytes."); + } + m.Append(" The transmission queue is "); + if (outQueueSize == 0) + { + m.Append("of unknown size and "); + } + else + { + m.Append(outQueueSize.ToString() + " bytes long and "); + } + if (outQueue == 0) + { + m.Append("is empty"); + } + else if (outQueue == 1) + { + m.Append("contains 1 byte. It is "); + } + else + { + m.Append("contains "); + m.Append(outQueue.ToString()); + m.Append(" bytes. It is "); + } + if (outQueue > 0) + { + if (ctsHold || dsrHold || rlsdHold || xoffHold || xoffSent) + { + m.Append("holding on"); + if (ctsHold) m.Append(" CTS"); + if (dsrHold) m.Append(" DSR"); + if (rlsdHold) m.Append(" RLSD"); + if (xoffHold) m.Append(" Rx XOff"); + if (xoffSent) m.Append(" Tx XOff"); + } + else + { + m.Append("pumping data"); + } + } + m.Append(". The immediate buffer is "); + if (immediateWaiting) + m.Append("full."); + else + m.Append("empty."); + return m.ToString(); + } + } + + /// + /// Get the status of the queues + /// + /// Queue status object + protected QueueStatus GetQueueStatus() + { + Win32Com.COMSTAT cs; + Win32Com.COMMPROP cp; + uint er; + + CheckOnline(); + if (!Win32Com.ClearCommError(hPort, out er, out cs)) ThrowException("Unexpected failure"); + if (!Win32Com.GetCommProperties(hPort, out cp)) ThrowException("Unexpected failure"); + return new QueueStatus(cs.Flags, cs.cbInQue, cs.cbOutQue, cp.dwCurrentRxQueue, cp.dwCurrentTxQueue); + } + + // JH 1.3. Added for this version. + /// + /// Test if the line is congested (data being queued for send faster than it is being dequeued) + /// This detects if baud rate is too slow or if handshaking is not allowing enough transmission + /// time. It should be called at reasonably long fixed intervals. If data has been sent during + /// the interval, congestion is reported if the queue was never empty during the interval. + /// + /// True if congested + protected bool IsCongested() + { + bool e; + if (!dataQueued) return false; + lock(empty) {e = empty[0]; empty[0] = false;} + dataQueued = false; + return !e; + } + + /// + /// True if the RTS pin is controllable via the RTS property + /// + protected bool RTSavailable { get { return (stateRTS < 2);}} + + /// + /// Set the state of the RTS modem control output + /// + protected bool RTS + { + set { + if (stateRTS > 1) return; + CheckOnline(); + if (value) + { + if (Win32Com.EscapeCommFunction(hPort, Win32Com.SETRTS)) + stateRTS = 1; + else + ThrowException("Unexpected Failure"); + } + else + { + if (Win32Com.EscapeCommFunction(hPort, Win32Com.CLRRTS)) + //JH 1.3: Was 1, should be 0: + stateRTS = 0; + else + ThrowException("Unexpected Failure"); + } + } + get { + return (stateRTS == 1); + } + } + + /// + /// True if the DTR pin is controllable via the DTR property + /// + protected bool DTRavailable { get { return (stateDTR < 2);}} + + /// + /// The state of the DTR modem control output + /// + protected bool DTR { + set { + if (stateDTR > 1) return; + CheckOnline(); + if (value) + { + if (Win32Com.EscapeCommFunction(hPort, Win32Com.SETDTR)) + stateDTR = 1; + else + ThrowException("Unexpected Failure"); + } + else + { + if (Win32Com.EscapeCommFunction(hPort, Win32Com.CLRDTR)) + stateDTR = 0; + else + ThrowException("Unexpected Failure"); + } + } + get { + return (stateDTR == 1); + } + } + + /// + /// Assert or remove a break condition from the transmission line + /// + 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); + } + } + + /// + /// Override this to provide settings. (NB this is called during Open method) + /// + /// CommSet, or derived object with required settings initialised + + /// + /// Override this to provide processing after the port is openned (i.e. to configure remote + /// device or just check presence). + /// + /// false to close the port again + protected virtual bool AfterOpen() {return true;} + + /// + /// Override this to provide processing prior to port closure. + /// + /// True if closing due to an error + protected virtual void BeforeClose(bool error) {} + + /// + /// Override this to process received bytes. + /// + /// The byte that was received + public virtual void OnRxChar(byte ch) + { + if (onRx != null) + onRx(ch); + } + + /// + /// Override this to take action when transmission is complete (i.e. all bytes have actually + /// been sent, not just queued). + /// + private void OnTxDone() + { + if (onTx != null) + onTx(); + } + + /// + /// Override this to take action when a break condition is detected on the input line. + /// + private void OnBreak() + { + if (Que.Count != 0) + { +// Console.Write($"OnBreak break que={Que.Count} "); + Byte[] bb = new Byte[Que.Count]; + int i = 0; + while (Que.Count > 0) + { + Byte b = 0; + Que.TryDequeue(out b); + bb[i++] = b; + } + //bb.ToList().ForEach(b => Console.Write($"0x{b:X2} ")); + // Console.WriteLine(); + if (onRxPack != null) + onRxPack(bb); + } + } + + //JH 1.3: Deleted OnRing() which was never called: use OnStatusChange instead (Thanks Jim Foster) + + /// + /// Override this to take action when one or more modem status inputs change state + /// + /// The status inputs that have changed state + /// The state of the status inputs + protected virtual void OnStatusChange(ModemStatus mask, ModemStatus state) {} + + /// + /// Override this to take action when the reception thread closes due to an exception being thrown. + /// + /// The exception which was thrown + protected virtual void OnRxException(Exception e) {} + + private void ReceiveThread() + { + byte[] buf = new Byte[1]; + uint gotbytes; + bool starting; + + starting = true; + AutoResetEvent sg = new AutoResetEvent(false); + Win32Com.OVERLAPPED ov = new Win32Com.OVERLAPPED(); + + IntPtr unmanagedOv; + IntPtr uMask; + uint eventMask = 0; + unmanagedOv = Marshal.AllocHGlobal(Marshal.SizeOf(ov)); + uMask = Marshal.AllocHGlobal(Marshal.SizeOf(eventMask)); + + ov.Offset = 0; ov.OffsetHigh = 0; + ov.hEvent = sg.Handle; + Marshal.StructureToPtr(ov, unmanagedOv, true); + + 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); + //JH 1.2: Tells the main thread that this thread is ready for action. + if (starting) + { + startEvent.Set(); + starting = false; + } + 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)) + { + //JH 1.2: BREAK condition has an error flag and and an event flag. Not sure if both + //are always raised, so if CE_BREAK is only error flag ignore it and set the EV_BREAK + //flag for normal handling. Also made more robust by handling case were no recognised + //error was present in the flags. (Thanks to Fred Pittroff for finding this problem!) + int ec = 0; + StringBuilder s = new StringBuilder("UART Error: ", 40); + if ((errs & Win32Com.CE_FRAME) != 0) + { + s = s.Append("Framing,"); ec++; + } + if ((errs & Win32Com.CE_IOE) != 0) + { + s = s.Append("IO,"); ec++; + } + if ((errs & Win32Com.CE_OVERRUN) != 0) + { + s = s.Append("Overrun,"); ec++; + } + if ((errs & Win32Com.CE_RXOVER) != 0) + { + s = s.Append("Receive Cverflow,"); ec++; + } + if ((errs & Win32Com.CE_RXPARITY) != 0) + { + s = s.Append("Parity,"); ec++; + } + if ((errs & Win32Com.CE_TXFULL) != 0) + { + s = s.Append("Transmit Overflow,"); ec++; + } + if (ec > 0) + { + s.Length = s.Length - 1; + throw new CommPortException(s.ToString()); + } + else + { + if (errs == Win32Com.CE_BREAK) + { + eventMask |= Win32Com.EV_BREAK; + } + else + { + throw new CommPortException("IO Error [003]"); + } + } + } + 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)) + { + //JH 1.1: Removed ERROR_IO_PENDING handling as comm timeouts have now + //been set so ReadFile returns immediately. This avoids use of CancelIo + //which was causing loss of data. Thanks to Daniel Moth for suggesting this + //might be a problem, and to many others for reporting that it was! + + int x = Marshal.GetLastWin32Error(); + + throw new CommPortException("IO Error [004]"); + } + if (gotbytes == 1) + { + OnRxChar(buf[0]); + Que.Enqueue(buf[0]); + } + } while (gotbytes > 0); + OnBreak(); + } + if ((eventMask & Win32Com.EV_TXEMPTY) != 0) + { + //JH1.3: + lock(empty) empty[0] = true; + 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) + { + //JH 1.3: Added for shutdown robustness (Thanks to Fred Pittroff, Mark Behner and Kevin Williamson!), . + Win32Com.CancelIo(hPort); + 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() + { + if ((rxException != null) && (!rxExceptionReported)) + { + rxExceptionReported = true; + ThrowException("rx"); + } + if (online) + { + //JH 1.1: Avoid use of GetHandleInformation for W98 compatability. + if (hPort != (System.IntPtr)Win32Com.INVALID_HANDLE_VALUE) return true; + ThrowException("Offline"); + return false; + } + else + { + if (auto) + { + if (Open()) return true; + } + ThrowException("Offline"); + return false; + } + } + + } + + + /// + /// Exception used for all errors. + /// + public class CommPortException : ApplicationException + { + /// + /// Constructor for raising direct exceptions + /// + /// Description of error + public CommPortException(string desc) : base(desc) {} + + /// + /// Constructor for re-raising exceptions from receive thread + /// + /// Inner exception raised on receive thread + public CommPortException(Exception e) : base("Receive Thread Exception", e) {} + } + + internal class Win32Com { + + /// + /// Opening Testing and Closing the Port Handle. + /// + [DllImport("kernel32.dll", SetLastError=true)] + internal static extern IntPtr CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, + IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, + IntPtr hTemplateFile); + + //Constants for errors: + internal const UInt32 ERROR_FILE_NOT_FOUND = 2; + internal const UInt32 ERROR_INVALID_NAME = 123; + internal const UInt32 ERROR_ACCESS_DENIED = 5; + internal const UInt32 ERROR_IO_PENDING = 997; + internal const UInt32 ERROR_IO_INCOMPLETE = 996; + + //Constants for return value: + internal const Int32 INVALID_HANDLE_VALUE = -1; + + //Constants for dwFlagsAndAttributes: + internal const UInt32 FILE_FLAG_OVERLAPPED = 0x40000000; + + //Constants for dwCreationDisposition: + internal const UInt32 OPEN_EXISTING = 3; + + //Constants for dwDesiredAccess: + internal const UInt32 GENERIC_READ = 0x80000000; + internal const UInt32 GENERIC_WRITE = 0x40000000; + + [DllImport("kernel32.dll")] + internal static extern Boolean CloseHandle(IntPtr hObject); + + /// + /// Manipulating the communications settings. + /// + + [DllImport("kernel32.dll")] + internal static extern Boolean GetCommState(IntPtr hFile, ref DCB lpDCB); + + [DllImport("kernel32.dll")] + internal static extern Boolean GetCommTimeouts(IntPtr hFile, out COMMTIMEOUTS lpCommTimeouts); + + [DllImport("kernel32.dll")] + internal static extern Boolean BuildCommDCBAndTimeouts(String lpDef, ref DCB lpDCB, ref COMMTIMEOUTS lpCommTimeouts); + + [DllImport("kernel32.dll")] + internal static extern Boolean SetCommState(IntPtr hFile, [In] ref DCB lpDCB); + + [DllImport("kernel32.dll")] + internal static extern Boolean SetCommTimeouts(IntPtr hFile, [In] ref COMMTIMEOUTS lpCommTimeouts); + + [DllImport("kernel32.dll")] + internal static extern Boolean SetupComm(IntPtr hFile, UInt32 dwInQueue, UInt32 dwOutQueue); + + [StructLayout( LayoutKind.Sequential )] internal struct COMMTIMEOUTS + { + //JH 1.1: Changed Int32 to UInt32 to allow setting to MAXDWORD + internal UInt32 ReadIntervalTimeout; + internal UInt32 ReadTotalTimeoutMultiplier; + internal UInt32 ReadTotalTimeoutConstant; + internal UInt32 WriteTotalTimeoutMultiplier; + internal UInt32 WriteTotalTimeoutConstant; + } + //JH 1.1: Added to enable use of "return immediately" timeout. + internal const UInt32 MAXDWORD = 0xffffffff; + + [StructLayout( LayoutKind.Sequential )] internal struct DCB + { + internal Int32 DCBlength; + internal Int32 BaudRate; + internal Int32 PackedValues; + internal Int16 wReserved; + internal Int16 XonLim; + internal Int16 XoffLim; + internal Byte ByteSize; + internal Byte Parity; + internal Byte StopBits; + internal Byte XonChar; + internal Byte XoffChar; + internal Byte ErrorChar; + internal Byte EofChar; + internal Byte EvtChar; + internal Int16 wReserved1; + + internal void init(bool parity, bool outCTS, bool outDSR, int dtr, bool inDSR, bool txc, bool xOut, + bool xIn, int rts) + { + //JH 1.3: Was 0x8001 ans so not setting fAbortOnError - Thanks Larry Delby! + DCBlength = 28; PackedValues = 0x4001; + if (parity) PackedValues |= 0x0002; + if (outCTS) PackedValues |= 0x0004; + if (outDSR) PackedValues |= 0x0008; + PackedValues |= ((dtr & 0x0003) << 4); + if (inDSR) PackedValues |= 0x0040; + if (txc) PackedValues |= 0x0080; + if (xOut) PackedValues |= 0x0100; + if (xIn) PackedValues |= 0x0200; + PackedValues |= ((rts & 0x0003) << 12); + + } + } + + /// + /// Reading and writing. + /// + [DllImport("kernel32.dll", SetLastError=true)] + internal static extern Boolean WriteFile(IntPtr fFile, Byte[] lpBuffer, UInt32 nNumberOfBytesToWrite, + out UInt32 lpNumberOfBytesWritten, IntPtr lpOverlapped); + + [StructLayout( LayoutKind.Sequential )] internal struct OVERLAPPED + { + internal UIntPtr Internal; + internal UIntPtr InternalHigh; + internal UInt32 Offset; + internal UInt32 OffsetHigh; + internal IntPtr hEvent; + } + + [DllImport("kernel32.dll")] + internal static extern Boolean SetCommMask(IntPtr hFile, UInt32 dwEvtMask); + + // Constants for dwEvtMask: + internal const UInt32 EV_RXCHAR = 0x0001; + internal const UInt32 EV_RXFLAG = 0x0002; + internal const UInt32 EV_TXEMPTY = 0x0004; + internal const UInt32 EV_CTS = 0x0008; + internal const UInt32 EV_DSR = 0x0010; + internal const UInt32 EV_RLSD = 0x0020; + internal const UInt32 EV_BREAK = 0x0040; + internal const UInt32 EV_ERR = 0x0080; + internal const UInt32 EV_RING = 0x0100; + internal const UInt32 EV_PERR = 0x0200; + internal const UInt32 EV_RX80FULL = 0x0400; + internal const UInt32 EV_EVENT1 = 0x0800; + internal const UInt32 EV_EVENT2 = 0x1000; + + [DllImport("kernel32.dll", SetLastError=true)] + internal static extern Boolean WaitCommEvent(IntPtr hFile, IntPtr lpEvtMask, IntPtr lpOverlapped); + + [DllImport("kernel32.dll")] + internal static extern Boolean CancelIo(IntPtr hFile); + + [DllImport("kernel32.dll", SetLastError=true)] + internal static extern Boolean ReadFile(IntPtr hFile, [Out] Byte[] lpBuffer, UInt32 nNumberOfBytesToRead, + out UInt32 nNumberOfBytesRead, IntPtr lpOverlapped); + + [DllImport("kernel32.dll")] + internal static extern Boolean TransmitCommChar(IntPtr hFile, Byte cChar); + + /// + /// Control port functions. + /// + [DllImport("kernel32.dll")] + internal static extern Boolean EscapeCommFunction(IntPtr hFile, UInt32 dwFunc); + + // Constants for dwFunc: + internal const UInt32 SETXOFF = 1; + internal const UInt32 SETXON = 2; + internal const UInt32 SETRTS = 3; + internal const UInt32 CLRRTS = 4; + internal const UInt32 SETDTR = 5; + internal const UInt32 CLRDTR = 6; + internal const UInt32 RESETDEV = 7; + internal const UInt32 SETBREAK = 8; + internal const UInt32 CLRBREAK = 9; + + [DllImport("kernel32.dll")] + internal static extern Boolean GetCommModemStatus(IntPtr hFile, out UInt32 lpModemStat); + + // Constants for lpModemStat: + internal const UInt32 MS_CTS_ON = 0x0010; + internal const UInt32 MS_DSR_ON = 0x0020; + internal const UInt32 MS_RING_ON = 0x0040; + internal const UInt32 MS_RLSD_ON = 0x0080; + + /// + /// Status Functions. + /// + [DllImport("kernel32.dll", SetLastError=true)] + internal static extern Boolean GetOverlappedResult(IntPtr hFile, IntPtr lpOverlapped, + out UInt32 nNumberOfBytesTransferred, Boolean bWait); + + [DllImport("kernel32.dll")] + internal static extern Boolean ClearCommError(IntPtr hFile, out UInt32 lpErrors, IntPtr lpStat); + [DllImport("kernel32.dll")] + internal static extern Boolean ClearCommError(IntPtr hFile, out UInt32 lpErrors, out COMSTAT cs); + + //Constants for lpErrors: + internal const UInt32 CE_RXOVER = 0x0001; + internal const UInt32 CE_OVERRUN = 0x0002; + internal const UInt32 CE_RXPARITY = 0x0004; + internal const UInt32 CE_FRAME = 0x0008; + internal const UInt32 CE_BREAK = 0x0010; + internal const UInt32 CE_TXFULL = 0x0100; + internal const UInt32 CE_PTO = 0x0200; + internal const UInt32 CE_IOE = 0x0400; + internal const UInt32 CE_DNS = 0x0800; + internal const UInt32 CE_OOP = 0x1000; + internal const UInt32 CE_MODE = 0x8000; + + [StructLayout( LayoutKind.Sequential )] internal struct COMSTAT + { + internal const uint fCtsHold = 0x1; + internal const uint fDsrHold = 0x2; + internal const uint fRlsdHold = 0x4; + internal const uint fXoffHold = 0x8; + internal const uint fXoffSent = 0x10; + internal const uint fEof = 0x20; + internal const uint fTxim = 0x40; + internal UInt32 Flags; + internal UInt32 cbInQue; + internal UInt32 cbOutQue; + } + [DllImport("kernel32.dll")] + internal static extern Boolean GetCommProperties(IntPtr hFile, out COMMPROP cp); + + [StructLayout( LayoutKind.Sequential )] internal struct COMMPROP + { + internal UInt16 wPacketLength; + internal UInt16 wPacketVersion; + internal UInt32 dwServiceMask; + internal UInt32 dwReserved1; + internal UInt32 dwMaxTxQueue; + internal UInt32 dwMaxRxQueue; + internal UInt32 dwMaxBaud; + internal UInt32 dwProvSubType; + internal UInt32 dwProvCapabilities; + internal UInt32 dwSettableParams; + internal UInt32 dwSettableBaud; + internal UInt16 wSettableData; + internal UInt16 wSettableStopParity; + internal UInt32 dwCurrentTxQueue; + internal UInt32 dwCurrentRxQueue; + internal UInt32 dwProvSpec1; + internal UInt32 dwProvSpec2; + internal Byte wcProvChar; + } + + } + +} diff --git a/ParParser.cs b/ParParser.cs new file mode 100644 index 0000000..a36641a --- /dev/null +++ b/ParParser.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; + +namespace UTIL +{ + public class ParParse + { + private List<(bool, string, string, bool, string, string)> Pars = new List<(bool, string, string, bool, string, string)>(); + private int _num = 0; + private (bool, string, string, bool, string, string) nullitem = (false, null, null, false, null,null); + public int NumofPar { get; } + + public ParParse() + { + AddPar("-h","--help",false, "Использование"); + } + public (bool, string, string, bool, string, string) GetPar(UInt16 num) + { + if (Pars[num].Item1) + return Pars[num]; + else + return nullitem; + } + public (bool, string, string, bool, string, string) GetPar(string par) + { + for (int j = 0; j < _num; j++) + { + if ((par == Pars[j].Item2 || par == Pars[j].Item3) && Pars[j].Item1) + return Pars[j]; + } + return nullitem; + } + public void AddPar(string shrt, string lng, Boolean key, string info) + { + Pars.Add((false, shrt, lng, key, "", info)); + _num = Pars.Count; + } + public int Parse(String[] arg) + { + int rez = 0; + if (_num == 0) + return -1; + + if (arg.Length == 0) + return -1; + + for (int i = 0; i < arg.Length; i++) + { + for (int j = 0; j < _num; j++) + { + if (arg[i] == Pars[j].Item2 || arg[i] == Pars[j].Item3) + { + (bool, string, string, bool, string, string) tmp = Pars[j]; + if (Pars[j].Item4) + { + tmp.Item5 = arg[i + 1]; + } + tmp.Item1 = true; + Pars[j] = tmp; + rez++; + } + } + } + return rez; + } + public void help() + { + string s = ""; + for (int i = 0; i < _num; i++) + { + if (Pars[i].Item3 != "") + s += $" {Pars[i].Item2}|{Pars[i].Item3}"; + else + s += $" {Pars[i].Item2}"; + } + Console.WriteLine($"Использование:\r\nGetVer3.exe{s}"); + for (int i = 0; i < _num; i++) + { + if (Pars[i].Item3 != "") + Console.WriteLine($"{Pars[i].Item2} {Pars[i].Item3}\t{Pars[i].Item6}"); + else + Console.WriteLine($"{Pars[i].Item2}\t{Pars[i].Item6}"); + } + } + } +} diff --git a/VCRuntime.cs b/VCRuntime.cs new file mode 100644 index 0000000..0fcad4a --- /dev/null +++ b/VCRuntime.cs @@ -0,0 +1,417 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Security.AccessControl; + +namespace UTIL +{ + public enum MscVer + { + // ReSharper disable InconsistentNaming + // + // MSC 1.0 _MSC_VER == 100 + // MSC 2.0 _MSC_VER == 200 + // MSC 3.0 _MSC_VER == 300 + // MSC 4.0 _MSC_VER == 400 + // MSC 5.0 _MSC_VER == 500 + // MSC 6.0 _MSC_VER == 600 + // MSC 7.0 _MSC_VER == 700 + // MSVC++ 1.0 _MSC_VER == 800 + // MSVC++ 2.0 _MSC_VER == 900 + // MSVC++ 4.0 _MSC_VER == 1000 (Developer Studio 4.0) + // MSVC++ 4.2 _MSC_VER == 1020 (Developer Studio 4.2) + // MSVC++ 5.0 _MSC_VER == 1100 (Visual Studio 97 version 5.0) + // MSVC++ 6.0 _MSC_VER == 1200 (Visual Studio 6.0 version 6.0) + // MSVC++ 7.0 _MSC_VER == 1300 (Visual Studio .NET 2002 version 7.0) + // MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio .NET 2003 version 7.1) + + Vs_2005 = 1400, // MSVC++ 8.0 + Vs_2008 = 1500, // MSVC++ 9.0 + Vs_2010 = 1600, // MSVC++ 10.0 + Vs_2012 = 1700, // MSVC++ 11.0 + Vs_2013 = 1800, // MSVC++ 12.0 + Vs_2015 = 1900, // MSVC++ 14.0 + Vs_2017_15_0 = 1910, // MSVC++ 14.10 + Vs_2017_15_3 = 1911, // MSVC++ 14.11 + Vs_2017_15_5 = 1912, // MSVC++ 14.12 + Vs_2017_15_6 = 1913, // MSVC++ 14.13 + Vs_2017_15_7 = 1914, // MSVC++ 14.14 + Vs_2017_15_8 = 1915, // MSVC++ 14.15 + Vs_2017_15_9 = 1916, // MSVC++ 14.16 + Vs_2019_16_0 = 1920, // MSVC++ 14.2 + Vs_2022_17_0 = 1930, // MSVC++ 14.30 + Vs_2022_17_1 = 1931 // MSVC++ 14.31 + } + public enum ArchType + { + // ReSharper disable InconsistentNaming + x86, + x64, + IA64 + } + public static class Msi + { + public static bool IsInstalled(IEnumerable productCodes) + { + return productCodes.Any(IsInstalled); + } + + public static bool IsInstalled(Guid productCode) + { + var state = MsiQueryProductState($"{{{productCode}}}"); + + return state == InstallState.INSTALLSTATE_LOCAL || + state == InstallState.INSTALLSTATE_DEFAULT; + } + + [DllImport("msi.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern InstallState MsiQueryProductState(string product); + } + + public enum InstallState + { + // ReSharper disable InconsistentNaming + INSTALLSTATE_NOTUSED = -7, // component disabled + INSTALLSTATE_BADCONFIG = -6, // configuration datacorrupt + INSTALLSTATE_INCOMPLETE = -5, // installationsuspended or in progress + INSTALLSTATE_SOURCEABSENT = -4, // run from source,source is unavailable + INSTALLSTATE_MOREDATA = -3, // return bufferoverflow + INSTALLSTATE_INVALIDARG = -2, // invalid functionargument + INSTALLSTATE_UNKNOWN = -1, // unrecognized productor feature + INSTALLSTATE_BROKEN = 0, // broken + INSTALLSTATE_ADVERTISED = 1, // advertised feature + INSTALLSTATE_REMOVED = 1, // component being removed(action state, not settable) + INSTALLSTATE_ABSENT = 2, // uninstalled (or actionstate absent but clients remain) + INSTALLSTATE_LOCAL = 3, // installed on local drive + INSTALLSTATE_SOURCE = 4, // run from source, CD ornet + INSTALLSTATE_DEFAULT = 5, // use default, local orsource + } + + public class VcRuntimeVersion + { + public Guid ProductCode { get; set; } + public MscVer MscVer { get; set; } + public ArchType Architecture { get; set; } + public string Version { get; set; } + + public VcRuntimeVersion(Guid productCode, MscVer mscVer, ArchType architecture, string version = "") + { + ProductCode = productCode; + MscVer = mscVer; + Architecture = architecture; + Version = version; + } + } + + public static class VcRuntime + { + public static IEnumerable GetInstalled(Func predicate) + { + return KnownRuntimeVersions.Where(predicate).Where(n => Msi.IsInstalled(n.ProductCode)); + } + + public static List KnownRuntimeVersions => new List + { + // https://en.wikipedia.org/wiki/Microsoft_Visual_C++ + // https://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Library + + // MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) + // ================================================= + // 8.0.50727.42 + // 8.0.50727.762 + // 8.0.50727.4053 + // todo 8.0.50727.5592 (can't find guids. see https://blogs.msdn.microsoft.com/astebner/2007/01/24/updated-vc-8-0-runtime-redistributable-packages-are-included-in-visual-studio-2005-sp1/) + // 8.0.50727.6195 + + new VcRuntimeVersion(Guid.Parse("{C1C4F017-81CC-94C4-C8FB-1542C0981A2A}"), MscVer.Vs_2005, ArchType.x86, "6.0.2900.2180"), + new VcRuntimeVersion(Guid.Parse("{1AF2A8DA-7E60-D0B4-29D7-E6453B3D0182}"), MscVer.Vs_2005, ArchType.x64, "6.0.2900.2180"), + + new VcRuntimeVersion(Guid.Parse("{A49F249F-0C91-497F-86DF-B2585E8E76B7}"), MscVer.Vs_2005, ArchType.x86, "8.0.50727.42"), + new VcRuntimeVersion(Guid.Parse("{6E8E85E8-CE4B-4FF5-91F7-04999C9FAE6A}"), MscVer.Vs_2005, ArchType.x64, "8.0.50727.42"), + new VcRuntimeVersion(Guid.Parse("{03ED71EA-F531-4927-AABD-1C31BCE8E187}"), MscVer.Vs_2005, ArchType.IA64, "8.0.50727.42"), + + new VcRuntimeVersion(Guid.Parse("{7299052B-02A4-4627-81F2-1818DA5D550D}"), MscVer.Vs_2005, ArchType.x86, "8.0.50727.762"), + new VcRuntimeVersion(Guid.Parse("{071C9B48-7C32-4621-A0AC-3F809523288F}"), MscVer.Vs_2005, ArchType.x64, "8.0.50727.762"), + new VcRuntimeVersion(Guid.Parse("{0F8FB34E-675E-42ED-850B-29D98C2ECE08}"), MscVer.Vs_2005, ArchType.IA64, "8.0.50727.762"), + + new VcRuntimeVersion(Guid.Parse("{837B34E3-7C30-493C-8F6A-2B0F04E2912C}"), MscVer.Vs_2005, ArchType.x86, "8.0.50727.4053"), + new VcRuntimeVersion(Guid.Parse("{6CE5BAE9-D3CA-4B99-891A-1DC6C118A5FC}"), MscVer.Vs_2005, ArchType.x64, "8.0.50727.4053"), + new VcRuntimeVersion(Guid.Parse("{85025851-A784-46D8-950D-05CB3CA43A13}"), MscVer.Vs_2005, ArchType.IA64, "8.0.50727.4053"), + + new VcRuntimeVersion(Guid.Parse("{710F4C1C-CC18-4C49-8CBF-51240C89A1A2}"), MscVer.Vs_2005, ArchType.x86, "8.0.50727.6195"), + new VcRuntimeVersion(Guid.Parse("{AD8A2FA1-06E7-4B0D-927D-6E54B3D31028}"), MscVer.Vs_2005, ArchType.x64, "8.0.50727.6195"), + new VcRuntimeVersion(Guid.Parse("{C2F60BDA-462A-4A72-8E4D-CA431A56E9EA}"), MscVer.Vs_2005, ArchType.IA64, "8.0.50727.6195"), + + // MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) + // ================================================= + // 9.0.21022.8 + // todo 9.0.30411 + // todo 9.0.30729.1 + // 9.0.30729.17 + // 9.0.30729.4148 + // todo 9.0.30729.5570 + // 9.0.30729.5677 + // 9.0.30729.6161 (see https://blogs.msdn.microsoft.com/astebner/2009/01/29/mailbag-how-to-detect-the-presence-of-the-visual-c-9-0-runtime-redistributable-package/) + + new VcRuntimeVersion(Guid.Parse("{FF66E9F6-83E7-3A3E-AF14-8DE9A809A6A4}"), MscVer.Vs_2008, ArchType.x86, "9.0.21022.8"), + new VcRuntimeVersion(Guid.Parse("{350AA351-21FA-3270-8B7A-835434E766AD}"), MscVer.Vs_2008, ArchType.x64, "9.0.21022.8"), + new VcRuntimeVersion(Guid.Parse("{2B547B43-DB50-3139-9EBE-37D419E0F5FA}"), MscVer.Vs_2008, ArchType.IA64, "9.0.21022.8"), + + new VcRuntimeVersion(Guid.Parse("{9A25302D-30C0-39D9-BD6F-21E6EC160475}"), MscVer.Vs_2008, ArchType.x86, "9.0.30729.17"), + new VcRuntimeVersion(Guid.Parse("{8220EEFE-38CD-377E-8595-13398D740ACE}"), MscVer.Vs_2008, ArchType.x64, "9.0.30729.17"), + new VcRuntimeVersion(Guid.Parse("{5827ECE1-AEB0-328E-B813-6FC68622C1F9}"), MscVer.Vs_2008, ArchType.IA64, "9.0.30729.17"), + + new VcRuntimeVersion(Guid.Parse("{1F1C2DFC-2D24-3E06-BCB8-725134ADF989}"), MscVer.Vs_2008, ArchType.x86, "9.0.30729.4148"), + new VcRuntimeVersion(Guid.Parse("{4B6C7001-C7D6-3710-913E-5BC23FCE91E6}"), MscVer.Vs_2008, ArchType.x64, "9.0.30729.4148"), + new VcRuntimeVersion(Guid.Parse("{977AD349-C2A8-39DD-9273-285C08987C7B}"), MscVer.Vs_2008, ArchType.IA64, "9.0.30729.4148"), + + new VcRuntimeVersion(Guid.Parse("{6E815EB9-6CCE-9A53-884E-7857C57002F0}"), MscVer.Vs_2008, ArchType.x86, "9.0.30729.5677"), + new VcRuntimeVersion(Guid.Parse("{67D6ECF5-CD5F-BA73-2B8B-22BAC8DE1B4D}"), MscVer.Vs_2008, ArchType.x64, "9.0.30729.5677"), + + new VcRuntimeVersion(Guid.Parse("{9BE518E6-ECC6-35A9-88E4-87755C07200F}"), MscVer.Vs_2008, ArchType.x86, "9.0.30729.6161"), + new VcRuntimeVersion(Guid.Parse("{5FCE6D76-F5DC-37AB-B2B8-22AB8CEDB1D4}"), MscVer.Vs_2008, ArchType.x64, "9.0.30729.6161"), + new VcRuntimeVersion(Guid.Parse("{515643D1-4E9E-342F-A75A-D1F16448DC04}"), MscVer.Vs_2008, ArchType.IA64, "9.0.30729.6161"), + + // MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) + // ================================================= + // 10.0.30319.1 + // todo 10.0.30319.415 + // 10.0.40219.1 + // 10.0.40219.325 + + new VcRuntimeVersion(Guid.Parse("{196BB40D-1578-3D01-B289-BEFC77A11A1E}"), MscVer.Vs_2010, ArchType.x86, "10.0.30319.1"), + new VcRuntimeVersion(Guid.Parse("{DA5E371C-6333-3D8A-93A4-6FD5B20BCC6E}"), MscVer.Vs_2010, ArchType.x64, "10.0.30319.1"), + new VcRuntimeVersion(Guid.Parse("{C1A35166-4301-38E9-BA67-02823AD72A1B}"), MscVer.Vs_2010, ArchType.IA64, "10.0.30319.1"), + + new VcRuntimeVersion(Guid.Parse("{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}"), MscVer.Vs_2010, ArchType.x86, "10.0.40219.1"), + new VcRuntimeVersion(Guid.Parse("{1D8E6291-B0D5-35EC-8441-6616F567A0F7}"), MscVer.Vs_2010, ArchType.x64, "10.0.40219.1"), + new VcRuntimeVersion(Guid.Parse("{88C73C1C-2DE5-3B01-AFB8-B46EF4AB41CD}"), MscVer.Vs_2010, ArchType.IA64, "10.0.40219.1"), + + new VcRuntimeVersion(Guid.Parse("{1D5E3C0F-EDA1-E123-1876-86FED06E995A}"), MscVer.Vs_2010, ArchType.x86, "10.0.40219.325"), + new VcRuntimeVersion(Guid.Parse("{1926E8D1-5D0B-CE53-4814-66615F760A7F}"), MscVer.Vs_2010, ArchType.x64, "10.0.40219.325"), + + // MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) + // ================================================= + // todo 11.0.50727.1 + // todo 11.0.51106.1 + // todo 11.0.60610.1 + // 11.0.61030 + + new VcRuntimeVersion(Guid.Parse("{33D1FD90-4274-48A1-9BC1-97E33D9C2D6F}"), MscVer.Vs_2012, ArchType.x86, "11.0.61030"), + new VcRuntimeVersion(Guid.Parse("{CA67548A-5EBE-413A-B50C-4B9CEB6D66C6}"), MscVer.Vs_2012, ArchType.x64, "11.0.61030"), + new VcRuntimeVersion(Guid.Parse("{BD95A8CD-1D9F-35AD-981A-3E7925026EBB}"), MscVer.Vs_2012, ArchType.x86, "11.0.61030 - Minimum runtime (Update 4)"), + new VcRuntimeVersion(Guid.Parse("{CF2BEA3C-26EA-32F8-AA9B-331F7E34BA97}"), MscVer.Vs_2012, ArchType.x64, "11.0.61030 - Minimum runtime (Update 4)"), + new VcRuntimeVersion(Guid.Parse("{B175520C-86A2-35A7-8619-86DC379688B9}"), MscVer.Vs_2012, ArchType.x86, "11.0.61030 - Additional runtime (Update 4)"), + new VcRuntimeVersion(Guid.Parse("{37B8F9C7-03FB-3253-8781-2517C99D7C00}"), MscVer.Vs_2012, ArchType.x64, "11.0.61030 - Additional runtime (Update 4)"), + + // MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) + // ================================================= + // todo 12.0.21005.1 + // 12.0.30501 + // 12.0.40660 + + new VcRuntimeVersion(Guid.Parse("{F65DB027-AFF3-4070-886A-0D87064AABB1}"), MscVer.Vs_2013, ArchType.x86, "12.0.30501"), + new VcRuntimeVersion(Guid.Parse("{050D4FC8-5D48-4B8F-8972-47C82C46020F}"), MscVer.Vs_2013, ArchType.x64, "12.0.30501"), + new VcRuntimeVersion(Guid.Parse("{13A4EE12-23EA-3371-91EE-EFB36DDFFF3E}"), MscVer.Vs_2013, ArchType.x86, "12.0.30501 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{A749D8E6-B613-3BE3-8F5F-045C84EBA29B}"), MscVer.Vs_2013, ArchType.x64, "12.0.30501 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{F8CFEB22-A2E7-3971-9EDA-4B11EDEFC185}"), MscVer.Vs_2013, ArchType.x86, "12.0.30501 - Additional runtime"), + new VcRuntimeVersion(Guid.Parse("{929FBD26-9020-399B-9A7A-751D61F0B942}"), MscVer.Vs_2013, ArchType.x64, "12.0.30501 - Additional runtime"), + + new VcRuntimeVersion(Guid.Parse("{61087a79-ac85-455c-934d-1fa22cc64f36}"), MscVer.Vs_2013, ArchType.x86, "12.0.40660"), + new VcRuntimeVersion(Guid.Parse("{ef6b00ec-13e1-4c25-9064-b2f383cb8412}"), MscVer.Vs_2013, ArchType.x64, "12.0.40660"), + new VcRuntimeVersion(Guid.Parse("{E30D8B21-D82D-3211-82CC-0F0A5D1495E8}"), MscVer.Vs_2013, ArchType.x86, "12.0.40660 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{CB0836EC-B072-368D-82B2-D3470BF95707}"), MscVer.Vs_2013, ArchType.x64, "12.0.40660 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{7DAD0258-515C-3DD4-8964-BD714199E0F7}"), MscVer.Vs_2013, ArchType.x86, "12.0.40660 - Additional runtime"), + new VcRuntimeVersion(Guid.Parse("{5740BD44-B58D-321A-AFC0-6D3D4556DD6C}"), MscVer.Vs_2013, ArchType.x64, "12.0.40660 - Additional runtime"), + + // MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) + // ================================================= + // 14.0.23026 + // 14.0.23506 + // 14.0.23918 + // 14.0.24123 + // todo 14.0.24210 (can't find 14.0.24210 installer - 03 Feb 2019) + // 14.0.24212 + // 14.0.24215 + // 14.0.24215.1 + + new VcRuntimeVersion(Guid.Parse("{74D0E5DB-B326-4DAE-A6B2-445B9DE1836E}"), MscVer.Vs_2015, ArchType.x86, "14.0.23026"), + new VcRuntimeVersion(Guid.Parse("{E46ECA4F-393B-40DF-9F49-076FAF788D83}"), MscVer.Vs_2015, ArchType.x64, "14.0.23026"), + new VcRuntimeVersion(Guid.Parse("{A2563E55-3BEC-3828-8D67-E5E8B9E8B675}"), MscVer.Vs_2015, ArchType.x86, "14.0.23026 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{0D3E9E15-DE7A-300B-96F1-B4AF12B96488}"), MscVer.Vs_2015, ArchType.x64, "14.0.23026 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{BE960C1C-7BAD-3DE6-8B1A-2616FE532845}"), MscVer.Vs_2015, ArchType.x86, "14.0.23026 - Additional runtime"), + new VcRuntimeVersion(Guid.Parse("{BC958BD2-5DAC-3862-BB1A-C1BE0790438D}"), MscVer.Vs_2015, ArchType.x64, "14.0.23026 - Additional runtime"), + + new VcRuntimeVersion(Guid.Parse("{23DAF363-3020-4059-B3AE-DC4AD39FED19}"), MscVer.Vs_2015, ArchType.x86, "14.0.23506"), + new VcRuntimeVersion(Guid.Parse("{3EE5E5BB-B7CC-4556-8861-A00A82977D6C}"), MscVer.Vs_2015, ArchType.x64, "14.0.23506"), + new VcRuntimeVersion(Guid.Parse("{65AD78AD-D23D-3A1E-9305-3AE65CD522C2}"), MscVer.Vs_2015, ArchType.x86, "14.0.23506 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{A1C31BA5-5438-3A07-9EEE-A5FB2D0FDE36}"), MscVer.Vs_2015, ArchType.x64, "14.0.23506 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{1045AB6F-6151-3634-8C2C-EE308AA1A6A7}"), MscVer.Vs_2015, ArchType.x86, "14.0.23506 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{B0B194F8-E0CE-33FE-AA11-636428A4B73D}"), MscVer.Vs_2015, ArchType.x64, "14.0.23506 - Additional Runtime"), + + new VcRuntimeVersion(Guid.Parse("{2E085FD2-A3E4-4B39-8E10-6B8D35F55244}"), MscVer.Vs_2015, ArchType.x86, "14.0.23918"), + new VcRuntimeVersion(Guid.Parse("{DAB68466-3A7D-41A8-A5CF-415E3FF8EF71}"), MscVer.Vs_2015, ArchType.x64, "14.0.23918"), + new VcRuntimeVersion(Guid.Parse("{262779DB-23A3-4517-BBCD-A05A9FF0570B}"), MscVer.Vs_2015, ArchType.x86, "14.0.23918 - Redistributable"), + new VcRuntimeVersion(Guid.Parse("{9F647882-65A3-4A6A-83CE-5E601E3D10A6}"), MscVer.Vs_2015, ArchType.x64, "14.0.23918 - Redistributable"), + new VcRuntimeVersion(Guid.Parse("{B5FC62F5-A367-37A5-9FD2-A6E137C0096F}"), MscVer.Vs_2015, ArchType.x86, "14.0.23918 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{7B50D081-E670-3B43-A460-0E2CDB5CE984}"), MscVer.Vs_2015, ArchType.x64, "14.0.23918 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{BD9CFD69-EB91-354E-9C98-D439E6091932}"), MscVer.Vs_2015, ArchType.x86, "14.0.23918 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{DFFEB619-5455-3697-B145-243D936DB95B}"), MscVer.Vs_2015, ArchType.x64, "14.0.23918 - Additional Runtime"), + + new VcRuntimeVersion(Guid.Parse("{206898CC-4B41-4D98-AC28-9F9AE57F91FE}"), MscVer.Vs_2015, ArchType.x86, "14.0.24123"), + new VcRuntimeVersion(Guid.Parse("{2CBCEDBB-F38C-48A3-A3E1-6C6FD821A7F4}"), MscVer.Vs_2015, ArchType.x64, "14.0.24123"), + new VcRuntimeVersion(Guid.Parse("{06AE3BCC-7612-39D3-9F3B-B6601D877D02}"), MscVer.Vs_2015, ArchType.x86, "14.0.24123 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{FDBE9DB4-7A91-3A28-B27E-705EF7CFAE57}"), MscVer.Vs_2015, ArchType.x64, "14.0.24123 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{03AC7A79-F8AF-38FC-9DA0-98DAB4F4B1CD}"), MscVer.Vs_2015, ArchType.x86, "14.0.24123 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{21134089-9B59-34C8-BE11-929D26AD5207}"), MscVer.Vs_2015, ArchType.x64, "14.0.24123 - Additional Runtime"), + + new VcRuntimeVersion(Guid.Parse("{8FD71E98-EE44-3844-9DAD-9CB0BBBC603C}"), MscVer.Vs_2015, ArchType.x86, "14.0.24210"), + new VcRuntimeVersion(Guid.Parse("{C0B2C673-ECAA-372D-94E5-E89440D087AD}"), MscVer.Vs_2015, ArchType.x64, "14.0.24210"), + + new VcRuntimeVersion(Guid.Parse("{462F63A8-6347-4894-A1B3-DBFE3A4C981D}"), MscVer.Vs_2015, ArchType.x86, "14.0.24212"), + new VcRuntimeVersion(Guid.Parse("{323DAD84-0974-4D90-A1C1-E006C7FDBB7D}"), MscVer.Vs_2015, ArchType.x64, "14.0.24212"), + new VcRuntimeVersion(Guid.Parse("{37B55901-995A-3650-80B1-BBFD047E2911}"), MscVer.Vs_2015, ArchType.x86, "14.0.24212 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{FAAD7243-0141-3987-AA2F-E56B20F80E41}"), MscVer.Vs_2015, ArchType.x64, "14.0.24212 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{844ECB74-9B63-3D5C-958C-30BD23F19EE4}"), MscVer.Vs_2015, ArchType.x86, "14.0.24212 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{F20396E5-D84E-3505-A7A8-7358F0155F6C}"), MscVer.Vs_2015, ArchType.x64, "14.0.24212 - Additional Runtime"), + + new VcRuntimeVersion(Guid.Parse("{BBF2AC74-720C-3CB3-8291-5E34039232FA}"), MscVer.Vs_2015, ArchType.x86, "14.0.24215 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{50A2BC33-C9CD-3BF1-A8FF-53C10A0B183C}"), MscVer.Vs_2015, ArchType.x64, "14.0.24215 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{C956892E-D1F3-3781-935C-8D9060E7CD7E}"), MscVer.Vs_2015, ArchType.x86, "14.0.24215 - Debug runtime"), + new VcRuntimeVersion(Guid.Parse("{406CC721-9FAD-3610-B44E-3130F84358D8}"), MscVer.Vs_2015, ArchType.x64, "14.0.24215 - Debug runtime"), + new VcRuntimeVersion(Guid.Parse("{69BCE4AC-9572-3271-A2FB-9423BDA36A43}"), MscVer.Vs_2015, ArchType.x86, "14.0.24215 - Additional runtime"), + new VcRuntimeVersion(Guid.Parse("{EF1EC6A9-17DE-3DA9-B040-686A1E8A8B04}"), MscVer.Vs_2015, ArchType.x64, "14.0.24215 - Additional runtime"), + + new VcRuntimeVersion(Guid.Parse("{E2803110-78B3-4664-A479-3611A381656A}"), MscVer.Vs_2015, ArchType.x86, "14.0.24215.1"), + new VcRuntimeVersion(Guid.Parse("{D992C12E-CAB2-426F-BDE3-FB8C53950B0D}"), MscVer.Vs_2015, ArchType.x64, "14.0.24215.1"), + new VcRuntimeVersion(Guid.Parse("{BBF2AC74-720C-3CB3-8291-5E34039232FA}"), MscVer.Vs_2015, ArchType.x86, "14.0.24215.1 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{50A2BC33-C9CD-3BF1-A8FF-53C10A0B183C}"), MscVer.Vs_2015, ArchType.x64, "14.0.24215.1 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{69BCE4AC-9572-3271-A2FB-9423BDA36A43}"), MscVer.Vs_2015, ArchType.x86, "14.0.24215.1 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{EF1EC6A9-17DE-3DA9-B040-686A1E8A8B04}"), MscVer.Vs_2015, ArchType.x64, "14.0.24215.1 - Additional Runtime"), + + // MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017) + // ================================================= + // 14.10.24629.0-rc1 + // 14.10.24911-rc5 + // 14.10.24930-rc6 + // 14.10.25008 MSVC++ 14.1 _MSC_VER == 1910 (Visual Studio 2017 version 15.0) + // 14.11.25325 MSVC++ 14.11 _MSC_VER == 1911 (Visual Studio 2017 version 15.3) + // 14.12.25810 MSVC++ 14.12 _MSC_VER == 1912 (Visual Studio 2017 version 15.5) + // todo 14.13.26020 MSVC++ 14.13 _MSC_VER == 1913 (Visual Studio 2017 version 15.6) + // 14.14.26405 MSVC++ 14.14 _MSC_VER == 1914 (Visual Studio 2017 version 15.7) + // 14.14.26429.4 + // todo 14.15.26706 MSVC++ 14.15 _MSC_VER == 1915 (Visual Studio 2017 version 15.8) + // 14.16.27012.6 MSVC++ 14.16 _MSC_VER == 1916 (Visual Studio 2017 version 15.9) - todo incomplete, find all guids + // 14.16.27024.1 + // todo 14.16.27026.1 + // 14.16.27027 + + new VcRuntimeVersion(Guid.Parse("{7d9c81d7-a921-4503-8518-38fc0c94b692}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.24629.0-rc1"), + new VcRuntimeVersion(Guid.Parse("{c60f2e5a-912d-426c-a6b1-8a80bebab424}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.24629.0-rc1"), + new VcRuntimeVersion(Guid.Parse("{27B6EB53-CB9C-3461-B05D-EB5210EBA3D4}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.24629 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{C8086B63-C436-3F8B-8064-CE8F27815C5F}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.24629 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{44EC2AE5-F313-3E2A-8167-9923138ED5B4}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.24629 - Additional runtime"), + new VcRuntimeVersion(Guid.Parse("{ADC1B84A-D61D-3B2F-854A-8F872E51BB65}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.24629 - Additional runtime"), + + new VcRuntimeVersion(Guid.Parse("{C64E9A20-DF31-4B11-ADA1-00909EB1B508}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.24911-rc5"), + new VcRuntimeVersion(Guid.Parse("{0A898FD4-A90B-46E2-8F20-46DDB3F24B6E}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.24911-rc5"), + new VcRuntimeVersion(Guid.Parse("{0C1C3F23-69C2-3D3D-9865-F8B6215289CD}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.24911-rc5 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{F0793C5B-0227-3294-91DE-0385602C6CBC}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.24911-rc5 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{568BE2F1-A2B2-3705-BF3E-8E6197382A46}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.24911-rc5 - Additional runtime"), + new VcRuntimeVersion(Guid.Parse("{E9A123F9-306E-3A29-88B9-5CD521D9109D}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.24911-rc5 - Additional runtime"), + + new VcRuntimeVersion(Guid.Parse("{3E053C90-8E3B-4A1B-AB2E-AFB57D20F4B0}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.24930-rc6"), + new VcRuntimeVersion(Guid.Parse("{20B93B94-495D-4022-A84F-F598998991BF}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.24930-rc6"), + new VcRuntimeVersion(Guid.Parse("{984D10BE-0781-3A9D-80FB-03540E0C3B42}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.24930-rc6 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{9F50D497-02C0-3BBB-9103-BFE6204FA318}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.24930-rc6 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{9AAEB713-D24D-37A4-8FBC-7A24739D3156}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.24930-rc6 - Additional runtime"), + new VcRuntimeVersion(Guid.Parse("{A8755EE8-AD62-37FE-B106-243DC209CF52}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.24930-rc6 - Additional runtime"), + + new VcRuntimeVersion(Guid.Parse("{C239CEA1-D49E-4E16-8E87-8C055765F7EC}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.25008-rtm"), + new VcRuntimeVersion(Guid.Parse("{F1E7E313-06DF-4C56-96A9-99FDFD149C51}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.25008-rtm"), + new VcRuntimeVersion(Guid.Parse("{C6CDA568-CD91-3CA0-9EDE-DAD98A13D6E1}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.25008-rtm - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{8D50D8C6-1E3D-3BAB-B2B7-A5399EA1EBD1}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.25008-rtm - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{2F8A908C-0CCD-3BDD-9212-DC6696525139}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.25008-rtm - Debug runtime"), + new VcRuntimeVersion(Guid.Parse("{B0763AF1-2B66-33B7-B6AF-78E123AEA826}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.25008-rtm - Debug runtime"), + new VcRuntimeVersion(Guid.Parse("{E6222D59-608C-3018-B86B-69BD241ACDE5}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.10.25008-rtm - Additional runtime"), + new VcRuntimeVersion(Guid.Parse("{C668F044-4825-330D-8F9F-3CBFC9F2AB89}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.10.25008-rtm - Additional runtime"), + + new VcRuntimeVersion(Guid.Parse("{404c9c27-8377-4fd1-b607-7ca635db4e49}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.11.25325"), + new VcRuntimeVersion(Guid.Parse("{6c6356fe-cbfa-4944-9bed-a9e99f45cb7a}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.11.25325"), + new VcRuntimeVersion(Guid.Parse("{029DA848-1A80-34D3-BFC1-A6447BFC8E7F}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.11.25325 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{B0037450-526D-3448-A370-CACBD87769A0}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.11.25325 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{568CD07E-0824-3EEB-AEC1-8FD51F3C85CF}"), MscVer.Vs_2017_15_0, ArchType.x86, "14.11.25325 - Additional runtime"), + new VcRuntimeVersion(Guid.Parse("{B13B3E11-1555-353F-A63A-8933EE104FBD}"), MscVer.Vs_2017_15_0, ArchType.x64, "14.11.25325 - Additional runtime"), + + new VcRuntimeVersion(Guid.Parse("{404c9c27-8377-4fd1-b607-7ca635db4e49}"), MscVer.Vs_2017_15_3, ArchType.x86, "14.11.25325"), + new VcRuntimeVersion(Guid.Parse("{6c6356fe-cbfa-4944-9bed-a9e99f45cb7a}"), MscVer.Vs_2017_15_3, ArchType.x64, "14.11.25325"), + new VcRuntimeVersion(Guid.Parse("{029DA848-1A80-34D3-BFC1-A6447BFC8E7F}"), MscVer.Vs_2017_15_3, ArchType.x86, "14.11.25325 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{B0037450-526D-3448-A370-CACBD87769A0}"), MscVer.Vs_2017_15_3, ArchType.x64, "14.11.25325 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{568CD07E-0824-3EEB-AEC1-8FD51F3C85CF}"), MscVer.Vs_2017_15_3, ArchType.x86, "14.11.25325 - Additional runtime"), + new VcRuntimeVersion(Guid.Parse("{B13B3E11-1555-353F-A63A-8933EE104FBD}"), MscVer.Vs_2017_15_3, ArchType.x64, "14.11.25325 - Additional runtime"), + + new VcRuntimeVersion(Guid.Parse("{E2EE15E2-A480-4BC5-BFB7-E9803D1D9823}"), MscVer.Vs_2017_15_5, ArchType.x64, "14.12.25810"), + new VcRuntimeVersion(Guid.Parse("{56e11d69-7cc9-40a5-a4f9-8f6190c4d84d}"), MscVer.Vs_2017_15_5, ArchType.x86, "14.12.25810"), + new VcRuntimeVersion(Guid.Parse("{2CD849A7-86A1-34A6-B8F9-D72F5B21A9AE}"), MscVer.Vs_2017_15_5, ArchType.x64, "14.12.25810 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{7FED75A1-600C-394B-8376-712E2A8861F2}"), MscVer.Vs_2017_15_5, ArchType.x86, "14.12.25810 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{C99E2ADC-0347-336E-A603-F1992B09D582}"), MscVer.Vs_2017_15_5, ArchType.x64, "14.12.25810 - Minimum runtime"), + new VcRuntimeVersion(Guid.Parse("{828952EB-5572-3666-8CA9-000B6CE79350}"), MscVer.Vs_2017_15_5, ArchType.x86, "14.12.25810 - Minimum runtime"), + + new VcRuntimeVersion(Guid.Parse("{EC9C2282-A836-48A6-9E41-C2F0BF8D678B}"), MscVer.Vs_2017_15_5, ArchType.x86, "14.14.26405"), + new VcRuntimeVersion(Guid.Parse("{5B295BA9-EF89-4AEB-8ACC-B61ADB0B9B5F}"), MscVer.Vs_2017_15_5, ArchType.x64, "14.14.26405"), + new VcRuntimeVersion(Guid.Parse("{644544A0-318A-344C-964C-4DBE2FB5F864}"), MscVer.Vs_2017_15_5, ArchType.x86, "14.14.26405 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{BCA8F863-9BAB-3398-B8E4-E1D0959D0943}"), MscVer.Vs_2017_15_5, ArchType.x64, "14.14.26405 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{36BF9A30-89CD-30BD-804D-09148F99DC67}"), MscVer.Vs_2017_15_5, ArchType.x86, "14.14.26405 - Debug Runtime"), + new VcRuntimeVersion(Guid.Parse("{874453C7-F1A2-3087-AE5B-A4D4C83B29B4}"), MscVer.Vs_2017_15_5, ArchType.x64, "14.14.26405 - Debug Runtime"), + new VcRuntimeVersion(Guid.Parse("{2BCACFA1-2BE1-373C-9051-76A9661D9FC4}"), MscVer.Vs_2017_15_5, ArchType.x86, "14.14.26405 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{A2999714-5C2C-3729-A911-4AE198B7B2FD}"), MscVer.Vs_2017_15_5, ArchType.x64, "14.14.26405 - Additional Runtime"), + + new VcRuntimeVersion(Guid.Parse("{7753EC39-3039-3629-98BE-447C5D869C09}"), MscVer.Vs_2017_15_7, ArchType.x86, "14.14.26429 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{03EBF679-E886-38AD-8E70-28658449F7F9}"), MscVer.Vs_2017_15_7, ArchType.x64, "14.14.26429 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{6F0267F3-7467-350D-A8C8-33B72E3658D8}"), MscVer.Vs_2017_15_7, ArchType.x86, "14.14.26429 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{B12F584A-DE7A-3EE3-8EC4-8A64DBC0F2A7}"), MscVer.Vs_2017_15_7, ArchType.x64, "14.14.26429 - Additional Runtime"), + + new VcRuntimeVersion(Guid.Parse("{67f67547-9693-4937-aa13-56e296bd40f6}"), MscVer.Vs_2017_15_7, ArchType.x86, "14.16.27012"), + new VcRuntimeVersion(Guid.Parse("{427ada59-85e7-4bc8-b8d5-ebf59db60423}"), MscVer.Vs_2017_15_7, ArchType.x64, "14.16.27012"), + new VcRuntimeVersion(Guid.Parse("{3ECD99CB-EDAF-45DA-AD9C-2C4875F375FB}"), MscVer.Vs_2017_15_7, ArchType.x64, "14.16.27012 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{7B77DE7F-5219-435E-9CE1-FC77F1D4CCAD}"), MscVer.Vs_2017_15_7, ArchType.x86, "14.16.27012 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{DF5B1280-A057-4536-9D03-3BCAA0D4C6F0}"), MscVer.Vs_2017_15_7, ArchType.x64, "14.16.27012 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{DD6BC8D7-4582-4677-BAAC-4AB933E6C315}"), MscVer.Vs_2017_15_7, ArchType.x86, "14.16.27012 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{BC1F17EB-F70C-4A9D-BAFE-BFFCF3DE24E2}"), MscVer.Vs_2017_15_7, ArchType.x64, "14.16.27012 - Debug Runtime"), + new VcRuntimeVersion(Guid.Parse("{4FCD7550-A8CF-47FF-AEA9-E0B03F9E82E7}"), MscVer.Vs_2017_15_7, ArchType.x86, "14.16.27012 - Debug Runtime"), + + new VcRuntimeVersion(Guid.Parse("{2ff11a2a-f7ac-4a6c-8cd4-c7bb974f3642}"), MscVer.Vs_2017_15_7, ArchType.x86, "14.16.27024.1"), + new VcRuntimeVersion(Guid.Parse("{5fb2083a-f3cc-4b78-93ff-bd9788b5de01}"), MscVer.Vs_2017_15_7, ArchType.x64, "14.16.27024.1"), + new VcRuntimeVersion(Guid.Parse("{5EEFCEFB-E5F7-4C82-99A5-813F04AA4FBD}"), MscVer.Vs_2017_15_7, ArchType.x86, "14.16.27024.1 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{F1B0FB3A-E0EA-47A6-9383-3650655403B0}"), MscVer.Vs_2017_15_7, ArchType.x64, "14.16.27024.1 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{7258184A-EC44-4B1A-A7D3-68D85A35BFD0}"), MscVer.Vs_2017_15_7, ArchType.x86, "14.16.27024.1 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{9D29FC96-9EEE-4253-943F-96B3BBFDD0B6}"), MscVer.Vs_2017_15_7, ArchType.x64, "14.16.27024.1 - Additional Runtime"), + + // MSVC++ 16.0 _MSC_VER >= 1920 (Visual Studio 2019) + // ================================================= + // 14.20.27508 + + new VcRuntimeVersion(Guid.Parse("{F3241984-5A0E-4632-9025-AA16E0780A4B}"), MscVer.Vs_2019_16_0, ArchType.x64, "14.20.27508 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{B96F6FA1-530F-42F1-9F71-33C583716340}"), MscVer.Vs_2019_16_0, ArchType.x86, "14.20.27508 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{4931385B-094D-4DC5-BD6A-5188FE9C51DF}"), MscVer.Vs_2019_16_0, ArchType.x64, "14.20.27508 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{C9DE51F8-7846-4621-815D-E8AFD3E3C0FF}"), MscVer.Vs_2019_16_0, ArchType.x86, "14.20.27508 - Additional Runtime"), + + // MSVC++ 17.0 _MSC_VER >= 1930 (Visual Studio 2022) + // ================================================= + // 14.30.30704 + + new VcRuntimeVersion(Guid.Parse("{662A0088-6FCD-45DD-9EA7-68674058AED5}"), MscVer.Vs_2022_17_0, ArchType.x64, "14.30.30704 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{F6080405-9FA8-4CAA-9982-14E95D1A3DAC}"), MscVer.Vs_2022_17_0, ArchType.x86, "14.30.30704 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{6DB765A8-05AF-49A1-A71D-6F645EE3CE41}"), MscVer.Vs_2022_17_0, ArchType.x64, "14.30.30704 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{BF08E976-B92E-4336-B56F-2171179476C4}"), MscVer.Vs_2022_17_0, ArchType.x86, "14.30.30704 - Additional Runtime"), + + // 14.31.31103 + + new VcRuntimeVersion(Guid.Parse("{A181A302-3F6D-4BAD-97A8-A426A6499D78}"), MscVer.Vs_2022_17_1, ArchType.x64, "14.31.31103 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{799E3FFF-705C-461F-B400-6DE27398B3E5}"), MscVer.Vs_2022_17_1, ArchType.x86, "14.31.31103 - Minimum Runtime"), + new VcRuntimeVersion(Guid.Parse("{A977984B-9244-49E3-BD24-43F0A8009667}"), MscVer.Vs_2022_17_1, ArchType.x64, "14.31.31103 - Additional Runtime"), + new VcRuntimeVersion(Guid.Parse("{5720EC03-F26F-40B7-980C-50B5D420B5DE}"), MscVer.Vs_2022_17_1, ArchType.x86, "14.31.31103 - Additional Runtime") + }; + } +} diff --git a/tcpsrvcli.cs b/tcpsrvcli.cs new file mode 100644 index 0000000..ef885b3 --- /dev/null +++ b/tcpsrvcli.cs @@ -0,0 +1,336 @@ +using System; +using System.IO; +using System.Net.Sockets; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +/// +/// Summary description for Class1 +/// +namespace TCPSRVCLI +{ + public class TCPSrvCli + { + private String _address; + private int _port; + private int _mode = -1; // -1 error, 0 server, 1 client + private bool _enabled = false; + private bool _connected = false; + private StreamWriter sw = null; + private StreamReader sr = null; + private TcpClient client; + Thread recv_thread = null; + private TcpListener listner = null; + + public delegate void Recv_Mess_s(String s); + public delegate void Recv_Mess_b(char[] arr); + public static Recv_Mess_s onRecvS; + public static Recv_Mess_b onRecvB; + + public bool Connected { get => _connected; } + public int Mode { get => _mode; } + + public TCPSrvCli(String address = "127.0.0.1", int port = 12000) + { + _address = address; + _port = port; + + if (InitSrv()) + { +#if DEBUG + Console.WriteLine("I a'm server"); +#endif + _connected = true; + return; + } + if (InitCli()) + { +#if DEBUG + Console.WriteLine("I a'm client"); +#endif + _connected = true; + return; + } + _connected = false; + } + public bool InitCli() + { + +#if DEBUG + Console.WriteLine("Start Client"); +#endif + int timeout = 100; + do + { + try + { + client = new TcpClient(); + client.Connect(new IPEndPoint(IPAddress.Parse(_address), _port)); + } + catch (Exception ee) + { +#if DEBUG + Console.Write("."); +#endif + Thread.Sleep(1000); + } + } while (!client.Connected && timeout-- > 0); + + if (timeout < 2) + { +#if DEBUG + Console.WriteLine("\r\nError connect Client " + timeout.ToString()); +#endif + return false; + } + Console.WriteLine(); + _enabled = true; + sw = new StreamWriter(client.GetStream()); + sr = new StreamReader(client.GetStream()); + sw.AutoFlush = true; + _connected = true; + + if (client.Connected) + { + recv_thread = new Thread(new ThreadStart(Recv)); + recv_thread.Start(); + } + _mode = 1; + return true; + } + public bool InitSrv() + { +#if DEBUG + Console.WriteLine("Start Server"); +#endif + try + { + listner = new TcpListener(new IPEndPoint(IPAddress.Parse(_address), _port)); + listner.Start(); + } + catch (Exception ee) + { +#if DEBUG + Console.WriteLine("Error start Server"); +#endif + _mode = -1; + return false; + } + _mode = 0; + _enabled = true; + _connected = true; + + client = listner.AcceptTcpClient(); + sr = new StreamReader(client.GetStream()); + sw = new StreamWriter(client.GetStream()); + sw.AutoFlush = true; + + recv_thread = new Thread(new ThreadStart(Recv)); + recv_thread.Start(); + + return true; + } + public void Stop() + { + try + { + _enabled = false; + if (_mode == 0) + { + client.Close(); + listner.Stop(); + } + if (_mode == 1) + { + client.Close(); + } + sr.Close(); + sw.Close(); + _connected = false; + } + catch (Exception ee) + { +#if DEBUG + Console.WriteLine(ee); +#endif + } + } + private void Recv() + { + while (_enabled) + { + if (client.Available > 0) + { + char[] s = new char[client.Available]; + sr.Read(s, 0, s.Length); +#if DEBUG + Console.WriteLine(s.Length); +#endif + if (s[s.Length - 2] == '\r' && s[s.Length - 1] == '\n') + onRecvS(new String(s)); + else + onRecvB(s); + } + } + client.Close(); + } + public void Send(String s) + { + try + { + if (client.Connected) + { + sw.WriteLine(s); + } + } + catch (Exception) + { +#if DEBUG + Console.WriteLine("Send string error"); +#endif + Stop(); + if (_mode == 0) + { + InitSrv(); + return; + } + if (_mode == 1) + { + InitCli(); + return; + } + } + } + public void Send(Byte[] b) + { + try + { + if (client.Connected) + { + sw.Write(Encoding.UTF8.GetChars(b)); + } + } + catch (Exception) + { +#if DEBUG + Console.WriteLine("Send array error"); +#endif + Stop(); + if (_mode == 0) + { + InitSrv(); + return; + } + if (_mode == 1) + { + InitCli(); + return; + } + } + } + } + + public class UDPSrvCli + { + private String _address; + private int _l_port; + private int _r_port; + private bool _enabled = false; + private bool _connected = false; + + public delegate void Recv_Mess_s(String s); + public delegate void Recv_Mess_b(Byte[] arr); + public static Recv_Mess_s onRecvS; + public static Recv_Mess_b onRecvB; + + public bool Connected { get => _connected; } + public int LocalPort { get => _l_port; } + public int RemotePort { get => _r_port; } + + public UDPSrvCli(String address = "127.0.0.1", int lport = 21000, int rport = 21001) + { + _address = address; + _l_port = lport; + _r_port = rport; + + try + { + using (UdpClient tmp = new UdpClient(_l_port)) + { +#if DEBUG + Console.WriteLine($"Client {_l_port}: OK"); +#endif + } + } + catch (Exception ee) + { + _l_port = 21001; + _r_port = 21000; +#if DEBUG + Console.WriteLine($"Client {_l_port}: OK"); +#endif + } + Task.Run(ReceiveMessageAsync); + + _connected = true; + _enabled = true; + return; + } + async Task ReceiveMessageAsync() + { + using (UdpClient receiver = new UdpClient(_l_port)) + { + while (_enabled) + { + var result = await receiver.ReceiveAsync(); + if (result.Buffer[result.Buffer.Length - 2] == '\r' && result.Buffer[result.Buffer.Length - 1] == '\n') + onRecvS(Encoding.UTF8.GetString(result.Buffer)); + else + onRecvB(result.Buffer); + } + } + } + + public async void Send(String s) + { + try + { + using (UdpClient sender = new UdpClient()) + { + byte[] data = Encoding.UTF8.GetBytes($"{s}\r\n"); + await sender.SendAsync(data, data.Length, new IPEndPoint(IPAddress.Parse(_address), _r_port)); + } + } + catch (Exception ee) + { +#if DEBUG + Console.WriteLine(ee); +#endif + } + } + public async void Send(Byte[] b) + { + try + { + using (UdpClient sender = new UdpClient()) + { + await sender.SendAsync(b, b.Length, new IPEndPoint(IPAddress.Parse(_address), _r_port)); + } + } + catch (Exception ee) + { +#if DEBUG + Console.WriteLine(ee); +#endif + } + } + + public void Stop() + { + _enabled = false; + _connected = false; + } + } +} diff --git a/udplib.cs b/udplib.cs index 814bffd..b0216f5 100644 --- a/udplib.cs +++ b/udplib.cs @@ -17,7 +17,7 @@ namespace UDPLIB { public class Data { - public static string Ver = "1.1.2.269"; + public static string Ver = "1.1.3.270"; protected static string IPAddr = "192.168.1.2"; protected static Int32 LocalPort = 5004; protected static Int32 RemotePort = 5006; @@ -147,6 +147,7 @@ namespace UDPLIB blackline = new Byte[iwidth * 3 + 20]; RTP.DataH0 = data; + rrr2.rawheader = data; RTP.GetDataH0(); iwidth = RTP.SD_Width; @@ -466,7 +467,6 @@ namespace UDPLIB } } - public class UDPTransmitSim : Data { UdpClient transmitter = null; @@ -746,6 +746,7 @@ namespace UDPLIB public String Configuration { get => Data.Conf; } public Boolean status_rs { set; get; } public Boolean status_eth { set; get; } + public Byte[] rawheader; } public static class CallBack { diff --git a/util.cs b/util.cs index afd4c25..e18fd2a 100644 --- a/util.cs +++ b/util.cs @@ -14,7 +14,8 @@ using static System.Net.Mime.MediaTypeNames; using System.Diagnostics; using System.Net.NetworkInformation; using System.Net; - +using System.Management; +using System.IO.Ports; namespace UTIL { @@ -482,6 +483,34 @@ namespace UTIL } public static class Util { + public static List getportnames() + { + List list = new List(); + try + { + String[] ports = System.IO.Ports.SerialPort.GetPortNames(); + foreach (var item in ports) + { + try + { + SerialPort sp_tmp = new SerialPort(item); + sp_tmp.Open(); + sp_tmp.Close(); + } + catch (Exception) + { + continue; + } + list.Add(item); + } + } + catch + { + return null; + } + return list; + } + public static String Val(Object value) { // Console.WriteLine(value.GetType()); @@ -670,6 +699,53 @@ namespace UTIL return num.ToString(); } } + #region создание нового имени файла из оригинального открытого с учетом дублей + //public static String NewFileName(String fullfilename, String newextention) + //{ + // if (!iofile.Exists(fullfilename.Replace(".bmp", "_00" + newextention))) + // return fullfilename.Replace(".bmp", "_00" + newextention); + // DirectoryInfo dir = new DirectoryInfo(iopath.GetDirectoryName(fullfilename)); + // String lastname; + // int lastnum = 0; + // String sss = ""; + // foreach (FileInfo item in dir.GetFiles("*" + newextention)) + // { + // //MessageBox.Show(item.FullName); + // if (item.FullName.StartsWith(fullfilename.Replace(".bmp", ""))) + // { + // lastname = item.FullName; + // lastnum = Convert.ToInt32(lastname.Replace(fullfilename.Replace(".bmp", ""), "").Replace(newextention, "").Remove(0, 1)); + // sss += lastname + "\r\n"; + // } + // } + // //MessageBox.Show(sss + "\r\n" + (lastnum + 1).ToString()); + // return fullfilename.Replace(".bmp", "") + "_" + (lastnum + 1).ToString("D2") + newextention; + //} + #endregion + #region Поиск последовательного порта по пид и вид + public static (String COM, String PID, String VID) SearchSerial(String pid, String vid) + { + var searcher = new ManagementObjectSearcher(@"Select * From Win32_PnPDevice"); + var s = ""; + if (pid != "") + s = $"PID_{pid}"; + else if (vid != "") + s = $"VID_{vid}"; + + foreach (var device in searcher.Get()) + { + if (device.ToString().Contains(s)) + { + String q1 = device.GetPropertyValue("SameElement").ToString().Replace("\"", "").Split('=')[1]; + String q2 = device.GetPropertyValue("SystemElement").ToString().Replace("\"", "").Split('=')[1]; + char[] sss = new char[] { '\\', '&' }; + String[] q3 = q2.Split(sss, StringSplitOptions.RemoveEmptyEntries); + return (q1, q3[2].Remove(0, 4), q3[1].Remove(0, 4)); + } + } + return ("", "", ""); + } + #endregion } public class CircularBuffer { @@ -1166,5 +1242,5 @@ namespace UTIL return rez; } } - + }