Как заставить DebugView работать в .NET 4?

DebugView от SysInternals больше не работает, если используется в .NET 4. Некоторые исследования показали, что новая архитектура фреймворка не позволяла захватывать следы, если был добавлен отладчик; в моем случае это отладчик Visual Studio. Изменение целевой структуры с 4 до 3.5 заставляет ее работать снова.

Кто-нибудь знает, как заставить DebugView работать с .NET 4 при подключении отладчика Visual Studio? Я попытался очистить коллекцию Listeners класса Trace, но не повезло.

+26
источник поделиться
4 ответа

Сообщения трассировки .NET испускаются с помощью функции OutputDebugString в ядре Windows. Эта функция, как описано в MSDN,

отправляет строку в отладчик для отображения.

Очевидно, что родной отладчик получит это сообщение. Это означает примечание, что это поведение по дизайну. Причина, по которой сообщения передавались другим слушателям, таким как DebugView перед .NET 4.0, заключается в том, что Visual Studio не отлаживала .NET-код как "родной" отладчик; DebugView никогда не работал, когда подключен встроенный отладчик.

Обходным решением может быть добавление TraceListener, которое пересылает все сообщения другому процессу, который не имеет прикрепленного отладчика. Связь может быть реализована с использованием любого механизма МПК. Ниже приведен пример с использованием сокетов TCP.


Серверное приложение

Это будет простая автономная программа командной строки, которая автоматически запускается и останавливается классом TraceListener:

using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        if (args.Length != 1)
        {
            Console.WriteLine("Usage: DebugOutputListener.exe <port>");
            return;
        }
        TcpListener server = null;
        try
        {
            Int32 port = Convert.ToInt32(args[0]);
            IPAddress localAddr = IPAddress.Parse("127.0.0.1");

            server = new TcpListener(localAddr, port);
            server.Start();

            while (true)
            {
                Console.Write("Waiting for a connection... ");

                using (TcpClient client = server.AcceptTcpClient())
                {
                    using (NetworkStream stream = client.GetStream())
                    {

                        byte[] bufferLength = new byte[4];
                        stream.Read(bufferLength, 0, 4);
                        int length = BitConverter.ToInt32(bufferLength, 0);

                        if (length == -1)
                        {
                            // close message received
                            Trace.WriteLine("DebugOutputListener is closing.");
                            return;
                        }

                        byte[] bufferMessage = new byte[length];
                        stream.Read(bufferMessage, 0, length);

                        string msg = Encoding.UTF8.GetString(bufferMessage);
                        Trace.WriteLine(msg);
                    }
                }
            }
        }
        catch (SocketException e)
        {
            Console.WriteLine("SocketException: {0}", e);
        }
        finally
        {
            server.Stop();
        }
    }
}

TraceListener

using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class DebugOutputTraceListener : TraceListener
{
    private IPEndPoint ipEndPoint;
    private bool needsDisposing;

    public DebugOutputTraceListener(string debugOutputListenerPath, int port)
    {
        this.ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 13000);

        // start the process that forwards the trace messages 
        var psi = new ProcessStartInfo()
        {
            FileName = debugOutputListenerPath,
            Arguments = port.ToString(),
            CreateNoWindow = true,
            UseShellExecute = false
        };
        Process.Start(psi);
        needsDisposing = true;
    }

    ~DebugOutputTraceListener()
    {
        Dispose(false);
    }

    public override void Write(string message)
    {
        sendMessage(message);
    }

    public override void WriteLine(string message)
    {
        sendMessage(message + Environment.NewLine);
    }

    private void sendMessage(string message)
    {
        try
        {
            using (TcpClient client = new TcpClient())
            {
                client.Connect(ipEndPoint);
                byte[] bufferMessage = Encoding.UTF8.GetBytes(message);
                byte[] bufferLength = 
                    BitConverter.GetBytes(bufferMessage.Length);

                using (NetworkStream stream = client.GetStream())
                {
                    stream.Write(bufferLength, 0, bufferLength.Length);
                    stream.Write(bufferMessage, 0, bufferMessage.Length);
                }
            }
        }
        catch (SocketException e)
        {
            Trace.WriteLine(e.ToString());
        }
    }

    /// <summary>
    /// Sends -1 to close the TCP listener server.
    /// </summary>
    private void sendCloseMessage()
    {
        try
        {
            using (TcpClient client = new TcpClient())
            {
                client.Connect(ipEndPoint);
                byte[] buffer = BitConverter.GetBytes(-1);

                using (NetworkStream stream = client.GetStream())
                {
                    stream.Write(buffer, 0, buffer.Length);
                }
            }
        }
        catch (SocketException e)
        {
            Trace.WriteLine(e.ToString());
        }
    }

    public override void Close()
    {
        sendCloseMessage();
        needsDisposing = false;
        base.Close();
    }

    protected override void Dispose(bool disposing)
    {
        if (needsDisposing)
        {
            sendCloseMessage();
            needsDisposing = false;
        }
        base.Dispose(disposing);
    }
}

Использование

public class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        // using Debug; start a listener process on port 13000
        Debug.Listeners.Add(
            new DebugOutputTraceListener("DebugOutputListener.exe", 13000));
        Debug.WriteLine("A debug message.");

        // using Trace; start a listener process on port 13001
        Trace.Listeners.Add(
            new DebugOutputTraceListener("DebugOutputListener.exe", 13001));
        Trace.WriteLine("A trace message");
    }
}
+23
источник

В зависимости от ваших потребностей есть более простой способ: просто запустите приложение без отладчика, используя Ctrl-F5.

Я надеялся использовать DebugView для захвата операторов отладки из размещенного приложения Silverlight, которое не работает в отладчике. Хотя это не работает так, как это было до .NET 4, запуск моего хоста без отладки позволяет пропустить инструкции отладчика, и они отображаются в DebugView.

+17
источник

Это исправило проблему для меня:

Trace.Autoflush = true;
+6
источник

Я столкнулся с этой проблемой, когда я понизил некоторые проекты с .NET 4.5 до .NET 4 - внезапно все мои данные Debug View исчезли (и я был напрямую PInvoking до:: OutputDebugString). В любом случае, обновление до последней доступной версии Debug View (4.81) решило проблему.

+2
источник

Посмотрите другие вопросы по меткам или Задайте вопрос