2010-12-13 8 views
27

DebugView di SysInternals non funziona più se utilizzato in .NET 4. Alcune ricerche hanno indicato che la nuova architettura del framework non consentiva la cattura di tracce se fosse collegato un debugger; nel mio caso è il debugger di Visual Studio. Cambiare il framework di destinazione da 4 a 3.5 fa funzionare di nuovo.Come far funzionare DebugView sotto .NET 4?

Qualcuno conosce un modo per far funzionare DebugView su .NET 4 mentre è in esecuzione il debugger di Visual Studio? Ho provato a cancellare la raccolta Listeners della classe Trace, ma senza fortuna.

+2

Davvero vero.Tuttavia, troverai i messaggi di tracciamento nella finestra * Output * di Visual Studio. –

+3

Il problema è stato segnalato 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 # e la loro risposta è stata che questo è "By Design". Se esiste una soluzione, mi piacerebbe conoscerla. . . –

+0

Sono consapevole di poter utilizzare l'output di Visual Studio. Ma non è così utile come DebugView. Nessun filtro, la dannata cosa continua a scorrere ... Sono stupito, come un ottimo strumento come DebugView, che non sembra essere disponibile alcuna soluzione alternativa. –

risposta

23

I messaggi di traccia .NET vengono emessi utilizzando la funzione OutputDebugString nel kernel di Windows. Questa funzione, come documentato in MSDN,

invia una stringa al debugger per la visualizzazione.

Ovviamente, un debugger nativo riceverà questo messaggio. Questo è inteso dal remark che questo comportamento è di progettazione. Il motivo per cui i messaggi venivano passati ad altri listener come DebugView prima di .NET 4.0 è che Visual Studio non eseguiva il debug del codice .NET come debugger "nativo"; DebugView non ha mai funzionato quando è collegato un debugger nativo.

Una soluzione alternativa potrebbe essere quella di aggiungere uno TraceListener che inoltra tutti i messaggi a un altro processo che non ha un debugger collegato. La comunicazione potrebbe essere realizzata utilizzando qualsiasi meccanismo IPC. Il seguente è un esempio che utilizza i socket TCP.


Application Server

Questo sarebbe un semplice programma a riga di comando stand-alone che viene avviato e arrestato automaticamente dalla classe 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

Grazie. Ottima spiegazione e soluzione. –

+0

Questo è bello. Vorrei poterlo revocare due volte. Ho fatto una piccola ottimizzazione che salta tutto questo se non si sta eseguendo nel debugger e si esegue DbgView. Basta avvolgere il codice di inizializzazione in qualcosa di simile: if (Debugger.IsAttached && Process.GetProcessesByName ("Dbgview"). Any()) –

17

A seconda delle esigenze, c'è una soluzione più semplice: basta iniziare la vostra applicazione senza il debugger utilizzando Ctrl-F5.

Speravo di utilizzare DebugView per acquisire le istruzioni di debug da un'applicazione di Silverlight ospitata che non funziona nel debugger. Anche se questo non funziona come prima di .NET 4, l'avvio del mio host senza eseguire il debug fa passare le istruzioni del debugger e queste vengono visualizzate in DebugView.

+1

Grazie! Questa è la soluzione più semplice. – duyn9uyen

6

Questo ha risolto il problema per me:

Trace.Autoflush = true; 
+0

Maiuscole/minuscole: Trace.AutoFlush = true; –

2

mi sono imbattuto in questo problema quando ho declassato alcuni progetti da .NET 4.5 a .NET 4 - improvvisamente tutti i miei debug Visualizzare i dati scomparsi (e sono stato direttamente PInvoking a :: OutputDebugString). Ad ogni modo, l'aggiornamento alla versione più recente disponibile di Debug View (4.81) ha risolto il problema.