internal SqlError ProcessSNIError(TdsParserStateObject stateObj) {
#if DEBUG
            // There is an exception here for MARS as its possible that another thread has closed the connection just as we see an error
            Debug.Assert(SniContext.Undefined!=stateObj.DebugOnlyCopyOfSniContext || ((_fMARS) && ((_state == TdsParserState.Closed) || (_state == TdsParserState.Broken))), "SniContext must not be None");
#endif
            SNINativeMethodWrapper.SNI_Error sniError = new SNINativeMethodWrapper.SNI_Error();
            SNINativeMethodWrapper.SNIGetLastError(sniError);

            if (sniError.sniError != 0) {

                // handle special SNI error codes that are converted into exception which is not a SqlException.
                switch (sniError.sniError) {
                    case (int)SNINativeMethodWrapper.SniSpecialErrors.MultiSubnetFailoverWithMoreThan64IPs:
                        // Connecting with the MultiSubnetFailover connection option to a SQL Server instance configured with more than 64 IP addresses is not supported.
                        throw SQL.MultiSubnetFailoverWithMoreThan64IPs();
                    
                    case (int)SNINativeMethodWrapper.SniSpecialErrors.MultiSubnetFailoverWithInstanceSpecified:
                        // Connecting to a named SQL Server instance using the MultiSubnetFailover connection option is not supported.
                        throw SQL.MultiSubnetFailoverWithInstanceSpecified();

                    case (int)SNINativeMethodWrapper.SniSpecialErrors.MultiSubnetFailoverWithNonTcpProtocol:
                        // Connecting to a SQL Server instance using the MultiSubnetFailover connection option is only supported when using the TCP protocol.
                        throw SQL.MultiSubnetFailoverWithNonTcpProtocol();

                    // continue building SqlError instance
                }
            }

            // error.errorMessage is null terminated with garbage beyond that, since fixed length
            string errorMessage;
            int MessageLength = Array.IndexOf(sniError.errorMessage, '\0');
            if (MessageLength == -1) {
                errorMessage = String.Empty;  // If we don't see the expected null return nothing.
            } else {            
                errorMessage = new String(sniError.errorMessage, 0, MessageLength);
            }

            //  Format SNI errors and add Context Information
            //
            //  General syntax is:
            //  <sqlclient message>
            //  (provider:<SNIx provider>, error: <SNIx error code> - <SNIx error message>)
            //
            // errorMessage | sniError |
            // -------------------------------------------
            // ==null       | x        | must never happen
            // !=null       | != 0     | retrieve corresponding errorMessage from resources
            // !=null       | == 0     | replace text left of errorMessage
            //

            Debug.Assert(!ADP.IsEmpty(errorMessage),"Empty error message received from SNI");

            string sqlContextInfo = Res.GetString(Enum.GetName(typeof(SniContext), stateObj.SniContext));

            string providerRid = String.Format((IFormatProvider)null,"SNI_PN{0}", (int)sniError.provider);
            string providerName = Res.GetString(providerRid);
            Debug.Assert(!ADP.IsEmpty(providerName), String.Format((IFormatProvider)null,"invalid providerResourceId '{0}'", providerRid));
            uint win32ErrorCode = sniError.nativeError;

            if (sniError.sniError == 0) {
                // Provider error. The message from provider is preceeded with non-localizable info from SNI
                // strip provider info from SNI
                //
                int iColon = errorMessage.IndexOf(':');
                Debug.Assert(0<=iColon, "':' character missing in sni errorMessage");
                Debug.Assert(errorMessage.Length>iColon+1 && errorMessage[iColon+1]==' ', "Expecting a space after the ':' character");

                // extract the message excluding the colon and trailing cr/lf chars
                if (0<=iColon) {
                    int len = errorMessage.Length;
                    len -=2;    // exclude "\r\n" sequence
                    iColon+=2;  // skip over ": " sequence
                    len-=iColon;
                    /*
                        The error message should come back in the following format: "TCP Provider: MESSAGE TEXT"
                        Fix Bug 370686, if the message is recieved on a Win9x OS, the error message will not contain MESSAGE TEXT 
                        per Bug: 269574.  If we get a errormessage with no message text, just return the entire message otherwise 
                        return just the message text.
                    */
                    if (len > 0) { 
                        errorMessage = errorMessage.Substring(iColon, len); 
                    }
                }
            }
            else {
                // SNI error. Replace the entire message
                //
                errorMessage = SQL.GetSNIErrorMessage((int)sniError.sniError);

                // If its a LocalDB error, then nativeError actually contains a LocalDB-specific error code, not a win32 error code
                if (sniError.sniError == (int)SNINativeMethodWrapper.SniSpecialErrors.LocalDBErrorCode) {
                    errorMessage += LocalDBAPI.GetLocalDBMessage((int)sniError.nativeError);
                    win32ErrorCode = 0;
                }
            }
            errorMessage = String.Format((IFormatProvider)null, "{0} (provider: {1}, error: {2} - {3})",
                sqlContextInfo, providerName, (int)sniError.sniError, errorMessage);

            return new SqlError((int)sniError.nativeError, 0x00, TdsEnums.FATAL_ERROR_CLASS,
                                _server, errorMessage, sniError.function, (int)sniError.lineNumber, win32ErrorCode);
        }
        internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
        {
            string sNIErrorMessage;
            SNINativeMethodWrapper.SNI_Error error = new SNINativeMethodWrapper.SNI_Error();
            SNINativeMethodWrapper.SNIGetLastError(error);
            switch (error.sniError)
            {
                case 0x2f:
                    throw SQL.MultiSubnetFailoverWithMoreThan64IPs();

                case 0x30:
                    throw SQL.MultiSubnetFailoverWithInstanceSpecified();

                case 0x31:
                    throw SQL.MultiSubnetFailoverWithNonTcpProtocol();
            }
            int index = Array.IndexOf<char>(error.errorMessage, '\0');
            if (index == -1)
            {
                sNIErrorMessage = string.Empty;
            }
            else
            {
                sNIErrorMessage = new string(error.errorMessage, 0, index);
            }
            string str4 = System.Data.Res.GetString(Enum.GetName(typeof(SniContext), stateObj.SniContext));
            string str2 = System.Data.Res.GetString(string.Format(null, "SNI_PN{0}", new object[] { (int) error.provider }));
            if (error.sniError == 0)
            {
                int startIndex = sNIErrorMessage.IndexOf(':');
                if (0 <= startIndex)
                {
                    int length = sNIErrorMessage.Length - 2;
                    startIndex += 2;
                    length -= startIndex;
                    if (length > 0)
                    {
                        sNIErrorMessage = sNIErrorMessage.Substring(startIndex, length);
                    }
                }
            }
            else
            {
                sNIErrorMessage = SQL.GetSNIErrorMessage((int) error.sniError);
                if (error.sniError == SNINativeMethodWrapper.SNI_LocalDBErrorCode)
                {
                    sNIErrorMessage = sNIErrorMessage + LocalDBAPI.GetLocalDBMessage((int) error.nativeError);
                }
            }
            return new SqlError((int) error.nativeError, 0, 20, this._server, string.Format(null, "{0} (provider: {1}, error: {2} - {3})", new object[] { str4, str2, (int) error.sniError, sNIErrorMessage }), error.function, (int) error.lineNumber);
        }