2

我有两个项目,一个是“前端”或加载器项目,另一个是 Web 服务,它实际上完全位于一个单独的文件夹/解决方案中。

我已经在使用我的前端将该项目加载到 Cassini 中(实际上有两个)。我想做的是将调试器附加到我的两个 Web 服务上,并且它们的相关源代码在运行时、在前端,甚至那些项目中,都不包含在前端解决方案中。

我确实可以访问源代码和 pdb,所以我相信我应该能够做到这一点,但不是 100% 肯定,而且在线执行此操作的信息充其量是……稀疏。

在 .NET、Visual Studio SDK 或其他第三方框架中,有没有办法做到这一点?

我可以访问 VS 2010 和 VS 2012

4

2 回答 2

0

要调用的 VS API 是EnvDTE.Process.Attach

API 的文档给出了一个按名称附加进程的示例,该示例不适用于多个应用程序池。您可以通过命令行工具(可能需要提升)w3wp 命令行按应用程序池名称找到正确的 w3wp 进程。

于 2013-04-02T20:12:47.940 回答
0

所以你在这里有几个选择。

第一个选项(如果适用)是仅添加以下行:

#if DEBUG
System.Diagnostics.Debugger.Launch();
#endif

这通常会弹出“Visual Studio JIT 调试”窗口并允许您选择正在运行的实例或启动新的 Visual Studio。

或者,如果您想要一些...“更棘手”的东西,您可以遍历正在运行的进程,查找任何 Visual Studio 实例,并使用EnvDTEAPI 绑定到它们。这要复杂得多,所以如果适用,我推荐上面更简单的选项,但这里是:

首先,我们需要一种“查找”Visual Studio 实例的方法:

private static IEnumerable<Process> GetVisualStudioProcesses()
{
    var processes = Process.GetProcesses();
    return processes.Where(o => o.ProcessName.Contains("devenv"));
}

然后我们可以使用它来尝试附加到那些正在运行的实例支持的正确的基于 COM 的接口:

private static bool TryGetVsInstance(int processId, out EnvDTE._DTE instance)
{
    var numFetched = IntPtr.Zero;
    var monikers = new IMoniker[1];
    IRunningObjectTable runningObjectTable;
    IEnumMoniker monikerEnumerator;

    GetRunningObjectTable(0, out runningObjectTable);
    runningObjectTable.EnumRunning(out monikerEnumerator);
    monikerEnumerator.Reset();

    while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
    {
        IBindCtx ctx;
        CreateBindCtx(0, out ctx);

        string runningObjectName;
        monikers[0].GetDisplayName(ctx, null, out runningObjectName);

        object runningObjectVal;
        runningObjectTable.GetObject(monikers[0], out runningObjectVal);

        if (runningObjectVal is EnvDTE._DTE && runningObjectName.StartsWith("!VisualStudio"))
        {                    
            var currentProcessId = int.Parse(runningObjectName.Split(':')[1]);
            if (currentProcessId == processId)
            {
                instance = (EnvDTE._DTE)runningObjectVal;
                return true;
            }
        }
    }

    instance = null;
    return false;
}

COM 定义在哪里:

[ComImport, Guid("00000016-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleMessageFilter
{
    [PreserveSig]
    int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);

    [PreserveSig]
    int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);

    [PreserveSig]
    int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
}
public class MessageFilter : IOleMessageFilter
{
    private const int Handled = 0, RetryAllowed = 2, Retry = 99, Cancel = -1, WaitAndDispatch = 2;

    int IOleMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo)
    {
        return Handled;
    }

    int IOleMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
    {
        return dwRejectType == RetryAllowed ? Retry : Cancel;
    }

    int IOleMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
    {
        return WaitAndDispatch;
    }

    public static void Register()
    {
        CoRegisterMessageFilter(new MessageFilter());
    }

    public static void Revoke()
    {
        CoRegisterMessageFilter(null);
    }

    private static void CoRegisterMessageFilter(IOleMessageFilter newFilter)
    {
        IOleMessageFilter oldFilter;
        CoRegisterMessageFilter(newFilter, out oldFilter);
    }

    [DllImport("Ole32.dll")]
    private static extern int CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
}

我们可以像这样在“尝试附加到”调用中结束它:

public static bool AttachToProcess(int processId)
{
#if !DEBUG
    // Not allowed if not in DEBUG mode...
    return false;
#else
    MessageFilter.Register();
    Exception lastException = null;
    bool attachSuccess = false;
    while (!attachSuccess && !(lastException is COMException))
    {
        Log("Attempting DynamicAttach to process id:" + processId);
        try
        {
            Log("Querying for active VS instances...");
            var studioProcesses = GetVisualStudioProcesses();
            var studioDtes = studioProcesses
                .Select(proc =>
                {
                    EnvDTE._DTE dte;
                    if (TryGetVsInstance(proc.Id, out dte))
                    {
                        return new DteWrapper(dte);
                    }
                    return null;
                })
                .Where(dte => dte != null);
            foreach (var studioDte in studioDtes)
            {
                attachSuccess = TryAttachTo(processId, studioDte, out lastException);
                if(attachSuccess) break;
            }
        }
        catch (Exception vsex)
        {
            lastException = vsex;
        }

    }
    MessageFilter.Revoke();
    return attachSuccess;
#endif
}

private static bool TryAttachTo(int processId, DteWrapper studioDte, out Exception lastException)
{
    bool attachSuccess = false;
    lastException = null;
    Log("Attempting to attach to process " + processId);
    try
    {
        var localProcesses =
            from localProcess in studioDte.Debugger.LocalProcesses.Cast<EnvDTE.Process>()
            let processWrapper = new ProcessWrapper(localProcess)
            where processWrapper.Process2 == null || !processWrapper.Process2.IsBeingDebugged
            select processWrapper;
        if (!localProcesses.Any())
        {
            lastException = new ApplicationException("Can not find process to attach to!");
            return false;
        }
        foreach (var process in localProcesses)
        {
            try
            {
                if (process.Process.ProcessID == processId)
                {
                    Log("Found dte process to attach to, attempting attach...", studioDte);
                    try
                    {
                        process.Process.Attach();
                        Log("Attached to process!");
                        attachSuccess = true;
                        AtLeastOneDebuggerWasAttached = true;
                    }
                    catch (Exception detachException)
                    {
                        Log("Could not attach to process:" + detachException, studioDte);
                        attachSuccess = false;
                        lastException = detachException;
                    }
                }
            }
            catch (Exception attachException)
            {
                lastException = attachException;
            }
        }
    }
    catch (Exception queryProcessesException)
    {
        lastException = queryProcessesException;
    }
    return attachSuccess;
}

一些辅助类定义为:

internal class DteWrapper
{
    public DteWrapper(EnvDTE._DTE dte)
    {
        Dte = dte as EnvDTE.DTE;
        Dte2 = dte as EnvDTE80.DTE2;
        Debugger = dte.Debugger;
        Debugger2 = (Dte2 != null) ? Dte2.Debugger as EnvDTE80.Debugger2 : null;
        Events = dte.Events;
        DebuggerEvents = dte.Events.DebuggerEvents;
    }

    public EnvDTE.DTE Dte { get; private set; }
    public EnvDTE80.DTE2 Dte2 { get; private set; }

    public EnvDTE.Debugger Debugger { get; private set; }
    public EnvDTE80.Debugger2 Debugger2 { get; private set; }

    public EnvDTE.Events Events { get; private set; }
    public EnvDTE.DebuggerEvents DebuggerEvents { get; private set; }
}
internal class ProcessWrapper
{
    public ProcessWrapper(EnvDTE.Process dteProcess)
    {
        this.Process = dteProcess;
        this.Process2 = dteProcess as EnvDTE80.Process2;
        this.Process3 = dteProcess as EnvDTE90.Process3;
        this.ManagedProcess = System.Diagnostics.Process.GetProcessById(dteProcess.ProcessID);
    }
    public Process ManagedProcess { get; private set; }
    public EnvDTE.Process Process { get; private set; }
    public EnvDTE80.Process2 Process2 { get; private set; }
    public EnvDTE90.Process3 Process3 { get; private set; }
}
于 2013-04-02T20:42:06.810 回答