internal SerialStream(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits, int readTimeout, int writeTimeout, Handshake handshake,
            bool dtrEnable, bool rtsEnable, bool discardNull, byte parityReplace)
        {

            int flags = UnsafeNativeMethods.FILE_FLAG_OVERLAPPED;
            // disable async on win9x
            if (Environment.OSVersion.Platform == PlatformID.Win32Windows) {
                flags = UnsafeNativeMethods.FILE_ATTRIBUTE_NORMAL;
                isAsync = false;
            }

            if ((portName == null) || !portName.StartsWith("COM", StringComparison.OrdinalIgnoreCase)) 
                throw new ArgumentException(SR.GetString(SR.Arg_InvalidSerialPort), "portName");

            //Error checking done in SerialPort.

            SafeFileHandle tempHandle = UnsafeNativeMethods.CreateFile("\\\\.\\" + portName,
                NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE,
                0,    // comm devices must be opened w/exclusive-access
                IntPtr.Zero, // no security attributes
                UnsafeNativeMethods.OPEN_EXISTING, // comm devices must use OPEN_EXISTING
                flags,
                IntPtr.Zero  // hTemplate must be NULL for comm devices
                );

            if (tempHandle.IsInvalid)
            {
                InternalResources.WinIOError(portName);
            }

            try {
                int fileType = UnsafeNativeMethods.GetFileType(tempHandle);

                // Allowing FILE_TYPE_UNKNOWN for legitimate serial device such as USB to serial adapter device 
                if ((fileType != UnsafeNativeMethods.FILE_TYPE_CHAR) && (fileType != UnsafeNativeMethods.FILE_TYPE_UNKNOWN))
                    throw new ArgumentException(SR.GetString(SR.Arg_InvalidSerialPort), "portName");

                _handle = tempHandle;

                // set properties of the stream that exist as members in SerialStream
                this.portName = portName;
                this.handshake = handshake;
                this.parityReplace = parityReplace;

                tempBuf = new byte[1];          // used in ReadByte()

                // Fill COMMPROPERTIES struct, which has our maximum allowed baud rate.
                // Call a serial specific API such as GetCommModemStatus which would fail
                // in case the device is not a legitimate serial device. For instance, 
                // some illegal FILE_TYPE_UNKNOWN device (or) "LPT1" on Win9x 
                // trying to pass for serial will be caught here. GetCommProperties works
                // fine for "LPT1" on Win9x, so that alone can't be relied here to
                // detect non serial devices.
                               
                commProp = new UnsafeNativeMethods.COMMPROP();
                int pinStatus = 0;
                
                if (!UnsafeNativeMethods.GetCommProperties(_handle, ref commProp) 
                    || !UnsafeNativeMethods.GetCommModemStatus(_handle, ref pinStatus))
                {
                    // If the portName they have passed in is a FILE_TYPE_CHAR but not a serial port,
                    // for example "LPT1", this API will fail.  For this reason we handle the error message specially. 
                    int errorCode = Marshal.GetLastWin32Error();
                    if ((errorCode == NativeMethods.ERROR_INVALID_PARAMETER) || (errorCode == NativeMethods.ERROR_INVALID_HANDLE))
                        throw new ArgumentException(SR.GetString(SR.Arg_InvalidSerialPortExtended), "portName");
                    else 
                        InternalResources.WinIOError(errorCode, string.Empty);
                }
                if (commProp.dwMaxBaud != 0 && baudRate > commProp.dwMaxBaud)
                    throw new ArgumentOutOfRangeException("baudRate", SR.GetString(SR.Max_Baud, commProp.dwMaxBaud));


                comStat = new UnsafeNativeMethods.COMSTAT();
                // create internal DCB structure, initialize according to Platform SDK
                // standard: ms-help://MS.MSNDNQTR.2002APR.1003/hardware/commun_965u.htm
                dcb = new UnsafeNativeMethods.DCB();

                // set constant properties of the DCB
                InitializeDCB(baudRate, parity, dataBits, stopBits, discardNull);

                this.DtrEnable = dtrEnable;

                // query and cache the initial RtsEnable value 
                // so that set_RtsEnable can do the (value != rtsEnable) optimization
                this.rtsEnable = (GetDcbFlag(NativeMethods.FRTSCONTROL) == NativeMethods.RTS_CONTROL_ENABLE);

                // now set this.RtsEnable to the specified value.
                // Handshake takes precedence, this will be a nop if 
                // handshake is either RequestToSend or RequestToSendXOnXOff 
                if ((handshake != Handshake.RequestToSend && handshake != Handshake.RequestToSendXOnXOff))
                    this.RtsEnable = rtsEnable;

                // NOTE: this logic should match what is in the ReadTimeout property
                if (readTimeout == 0) {
                    commTimeouts.ReadTotalTimeoutConstant   = 0;
                    commTimeouts.ReadTotalTimeoutMultiplier = 0;
                    commTimeouts.ReadIntervalTimeout        = NativeMethods.MAXDWORD;
                } else if (readTimeout == SerialPort.InfiniteTimeout) {
                    // SetCommTimeouts doesn't like a value of -1 for some reason, so
                    // we'll use -2(infiniteTimeoutConst) to represent infinite. 
                    commTimeouts.ReadTotalTimeoutConstant   = infiniteTimeoutConst;
                    commTimeouts.ReadTotalTimeoutMultiplier = NativeMethods.MAXDWORD;
                    commTimeouts.ReadIntervalTimeout        = NativeMethods.MAXDWORD;
                } else {
                    commTimeouts.ReadTotalTimeoutConstant   = readTimeout;
                    commTimeouts.ReadTotalTimeoutMultiplier = NativeMethods.MAXDWORD;
                    commTimeouts.ReadIntervalTimeout        = NativeMethods.MAXDWORD;
                }

                commTimeouts.WriteTotalTimeoutMultiplier    = 0;
                commTimeouts.WriteTotalTimeoutConstant      = ((writeTimeout == SerialPort.InfiniteTimeout) ? 0 : writeTimeout);

                // set unmanaged timeout structure
                if (UnsafeNativeMethods.SetCommTimeouts(_handle, ref commTimeouts) == false)
                {
                    InternalResources.WinIOError();
                }

                if (isAsync) {
                    if (!ThreadPool.BindHandle(_handle))
                    {
                        throw new IOException(SR.GetString(SR.IO_BindHandleFailed));
                    }
                }

                // monitor all events except TXEMPTY
                UnsafeNativeMethods.SetCommMask(_handle, NativeMethods.ALL_EVENTS);

                // prep. for starting event cycle.
                eventRunner = new EventLoopRunner(this);
                Thread eventLoopThread = new Thread(new ThreadStart(eventRunner.WaitForCommEvent));
                eventLoopThread.IsBackground = true;
                eventLoopThread.Start();
                
            }
            catch  {
                // if there are any exceptions after the call to CreateFile, we need to be sure to close the
                // handle before we let them continue up.
                tempHandle.Close();
                _handle = null;
                throw;
            }
        }
 internal SerialStream(string portName, int baudRate, System.IO.Ports.Parity parity, int dataBits, System.IO.Ports.StopBits stopBits, int readTimeout, int writeTimeout, System.IO.Ports.Handshake handshake, bool dtrEnable, bool rtsEnable, bool discardNull, byte parityReplace)
 {
     int dwFlagsAndAttributes = 0x40000000;
     if (Environment.OSVersion.Platform == PlatformID.Win32Windows)
     {
         dwFlagsAndAttributes = 0x80;
         this.isAsync = false;
     }
     if ((portName == null) || !portName.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
     {
         throw new ArgumentException(SR.GetString("Arg_InvalidSerialPort"), "portName");
     }
     SafeFileHandle hFile = Microsoft.Win32.UnsafeNativeMethods.CreateFile(@"\\.\" + portName, -1073741824, 0, IntPtr.Zero, 3, dwFlagsAndAttributes, IntPtr.Zero);
     if (hFile.IsInvalid)
     {
         InternalResources.WinIOError(portName);
     }
     try
     {
         int fileType = Microsoft.Win32.UnsafeNativeMethods.GetFileType(hFile);
         if ((fileType != 2) && (fileType != 0))
         {
             throw new ArgumentException(SR.GetString("Arg_InvalidSerialPort"), "portName");
         }
         this._handle = hFile;
         this.portName = portName;
         this.handshake = handshake;
         this.parityReplace = parityReplace;
         this.tempBuf = new byte[1];
         this.commProp = new Microsoft.Win32.UnsafeNativeMethods.COMMPROP();
         int lpModemStat = 0;
         if (!Microsoft.Win32.UnsafeNativeMethods.GetCommProperties(this._handle, ref this.commProp) || !Microsoft.Win32.UnsafeNativeMethods.GetCommModemStatus(this._handle, ref lpModemStat))
         {
             int errorCode = Marshal.GetLastWin32Error();
             switch (errorCode)
             {
                 case 0x57:
                 case 6:
                     throw new ArgumentException(SR.GetString("Arg_InvalidSerialPortExtended"), "portName");
             }
             InternalResources.WinIOError(errorCode, string.Empty);
         }
         if ((this.commProp.dwMaxBaud != 0) && (baudRate > this.commProp.dwMaxBaud))
         {
             throw new ArgumentOutOfRangeException("baudRate", SR.GetString("Max_Baud", new object[] { this.commProp.dwMaxBaud }));
         }
         this.comStat = new Microsoft.Win32.UnsafeNativeMethods.COMSTAT();
         this.dcb = new Microsoft.Win32.UnsafeNativeMethods.DCB();
         this.InitializeDCB(baudRate, parity, dataBits, stopBits, discardNull);
         this.DtrEnable = dtrEnable;
         this.rtsEnable = this.GetDcbFlag(12) == 1;
         if ((handshake != System.IO.Ports.Handshake.RequestToSend) && (handshake != System.IO.Ports.Handshake.RequestToSendXOnXOff))
         {
             this.RtsEnable = rtsEnable;
         }
         if (readTimeout == 0)
         {
             this.commTimeouts.ReadTotalTimeoutConstant = 0;
             this.commTimeouts.ReadTotalTimeoutMultiplier = 0;
             this.commTimeouts.ReadIntervalTimeout = -1;
         }
         else if (readTimeout == -1)
         {
             this.commTimeouts.ReadTotalTimeoutConstant = -2;
             this.commTimeouts.ReadTotalTimeoutMultiplier = -1;
             this.commTimeouts.ReadIntervalTimeout = -1;
         }
         else
         {
             this.commTimeouts.ReadTotalTimeoutConstant = readTimeout;
             this.commTimeouts.ReadTotalTimeoutMultiplier = -1;
             this.commTimeouts.ReadIntervalTimeout = -1;
         }
         this.commTimeouts.WriteTotalTimeoutMultiplier = 0;
         this.commTimeouts.WriteTotalTimeoutConstant = (writeTimeout == -1) ? 0 : writeTimeout;
         if (!Microsoft.Win32.UnsafeNativeMethods.SetCommTimeouts(this._handle, ref this.commTimeouts))
         {
             InternalResources.WinIOError();
         }
         if (this.isAsync && !ThreadPool.BindHandle(this._handle))
         {
             throw new IOException(SR.GetString("IO_BindHandleFailed"));
         }
         Microsoft.Win32.UnsafeNativeMethods.SetCommMask(this._handle, 0x1fb);
         this.eventRunner = new EventLoopRunner(this);
         new Thread(new ThreadStart(this.eventRunner.WaitForCommEvent)) { IsBackground = true }.Start();
     }
     catch
     {
         hFile.Close();
         this._handle = null;
         throw;
     }
 }