从 C# 中重定向本机 dll stdout/stderr

发布于 2024-08-05 09:30:31 字数 1097 浏览 4 评论 0原文

我正在尝试重定向第三方本机 dll 的输出,该 dll 从 C# 内输出到 stdout/stderr。 stdout 和 stderr 的输出都应保存到日志文件中。

这是我的想法(两个流 x2):

  • 创建一个 AnonymousPipeServerStream
  • 通过_outServer.SafePipeHandle.DangerousGetHandle()获取管道的句柄
  • 使用P/Invoke调用SetStdHandle 与所述句柄
  • 创建一个 AnonymousPipeClientStream 连接到服务器流
  • 创建一个线程以循环读取 AnonymousPipeClientStream 并输出到记录器。
  • 定期在 AnonymousPipeServerStream 上调用 flush

因此,这一切似乎在我的代码中运行良好。一旦控制权传递到本机 DLL,一切都会返回到 stderr!如果需要的话,我可以调试到本机 DLL 中,看看出了什么问题,但是......我真的不想,所以在我花 10 个小时试图弄清楚句柄如何工作之前,有人有任何想法吗?

作为参考,测试代码位于:http://pastebin.com/f3eda7c8。有趣的是构造函数中的第 58-89 行。 (当然,我稍后会添加错误处理等)。

I'm trying to redirect the output of a third-party native dll which outputs to stdout/stderr from within C#. The output of both stdout and stderr should go to a log file.

Here's my idea (x2 for two streams):

  • Create an AnonymousPipeServerStream
  • Get the pipe's handle via _outServer.SafePipeHandle.DangerousGetHandle()
  • Use P/Invoke to call SetStdHandle with said handle
  • Create an AnonymousPipeClientStream connected to the server stream
  • Create a thread to sit in a loop reading from the AnonymousPipeClientStream and outputting to the logger.
  • Periodically call flush on the AnonymousPipeServerStream

So all this seems to be working well... within my code. As soon as control passes to the native DLL, everything goes back to stderr! If need be, I can debug into the native DLL and see what's going wrong, but... I'd really rather not, so does anyone have any ideas before I spend 10 hours trying to figure out how handles work?

For reference, the test code is at: http://pastebin.com/f3eda7c8. The interesting stuff is lines 58-89 in the constructor. (I'll add error handling, etc. later, of course).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

难以启齿的温柔 2024-08-12 09:30:31

我解决了它,尽管解决方案(当然)与问题无关。该 dll 是在 mingw 中编译的,它显然不尊重 MSVC 运行时使用的句柄。

我会留下代码&解决方案以防其他人遇到此问题。

I solved it, though the solution (of course) has very little to do with the problem. The dll was compiled in mingw, which apparently doesn't respect the handles used by the MSVC runtime.

I'll leave the code & solution up in case anyone else encounters this problem.

沩ん囻菔务 2024-08-12 09:30:31

使用 https://pastebin.com/f3eda7c8 上的代码我已经让它在 Windows 10 上运行并且在 Windows LTSC 2019 容器内。但是,它仅捕获 C# 代码的控制台输出,而不捕获非托管 DLL 的 printf 输出的痕迹,而这正是我希望达到的结果。我必须在 SetStdHandle 分配之后使用下面的 hack 才能使其工作 - 顺便说一句,我不太喜欢这个 hack。

谁能告诉我,我缺少什么才能将 printf 输出重定向到源自本机 .DLL 的控制台?我需要在每个 [f]printf 语句后添加 fflush(stdout / stderr) 吗?或者只是在我有兴趣查看其输出返回的函数之前使用 fflush(stdout);fflush(stderr); ?事实上,我在容器输出中看到的行之后添加了几个 fflush(stdout); 调用,但这些本机 printf 信息都没有被重定向。

        private void _ResetConsoleOutStream()
        {
            //Force console to recreate its output stream the next time Write/WriteLine is called
            typeof(Console).GetField("_out", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)
                           .SetValue(null, null);
        }```

Using the code at https://pastebin.com/f3eda7c8 I've got it to work on Windows 10 and within a Windows LTSC 2019 container. However, it captures only the Console output of the C# code, not a trace of the unmanaged DLL's printf output which is the outcome that I desire to reach. I had to use the hack below after the SetStdHandle assignments in order to get it work - a hack that I do not really like BTW.

Could anyone please enlighten me on what is missing for me to get it to redirect the printf output to the Console that originates from the native .DLL? Do I need to add a fflush(stdout / stderr) after each [f]printf statement? Or just fflush(stdout); and fflush(stderr); before the function I'm interested in seeing its output returns? As a matter of fact I added a couple of fflush(stdout); calls after lines I am seeing in the container's output but none of those native printf pieces of information got redirected.

        private void _ResetConsoleOutStream()
        {
            //Force console to recreate its output stream the next time Write/WriteLine is called
            typeof(Console).GetField("_out", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)
                           .SetValue(null, null);
        }```
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文