// Resume a process launched by IDebugEngineLaunch2.LaunchSuspended int IDebugEngineLaunch2.ResumeProcess(IDebugProcess2 process) { Debug.Assert(Worker.MainThreadId == Worker.CurrentThreadId); Debug.Assert(m_pollThread != null); Debug.Assert(m_engineCallback != null); Debug.Assert(m_debuggedProcess != null); Debug.Assert(m_ad7ProgramId == Guid.Empty); try { int processId = EngineUtils.GetProcessId(process); if (processId != m_debuggedProcess.Id) { return(Constants.S_FALSE); } // Send a program node to the SDM. This will cause the SDM to turn around and call IDebugEngine2.Attach // which will complete the hookup with AD7 IDebugPort2 port; EngineUtils.RequireOk(process.GetPort(out port)); IDebugDefaultPort2 defaultPort = (IDebugDefaultPort2)port; IDebugPortNotify2 portNotify; EngineUtils.RequireOk(defaultPort.GetPortNotify(out portNotify)); EngineUtils.RequireOk(portNotify.AddProgramNode(new AD7ProgramNode(m_debuggedProcess.Id))); if (m_ad7ProgramId == Guid.Empty) { Debug.Fail("Unexpected problem -- IDebugEngine2.Attach wasn't called"); return(Constants.E_FAIL); } // Resume the threads in the debuggee process m_pollThread.RunOperation(new Operation(delegate { m_debuggedProcess.ResumeFromLaunch(); })); return(Constants.S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// 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(Worker.MainThreadId == Worker.CurrentThreadId); Debug.Assert(m_pollThread == null); Debug.Assert(m_engineCallback == null); Debug.Assert(m_debuggedProcess == null); Debug.Assert(m_ad7ProgramId == Guid.Empty); process = null; try { string commandLine = EngineUtils.BuildCommandLine(exe, args); ProcessLaunchInfo processLaunchInfo = new ProcessLaunchInfo(exe, commandLine, dir, env, options, (uint)launchFlags, hStdInput, hStdOutput, hStdError); // We are being asked to debug a process when we currently aren't debugging anything m_pollThread = new WorkerThread(); m_engineCallback = new EngineCallback(this, ad7Callback); // Complete the win32 attach on the poll thread m_pollThread.RunOperation(new Operation(delegate { m_debuggedProcess = Worker.LaunchProcess(m_engineCallback, processLaunchInfo); })); AD_PROCESS_ID adProcessId = new AD_PROCESS_ID(); adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = (uint)m_debuggedProcess.Id; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); return(Constants.S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Attach the debug engine to a program. int IDebugEngine2.Attach(IDebugProgram2[] rgpPrograms, IDebugProgramNode2[] rgpProgramNodes, uint celtPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason) { Debug.Assert(Worker.MainThreadId == Worker.CurrentThreadId); Debug.Assert(m_ad7ProgramId == Guid.Empty); if (celtPrograms != 1) { Debug.Fail("SampleEngine only expects to see one program in a process"); throw new ArgumentException(); } try { int processId = EngineUtils.GetProcessId(rgpPrograms[0]); if (processId == 0) { return(Constants.E_NOTIMPL); // sample engine only supports system processes } EngineUtils.RequireOk(rgpPrograms[0].GetProgramId(out m_ad7ProgramId)); // Attach can either be called to attach to a new process, or to complete an attach // to a launched process if (m_pollThread == null) { // We are being asked to debug a process when we currently aren't debugging anything m_pollThread = new WorkerThread(); m_engineCallback = new EngineCallback(this, ad7Callback); // Complete the win32 attach on the poll thread m_pollThread.RunOperation(new Operation(delegate { m_debuggedProcess = Worker.AttachToProcess(m_engineCallback, processId); })); m_pollThread.SetDebugProcess(m_debuggedProcess); } else { if (processId != m_debuggedProcess.Id) { Debug.Fail("Asked to attach to a process while we are debugging"); return(Constants.E_FAIL); } m_pollThread.SetDebugProcess(m_debuggedProcess); } AD7EngineCreateEvent.Send(this); AD7ProgramCreateEvent.Send(this); // start polling for debug events on the poll thread m_pollThread.RunOperationAsync(new Operation(delegate { m_debuggedProcess.ResumeEventPump(); })); return(Constants.S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// 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(Worker.MainThreadId == Worker.CurrentThreadId); Debug.Assert(m_pollThread == null); Debug.Assert(m_engineCallback == null); Debug.Assert(m_debuggedProcess == null); Debug.Assert(m_ad7ProgramId == Guid.Empty); process = null; try { string commandLine = EngineUtils.BuildCommandLine(exe, args); ProcessLaunchInfo processLaunchInfo = new ProcessLaunchInfo(exe, commandLine, dir, env, options, (uint)launchFlags, hStdInput, hStdOutput, hStdError); // We are being asked to debug a process when we currently aren't debugging anything m_pollThread = new WorkerThread(); m_engineCallback = new EngineCallback(this, ad7Callback); // Complete the win32 attach on the poll thread m_pollThread.RunOperation(new Operation(delegate { m_debuggedProcess = Worker.LaunchProcess(m_engineCallback, processLaunchInfo); })); AD_PROCESS_ID adProcessId = new AD_PROCESS_ID(); adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = (uint)m_debuggedProcess.Id; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); return Constants.S_OK; } catch (ComponentException e) { return e.HResult; } catch (Exception e) { return EngineUtils.UnexpectedException(e); } }
// Attach the debug engine to a program. int IDebugEngine2.Attach(IDebugProgram2[] rgpPrograms, IDebugProgramNode2[] rgpProgramNodes, uint celtPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason) { Debug.Assert(Worker.MainThreadId == Worker.CurrentThreadId); Debug.Assert(m_ad7ProgramId == Guid.Empty); if (celtPrograms != 1) { Debug.Fail("SampleEngine only expects to see one program in a process"); throw new ArgumentException(); } try { int processId = EngineUtils.GetProcessId(rgpPrograms[0]); if (processId == 0) { return Constants.E_NOTIMPL; // sample engine only supports system processes } EngineUtils.RequireOk(rgpPrograms[0].GetProgramId(out m_ad7ProgramId)); // Attach can either be called to attach to a new process, or to complete an attach // to a launched process if (m_pollThread == null) { // We are being asked to debug a process when we currently aren't debugging anything m_pollThread = new WorkerThread(); m_engineCallback = new EngineCallback(this, ad7Callback); // Complete the win32 attach on the poll thread m_pollThread.RunOperation(new Operation(delegate { m_debuggedProcess = Worker.AttachToProcess(m_engineCallback, processId); })); m_pollThread.SetDebugProcess(m_debuggedProcess); } else { if (processId != m_debuggedProcess.Id) { Debug.Fail("Asked to attach to a process while we are debugging"); return Constants.E_FAIL; } m_pollThread.SetDebugProcess(m_debuggedProcess); } AD7EngineCreateEvent.Send(this); AD7ProgramCreateEvent.Send(this); // start polling for debug events on the poll thread m_pollThread.RunOperationAsync(new Operation(delegate { m_debuggedProcess.ResumeEventPump(); })); return Constants.S_OK; } catch (ComponentException e) { return e.HResult; } catch (Exception e) { return EngineUtils.UnexpectedException(e); } }