2010-12-13 34 views
27

DebugView của SysInternals không còn hoạt động nếu được sử dụng trong .NET 4. Một số nghiên cứu chỉ ra rằng kiến ​​trúc mới của khung công tác không cho phép các dấu vết bị bắt nếu một trình gỡ lỗi được đính kèm; trong trường hợp của tôi đó là trình gỡ rối Visual Studio. Thay đổi khung mục tiêu từ 4 đến 3.5 khiến cho nó hoạt động trở lại.Làm cách nào để thực hiện công việc DebugView trong .NET 4?

Bất kỳ ai biết cách nhận DebugView hoạt động trong .NET 4 trong khi có trình gỡ lỗi Visual Studio được đính kèm? Tôi đã thử xóa bộ sưu tập Người nghe của lớp Trace, nhưng không may mắn.

+2

Thực sự đúng.Tuy nhiên, bạn sẽ tìm thấy các thông điệp dấu vết trong cửa sổ * Output * của Visual Studio. –

+3

Sự cố đã được báo cáo cho MS: https://connect.microsoft.com/VisualStudio/feedback/details/457063/outputdebugstring-doesnt-work-in-the-debugger-vs-2010-pro-beta-1-c? wa = wsignin1.0 # và câu trả lời của họ là đây là "Thiết kế". Nếu một workaround tồn tại tôi rất thích biết nó. . . –

+0

Tôi biết tôi có thể sử dụng đầu ra của Visual Studio. Nhưng nó gần như không hữu ích như DebugView. Không lọc, thứ chết tiệt chỉ giữ cuộn ... Tôi ngạc nhiên, công cụ tuyệt vời như DebugView là, không có cách giải quyết nào có sẵn. –

Trả lời

23

Thông báo theo dõi .NET được phát ra bằng chức năng OutputDebugString trong nhân Windows. Chức năng này, như được ghi trong MSDN,

gửi một chuỗi tới trình gỡ rối để hiển thị.

Rõ ràng, trình gỡ lỗi gốc sẽ nhận được thông báo này. Điều này có nghĩa là bởi remark rằng hành vi này là do thiết kế. Lý do các thông điệp được truyền cho các trình lắng nghe khác như DebugView trước .NET 4.0 là Visual Studio đã không gỡ lỗi mã .NET như một trình gỡ rối "bản địa"; DebugView chưa bao giờ làm việc khi một trình gỡ lỗi gốc được đính kèm.

Cách giải quyết có thể là thêm TraceListener chuyển tiếp tất cả thư đến một quy trình khác không đính kèm trình gỡ lỗi. Giao tiếp có thể được thực hiện bằng cách sử dụng bất kỳ cơ chế IPC nào. Sau đây là một mẫu sử dụng các cổng TCP.


Application Server

Đây sẽ là một chương trình dòng lệnh độc lập đơn giản mà được bắt đầu và dừng tự động bởi lớp 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); 
    } 
} 

Cách sử dụng

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

Cảm ơn. Giải thích và giải pháp tuyệt vời. –

+0

Điều này thật tuyệt. Ước gì tôi có thể upvote nó hai lần. Tôi đã thực hiện một tối ưu hóa nhỏ bỏ qua tất cả điều này nếu bạn không chạy trong trình gỡ rối và chạy DbgView. Chỉ cần quấn mã khởi tạo vào một cái gì đó như: if (Debugger.IsAttached && Process.GetProcessesByName ("Dbgview"). Any()) –

17

Tùy thuộc vào nhu cầu của bạn, có một cách giải quyết đơn giản hơn: chỉ cần bắt đầu ứng dụng của bạn mà không cần trình gỡ lỗi bằng cách sử dụng tổ hợp phím Ctrl-F5.

Tôi đã hy vọng sử dụng DebugView để nắm bắt các câu lệnh gỡ lỗi từ ứng dụng Silverlight được lưu trữ không hoạt động trong trình gỡ lỗi. Mặc dù điều này không hoạt động như trước đây .NET 4, việc khởi chạy máy chủ của tôi mà không cần gỡ lỗi không cho phép các trình gỡ lỗi thông qua và chúng hiển thị trong DebugView.

+1

Cảm ơn! Đây là cách giải quyết dễ nhất. – duyn9uyen

6

này cố định các vấn đề đối với tôi:

Trace.Autoflush = true; 
+0

Phân biệt chữ hoa chữ thường: Trace.AutoFlush = true; –

2

Tôi chạy vào vấn đề này khi tôi hạ cấp một số dự án từ .NET 4.5 để NET 4 - đột nhiên tất cả gỡ lỗi Xem dữ liệu của tôi biến mất (và tôi đã trực tiếp PInvoking đến :: OutputDebugString). Dù sao, nâng cấp lên phiên bản mới nhất có sẵn của Debug View (4.81) đã giải quyết được vấn đề.

Các vấn đề liên quan