2

私は2つのプロジェクトを持っています。1つは「フロントエンド」またはローダープロジェクトで、もう1つはWebサービスで、実際には完全に別のフォルダー/ソリューションにあります。

私はすでにフロントエンドを使用して、そのプロジェクトを Cassini にロードしています (実際には 2 つあります)。私がやりたいのは、両方の Web サービスにデバッガーをアタッチすることです。実行時に、それらのプロジェクトでさえ、フロントエンド ソリューションには含まれません。

私はソース コードと pdb にアクセスできるので、これを実行できるはずだと思いますが、100% 確実ではなく、これをオンラインで実行するための情報は...せいぜいまばらです。

.NET、Visual Studio SDK、またはその他のサードパーティ フレームワークでこれを行う方法はありますか?

VS 2010 と VS 2012 にアクセスできます

4

2 に答える 2

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);
}

次のように「Try to attach to」呼び出しでまとめることができます。

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 に答える