我可以将C DLL的输出重定向到我的c#log4net输出

时间:2015-02-04 21:08:01

标签: c# c++ c dll log4net

我有一个C#应用程序,它反过来加载一个C或C ++ DLL(后者又加载其他C / C ++ dll)。在C#应用程序中,我使用log4net记录器将所有输出捕获到一系列日志文件中。我的应用程序作为Windows服务运行,因此没有正常printfs的控制台/输出窗口或写入stdout / stderr的输出。

有没有办法设置C#应用程序来引导stdout / stderr(来自DLL)并将每一行转换为log4net输出。或者在C / C ++ DLL中是否有某种方法将stdout / stderr流连接到log4net输出?

我找到了一些解决方案(这里:http://bytes.com/topic/c-sharp/answers/822341-dllimport-stdout-gets-eaten)表明我需要调用我的C DLL这样的调用:setvbuf(stdout, NULL, _IONBF, 0);虽然,我不知道它做了什么,但它没有做我想做的事。我想我也需要一个类似的stderr线。在任何一种情况下,谷歌似乎认为这些行只是处理缓冲而不是重定向到log4net。

我假设我需要某种功能覆盖,它会阻止控制台写入(从另一种语言加载的DLL)并将它们转换为mLog.InfoFormat("{0}", consoleString);种类的调用。我是c#的新手,甚至不确定google的哪些条款才能找到这样的覆盖(如果可能的话)。

不确定这是否会使问题复杂化,但我的C#应用​​程序是多线程的,并且一些DLL也有多个线程。我假设这只是意味着我需要在处理控制台输出的方法内部进行某种锁定并将其写入log4net框架(可能)或者正常的log4net序列化将为我处理它。

1 个答案:

答案 0 :(得分:1)

在我弄清楚如何使用它们之后,结果证明了这些技巧。我设置了两个命名管道(或同一管道的两端?)。一个我连接到stdout并让它在log4net中执行任何来自管道的日志消息。

internal static void InfoLogWriter(Object threadContext)
{
    mLog.Info("InfoLogWriterthread started");
    int id = Process.GetCurrentProcess().Id; // make this instance unique
    var serverPipe = new NamedPipeServerStream("consoleRedirect" + id, PipeDirection.In, 1);
    NamedPipeClientStream clientPipe = new NamedPipeClientStream(".", "consoleRedirect" + id, PipeDirection.Out, PipeOptions.WriteThrough);
    mLog.Info("Connecting Client Pipe.");
    clientPipe.Connect();
    mLog.Info("Connected Client Pipe, redirecting stdout");
    HandleRef hr11 = new HandleRef(clientPipe, clientPipe.SafePipeHandle.DangerousGetHandle());
    SetStdHandle(-11, hr11.Handle); // redirect stdout to my pipe
    mLog.Info("Redirection of stdout complete.");
    mLog.Info("Waiting for console connection");
    serverPipe.WaitForConnection(); //blocking
    mLog.Info("Console connection made.");
    using (var stm = new StreamReader(serverPipe))
    {
        while (serverPipe.IsConnected)
        {
            try
            {
                string txt = stm.ReadLine();
                if (!string.IsNullOrEmpty(txt))
                    mLog.InfoFormat("DLL MESSAGE : {0}", txt);
            }
            catch (IOException)
            {
                break; // normal disconnect
            }
        }
    }
    mLog.Info("Console connection broken.   Thread Stopping.");
}

还有一个函数可以将所有内容推送到另一个线程,这样当它遇到各种阻塞调用时它就不会阻塞我的主线程。

internal static void RedirectConsole()
{
    mLog.Info("RedirectConsole called.");
    ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(InfoLogWriter));
    // TODO enqueue and item for error messages too.
}

我无法断开连接并且必须重新连接管道,但我会找出一个重新连接解决方​​案。我猜这种情况发生在DLL被换回内存时,或者当我需要阅读时,但目前还没有任何东西可以读取?我还需要设置另一对来阻止stderr并重定向它,使用错误日志。可能想摆脱幻数(-11)并使用正常的枚举(STD_ERROR_HANDLE等)