2010-12-13 15 views
27

DebugView de SysInternals ya no funciona si se usa bajo .NET 4. Algunas investigaciones indicaron que la nueva arquitectura del framework no permitía capturar rastros si se adjuntaba un depurador; en mi caso es el depurador de Visual Studio. Cambiar el marco de destino de 4 a 3.5 lo hace funcionar nuevamente.¿Cómo hacer que DebugView funcione bajo .NET 4?

¿Alguien sabe cómo conseguir que DebugView funcione bajo .NET 4 mientras tiene instalado el depurador de Visual Studio? Intenté borrar la colección Listeners de la clase Trace, pero no tuve suerte.

+2

De hecho cierto.Sin embargo, encontrará los mensajes de seguimiento en la ventana * Output * de Visual Studio. –

+3

El problema se informó a MS: https://connect.microsoft.com/VisualStudio/feedback/details/457063/outputdebugstring-doesnt-work-in-the-debugger-vs-2010-pro-beta-1-c? wa = wsignin1.0 # y su respuesta fue que esto es "Por diseño". Si existe una solución alternativa, me encantaría saberlo. . . –

+0

Soy consciente de que puedo usar la salida de Visual Studio. Pero no es tan útil como DebugView. Sin filtros, la maldita cosa sigue desplazándose ... Estoy sorprendido, como una gran herramienta como DebugView, de que no parece haber ninguna solución disponible. –

Respuesta

23

. Los mensajes de rastreo .NET se emiten utilizando la función OutputDebugString en el kernel de Windows. Esta función, como se documenta en MSDN,

envía una cadena al depurador para su visualización.

Obviamente, un depurador nativo recibirá este mensaje. Esto significa remark que este comportamiento es por diseño. El motivo por el que los mensajes se transmitieron a otros oyentes, como DebugView antes de .NET 4.0, es que Visual Studio no depuró el código .NET como un depurador "nativo"; DebugView nunca funcionó cuando se adjuntó un depurador nativo.

Una solución podría ser agregar un TraceListener que reenvía todos los mensajes a otro proceso que no tiene un depurador conectado. La comunicación podría realizarse utilizando cualquier mecanismo de IPC. La siguiente es una muestra que usa sockets TCP.


Application Server

Esto sería un simple programa de línea de comandos independiente que se inicia y se detiene automáticamente por la clase 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); 
    } 
} 

Uso

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"); 
    } 
} 
+0

Gracias. Gran explicación y solución. –

+0

Esto es genial. Ojalá pudiera votarlo dos veces. Hice una pequeña optimización que omite todo esto si no está ejecutando en el depurador y ejecutando DbgView. Simplemente ajuste el código de inicialización en algo como: if (Debugger.IsAttached && Process.GetProcessesByName ("Dbgview"). Any()) –

17

Dependiendo de sus necesidades, hay una solución más simple: basta con iniciar su aplicación sin el depurador mediante el uso de Ctrl-F5.

Tenía la esperanza de usar DebugView para capturar sentencias de depuración desde una aplicación alojada de Silverlight que no funciona en el depurador. Aunque esto no funciona como lo hacía antes con .NET 4, el inicio de mi host sin depuración deja pasar las instrucciones del depurador y aparecen en DebugView.

+1

¡Gracias! Esta es la solución más fácil. – duyn9uyen

6

se ha arreglado el problema para mí:

Trace.Autoflush = true; 
+0

Distinción entre mayúsculas y minúsculas: Trace.AutoFlush = true; –

2

me encontré con este problema cuando cambié algunos proyectos de .NET 4.5 a .NET 4 - de repente todos mis datos de depuración Ver desaparecieron (y yo estaba PInvoking directamente a :: OutputDebugString). De todos modos, la actualización a la última versión disponible de Debug View (4.81) resolvió el problema.

Cuestiones relacionadas