Как заставить DebugView работать под.NET 4?
DebugView SysInternals больше не работает, если используется в.NET 4. Некоторые исследования показали, что новая архитектура фреймворка не позволяет захватывать трассировки, если подключен отладчик; в моем случае это отладчик Visual Studio. Изменение целевого фреймворка с 4 на 3,5 заставляет его работать снова.
Кто-нибудь знает способ заставить DebugView работать под.NET 4, когда подключен отладчик Visual Studio? Я попытался очистить коллекцию Listeners класса Trace, но безуспешно.
4 ответа
Сообщения трассировки.NET отправляются с использованием OutputDebugString
функция в ядре Windows. Эта функция, как описано в MSDN,
отправляет строку в отладчик для отображения.
Очевидно, нативный отладчик получит это сообщение. Это подразумевается под замечанием, что это поведение разработано. Причина, по которой сообщения были переданы другим слушателям, таким как DebugView до.NET 4.0, заключается в том, что 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");
}
}
В зависимости от ваших потребностей, существует более простой обходной путь: просто запустите ваше приложение без отладчика, используя Ctrl-F5.
Я надеялся использовать DebugView для записи операторов отладки из размещенного приложения Silverlight, которое не работает в отладчике. Хотя это не работает, как это было до.NET 4, запуск моего хоста без отладки пропускает операторы отладчика, и они отображаются в DebugView.
Я столкнулся с этой проблемой, когда понизил некоторые проекты с.NET 4.5 до.NET 4 - внезапно все мои данные в представлении отладки исчезли (и я непосредственно вызывал PInvoking to::OutputDebugString). В любом случае, обновление до последней доступной версии Debug View (4.81) решило проблему.