【问题标题】:.NET external DLL log redirection.NET 外部 DLL 日志重定向
【发布时间】:2015-03-16 12:15:40
【问题描述】:
情况是这样的:
- 我有一个 .net 应用程序,它使用并调用外部 win32 dll 方法。
- dll 本身会为调试目的执行大量控制台日志记录
有没有办法在执行它的方法时从 dll 中预取日志并将它们重定向到一个文件左右?
我可以毫无问题地将应用程序的控制台输出重定向到文件 - 但 DLL 调用仍然隐藏(我只能在实际控制台中看到它们)。
谢谢!
【问题讨论】:
标签:
.net
logging
dll
nlog
console-redirect
【解决方案1】:
这可能对谁有帮助,here is the solution for this:
#region thanks
/////////////////////////////////////////////////////////////////
// With thanks to nobugz //
// MVP, Moderator on the MSDN C# general forums //
// http://social.msdn.microsoft.com/Profile/en-US/?user=nobugz //
/////////////////////////////////////////////////////////////////
#endregion
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace miniws
{
internal sealed class ConsoleRedirector : IDisposable
{
private static ConsoleRedirector _instance;
public static void attach(ILogListener listener)
{
Debug.Assert(null == _instance);
_instance = new ConsoleRedirector(listener);
}
public static void detatch()
{
_instance.Dispose();
_instance = null;
}
public static bool isAttached
{
get
{
return null != _instance;
}
}
//----------------------------------------------------------------------
private const int PERIOD = 500;
private const int BUFFER_SIZE = 4096;
private volatile bool _isDisposed;
private readonly ILogListener _logListener;
private readonly IntPtr _stdout;
private readonly IntPtr _stderr;
private readonly Mutex _sync;
private readonly Timer _timer;
private readonly char[] _buffer;
private readonly AnonymousPipeServerStream _outServer;
private readonly AnonymousPipeServerStream _errServer;
private readonly TextReader _outClient;
private readonly TextReader _errClient;
// ReSharper disable UseObjectOrCollectionInitializer
private ConsoleRedirector(ILogListener logListener)
{
bool ret;
AnonymousPipeClientStream client;
_logListener = logListener;
_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
_stderr = GetStdHandle(STD_ERROR_HANDLE);
_sync = new Mutex();
_buffer = new char[BUFFER_SIZE];
_outServer = new AnonymousPipeServerStream(PipeDirection.Out);
client = new AnonymousPipeClientStream(PipeDirection.In,
_outServer.ClientSafePipeHandle);
//client.ReadTimeout = 0;
Debug.Assert(_outServer.IsConnected);
_outClient = new StreamReader(client, Encoding.Default);
ret = SetStdHandle(STD_OUTPUT_HANDLE, _outServer.SafePipeHandle.DangerousGetHandle());
Debug.Assert(ret);
_errServer = new AnonymousPipeServerStream(PipeDirection.Out);
client = new AnonymousPipeClientStream(PipeDirection.In,
_errServer.ClientSafePipeHandle);
//client.ReadTimeout = 0;
Debug.Assert(_errServer.IsConnected);
_errClient = new StreamReader(client, Encoding.Default);
ret = SetStdHandle(STD_ERROR_HANDLE, _errServer.SafePipeHandle.DangerousGetHandle());
Debug.Assert(ret);
Thread outThread = new Thread(doRead);
Thread errThread = new Thread(doRead);
outThread.Name = "stdout logger";
errThread.Name = "stderr logger";
outThread.Start(_outClient);
errThread.Start(_errClient);
_timer = new Timer(flush, null, PERIOD, PERIOD);
}
// ReSharper restore UseObjectOrCollectionInitializer
private void flush(object state)
{
_outServer.Flush();
_errServer.Flush();
}
private void doRead(object clientObj)
{
TextReader client = (TextReader)clientObj;
try
{
while (true)
{
int read = client.Read(_buffer, 0, BUFFER_SIZE);
if (read > 0)
//Console.WriteLine(" log :"+_buffer.ToString()+read);
_logListener.writeChars(_buffer, 0, read);
}
}
catch (ObjectDisposedException)
{
// Pipe was closed... terminate
}
}
public void Dispose()
{
Dispose(true);
}
~ConsoleRedirector()
{
Dispose(false);
}
// ReSharper disable InconsistentNaming
// ReSharper disable UnusedParameter.Local
// ReSharper disable EmptyGeneralCatchClause
private void Dispose(bool disposing)
{
if (!_isDisposed)
{
lock (_sync)
{
if (!_isDisposed)
{
_isDisposed = true;
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_timer.Dispose();
flush(null);
try { SetStdHandle(STD_OUTPUT_HANDLE, _stdout); }
catch (Exception) { }
_outClient.Dispose();
_outServer.Dispose();
try { SetStdHandle(STD_ERROR_HANDLE, _stderr); }
catch (Exception) { }
_errClient.Dispose();
_errServer.Dispose();
}
}
}
}
// ReSharper restore EmptyGeneralCatchClause
// ReSharper restore UnusedParameter.Local
// ReSharper restore InconsistentNaming
// ReSharper disable InconsistentNaming
private const int STD_OUTPUT_HANDLE = -11;
private const int STD_ERROR_HANDLE = -12;
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);
[DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(int nStdHandle);
// ReSharper restore InconsistentNaming
}
}