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;
}
}
-
+
}