Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make DebugView work under .NET 4?

SysInternals' DebugView no longer works if used under .NET 4. Some research indicated that the new architecture of the framework did not allow for traces to be captured if a debugger was attached; in my case it's the Visual Studio debugger. Changing target framework from 4 to 3.5 makes it work again.

Anybody knows a way of getting DebugView to work under .NET 4 while having the Visual Studio debugger attached? I tried clearing the Listeners collection of the Trace class, but no luck.

like image 606
So Many Goblins Avatar asked Dec 13 '10 13:12

So Many Goblins


People also ask

How do I run DebugView?

To start DebugView from AlwaysUp, choose Application > Start "Dbgview". The state will transition to Running and DebugView will start working in the background. That's it! Next time your computer boots, DebugView will start up immediately, before anyone logs on.

How do I use DebugView for Windows?

Installation and Use Simply execute the DebugView program file (dbgview.exe) and DebugView will immediately start capturing debug output. Note that if you run DebugView on Windows 2000/XP you must have administrative privilege to view kernel-mode debug output.

How do I view OutputDebugString?

Anyway, the natural way to view the OutputDebugString output for a Delphi application is to use the Delphi IDE and the Event Log Window.


4 Answers

.NET trace messages are emitted using the OutputDebugString function in the Windows kernel. This function, as documented in MSDN,

sends a string to the debugger for display.

Obviously, a native debugger will receive this message. This is meant by the remark that this behavior is by design. The reason the messages were passed on to other listeners such as DebugView before .NET 4.0 is that Visual Studio did not debug .NET code as a "native" debugger; DebugView has never worked when a native debugger is attached.

A workaround could be to add a TraceListener that forwards all messages to another process that has no debugger attached. The communication could be realized using any IPC mechanism. The following is a sample using TCP sockets.


Server Application

This would be a simple stand-alone command line program that gets started and stopped automatically by the TraceListener class:

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);
    }
}

Usage

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");
    }
}
like image 126
Dirk Vollmar Avatar answered Oct 01 '22 10:10

Dirk Vollmar


Depending on your needs, there is a simpler workaround: just start your app without the debugger by using Ctrl-F5.

I had hoped to use DebugView to capture debug statements from a hosted Silverlight app that doesn't work in the debugger. Although this doesn't work as it did before .NET 4, launching my host without debugging does let the debugger statements through and they show up in DebugView.

like image 34
mcobrien Avatar answered Oct 01 '22 12:10

mcobrien


This fixed the problem for me:

Trace.AutoFlush = true;
like image 34
Ashley Davis Avatar answered Oct 01 '22 12:10

Ashley Davis


I ran into this problem when I downgraded some projects from .NET 4.5 to .NET 4 - suddenly all my Debug View data disappeared (and I was directly PInvoking to ::OutputDebugString). Anyway, upgrade to late latest available version of Debug View (4.81) solved the problem.

like image 37
Tom Kirby-Green Avatar answered Oct 01 '22 11:10

Tom Kirby-Green