关于调试:如何使DebugView在.NET 4下工作?

How to make DebugView work under .NET 4?

如果在.NET 4下使用,SysInternals的DebugView将不再起作用。一些研究表明,如果连接了调试器,该框架的新体系结构将无法捕获跟踪。 就我而言,它是Visual Studio调试器。 将目标框架从4更改为3.5使其可以再次工作。

有人知道在连接Visual Studio调试器的同时让DebugView在.NET 4下工作的方法吗? 我尝试清除Trace类的Listeners集合,但是没有运气。


使用Windows内核中的OutputDebugString函数发出.NET跟踪消息。如MSDN中所述,此功能

sends a string to the debugger for display.

显然,本机调试器将收到此消息。这表示此行为是设计使然。消息在.NET 4.0之前传递给其他侦听器(如DebugView)的原因是Visual Studio并未将.NET代码作为"本机"调试器进行调试。连接本机调试器时,DebugView从未运行。

一种解决方法是添加TraceListener,将所有消息转发到另一个未附加调试器的进程。可以使用任何IPC机制来实现通信。以下是使用TCP套接字的示例。

服务器应用

这将是一个简单的独立命令行程序,由TraceListener类自动启动和停止:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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();
        }
    }
}

跟踪监听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
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);
    }
}

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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");
    }
}


根据您的需求,有一个更简单的解决方法:使用Ctrl-F5无需调试器即可启动您的应用程序。

我曾希望使用DebugView从无法在调试器中运行的托管Silverlight应用程序捕获调试语句。尽管这与.NET 4之前的工作不同,但在未调试的情况下启动主机确实会使调试器语句通过,并且它们显示在DebugView中。


这为我解决了问题:

1
Trace.AutoFlush = true;

当我将某些项目从.NET 4.5降级到.NET 4时,我遇到了这个问题-突然我的所有Debug View数据都消失了(而我直接P调用了:: OutputDebugString)。无论如何,升级到最新的最新可用版本的Debug View(4.81)解决了该问题。