// Launches a process by means of the debug engine.
        // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger
        // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program
        // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language),
        // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method
        // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state.
        int IDebugEngineLaunch2.LaunchSuspended(
            string pszServer,
            IDebugPort2 port,
            string exe,
            string args,
            string dir,
            string env,
            string options,
            enum_LAUNCH_FLAGS launchFlags,
            uint hStdInput,
            uint hStdOutput,
            uint hStdError,
            IDebugEventCallback2 ad7Callback,
            out IDebugProcess2 process)
        {
            Debug.Assert(_pollThread == null);
            Debug.Assert(_engineCallback == null);
            Debug.Assert(_debuggedProcess == null);
            Debug.Assert(_ad7ProgramId == Guid.Empty);

            process = null;

            _engineCallback = new EngineCallback(this, ad7Callback);

            try
            {
                // We are being asked to debug a process when we currently aren't debugging anything
                _pollThread = new WorkerThread();

                _pollThread.RunOperation(() =>
                {
                    var endpoint     = new IPEndPoint(IPAddress.Parse(args.Split('=')[1]), 8085);
                    _debuggedProcess = new DebuggedProcess(endpoint, _engineCallback, _pollThread, this);

                    _pollThread.PostedOperationErrorEvent += _debuggedProcess.OnPostedOperationError;

                    return(_debuggedProcess.Initialize());
                });

                EngineUtils.RequireOk(port.GetProcess(_debuggedProcess.Id, out process));

                return(VSConstants.S_OK);
            }
            catch (Exception e) when(ExceptionHelper.BeforeCatch(e, reportOnlyCorrupting: true))
            {
                // If we just return the exception as an HRESULT, we will loose our message, so we instead send up an error event, and then
                // return E_ABORT.
                SendStartDebuggingError(e);
            }

            Dispose();

            return(VSConstants.E_ABORT);
        }
        // Called by the SDM to indicate that a synchronous debug event, previously sent by the DE to the SDM,
        // was received and processed. The only event the sample engine sends in this fashion is Program Destroy.
        // It responds to that event by shutting down the engine.
        int IDebugEngine2.ContinueFromSynchronousEvent(IDebugEvent2 eventObject)
        {
            try
            {
                if (eventObject is AD7ProgramCreateEvent)
                {
                    try
                    {
                        // At this point breakpoints and exception settings have been sent down, so we can resume the target
                        _pollThread.RunOperation(() =>
                        {
                            return(_debuggedProcess.ResumeFromLaunch());
                        });
                    }
                    catch (Exception e)
                    {
                        // If something goes wrong, report the error and then stop debugging. The SDM will drop errors
                        // from ContinueFromSynchronousEvent, so we want to deal with them ourself.
                        SendStartDebuggingError(e);
                        _debuggedProcess.Terminate();
                    }

                    return(VSConstants.S_OK);
                }
                else if (eventObject is AD7ProgramDestroyEvent)
                {
                    Dispose();
                }
                else
                {
                    Debug.Fail("Unknown syncronious event");
                }
            }
            catch (Exception e)
            {
                //return EngineUtils.UnexpectedException(e);
            }

            return(VSConstants.S_OK);
        }