/// <summary>
        /// Connect to an existing emulator process
        /// </summary>
        /// <returns>Success indication and error message.</returns>
        public async Task <StartResult> StartAsync()
        {
            int port;

            if (this.portConfig.Port != 0)
            {
                port = this.portConfig.Port;
            }
            else
            {
                var portString = Environment.GetEnvironmentVariable(Util.X3270Port);
                if (portString == null)
                {
                    return(new StartResult(Util.X3270Port + " not found in the environment"));
                }

                // Parse it.
                ushort port16;
                if (!ushort.TryParse(portString, out port16))
                {
                    return(new StartResult("Invalid " + Util.X3270Port + " in the environment"));
                }

                port = port16;
            }

            var result = await SessionUtil.TryConnect(port, this.portConfig.ConnectRetryMsec).ConfigureAwait(continueOnCapturedContext: false);

            if (result.Success)
            {
                this.client = result.Client;
                return(new StartResult());
            }
            else
            {
                return(new StartResult(result.FailReason));
            }
        }
        /// <summary>
        /// Start a new emulator process. Asynchronous version.
        /// </summary>
        /// <returns>Success/failure and failure reason.</returns>
        /// <exception cref="InvalidOperationException">Arguments are too long.</exception>
        public async Task <StartResult> StartAsync()
        {
            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            {
                socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true);
                socket.Bind(new IPEndPoint(IPAddress.Any, 0));
                int port = ((IPEndPoint)socket.LocalEndPoint).Port;

                // Start with basic arguments:
                //  -utf8             UTF-8 mode
                //  -model n          Model number
                //  -scriptportonce   Make sure the emulator exists if the socket connection breaks
                var arguments = string.Format("-minversion {0} -utf8 -model {1} -scriptportonce", MinVersion, this.processConfig.Model);

                // Add arbitrary extra options.
                if (this.processConfig.ExtraOptions != null)
                {
                    arguments += " " + string.Join(" ", this.processConfig.ExtraOptions.Select(o => o.Quote()));
                }

                // Build up the parameters for ws3270.
                var info = new ProcessStartInfo(this.processConfig.ProcessName);
                info.UseShellExecute        = false;
                info.CreateNoWindow         = true;
                info.RedirectStandardError  = true;
                info.RedirectStandardOutput = true;
                info.Arguments = string.Empty;

                // Put special unit test options first, intended to throw off the "-scriptport"-first logic below.
                if (this.processConfig.TestFirstOptions != null)
                {
                    info.Arguments = this.processConfig.TestFirstOptions;
                }

                // It's important to put "-scriptport" first, because the Mock server looks for it and ignores everything else.
                info.Arguments += info.Arguments.JoinNonEmpty(" ", string.Format("-scriptport {0}", port));
                info.Arguments += info.Arguments.JoinNonEmpty(" ", arguments);

                // Check for argument overflow.
                // At some point, we could automatically put most arguments into a temporary session file, but for now,
                // we blow up, so arguments aren't silently ignored.
                var argsMax = (Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 1) ? 32699 : 2080;
                if (this.processConfig.ProcessName.Length + 1 + info.Arguments.Length > argsMax)
                {
                    throw new InvalidOperationException("Arguments too long");
                }

                Util.Log("ProcessSession Start: ProcessName '{0}', arguments '{1}'", this.processConfig.ProcessName, info.Arguments);

                // Try starting it.
                try
                {
                    this.process = Process.Start(info);
                }
                catch (System.ComponentModel.Win32Exception e)
                {
                    // Typically Start errors are Win32 errors
                    return(new StartResult(e.Message));
                }
                catch (Exception e)
                {
                    return(new StartResult(string.Format("Caught exception {0}", e)));
                }

                var result = await SessionUtil.TryConnect(port, this.processConfig.ConnectRetryMsec).ConfigureAwait(continueOnCapturedContext: false);

                if (!result.Success)
                {
                    var emulatorErrorMessage = this.GetErrorOutput(result.FailReason);
                    this.ZapProcess();
                    return(new StartResult(emulatorErrorMessage));
                }
                else
                {
                    this.client = result.Client;
                    return(new StartResult());
                }
            }
        }