28

SysInternals の DebugView は、.NET 4 で使用すると機能しなくなりました。一部の調査では、フレームワークの新しいアーキテクチャでは、デバッガーが接続されている場合にトレースをキャプチャできないことが示されました。私の場合は、Visual Studio デバッガーです。ターゲット フレームワークを 4 から 3.5 に変更すると、再び機能するようになります。

Visual Studioデバッガーが接続されているときに、DebugViewを.NET 4で動作させる方法を知っている人はいますか? Trace クラスの Listeners コレクションをクリアしようとしましたが、うまくいきませんでした。

4

4 に答える 4

23

.NET トレース メッセージはOutputDebugString、Windows カーネルの関数を使用して発行されます。この関数は、MSDN に記載されているように、

表示のために文字列をデバッガに送信します。

明らかに、ネイティブ デバッガーはこのメッセージを受け取ります。これは、この動作が仕様によるものであるという注釈によって意味されます。メッセージが .NET 4.0 より前の DebugView などの他のリスナーに渡された理由は、Visual Studio が「ネイティブ」デバッガーとして .NET コードをデバッグしなかったためです。ネイティブ デバッガーがアタッチされている場合、DebugView は機能しませんでした。

TraceListener回避策として、デバッガーが接続されていない別のプロセスにすべてのメッセージを転送する を追加することが考えられます。通信は、任意の IPC メカニズムを使用して実現できます。以下は、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");
    }
}
于 2010-12-14T13:15:50.870 に答える
17

必要に応じて、より簡単な回避策があります。Ctrl-F5 を使用して、デバッガーなしでアプリを起動するだけです。

DebugView を使用して、デバッガーで動作しないホストされた Silverlight アプリからデバッグ ステートメントを取得したいと考えていました。これは .NET 4 以前のようには機能しませんが、デバッグなしでホストを起動すると、デバッガー ステートメントが通過し、DebugView に表示されます。

于 2011-01-11T15:45:19.303 に答える
6

これで問題が解決しました:

Trace.AutoFlush = true;
于 2011-12-06T02:51:38.073 に答える
2

一部のプロジェクトを .NET 4.5 から .NET 4 にダウングレードしたときに、この問題に遭遇しました。突然、すべてのデバッグ ビュー データが消えました (そして、::OutputDebugString に直接 PInvoking していました)。とにかく、利用可能な最新バージョンの Debug View (4.81) にアップグレードすると、問題は解決しました。

于 2013-06-20T14:15:10.450 に答える