Windows C++:如何重定向 stderr 以调用 fprintf?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7664/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Windows C++: How can I redirect stderr for calls to fprintf?
提问by jkp
I am wrapping existing C++ code from a BSDproject in our own custom wrapper and I want to integrate it to our code with as few changes as possible. This code uses fprintf
to print to stderrin order to log / report errors.
我正在将来自BSD项目的现有 C++ 代码包装在我们自己的自定义包装器中,并且我希望以尽可能少的更改将其集成到我们的代码中。此代码用于fprintf
打印到stderr以记录/报告错误。
I want to redirect this to an alternative place within the same process. On UnixI have done this with a socketpair
and a thread
: one end of the socket is where I send stderr(via a call to dup2
) and the other end is monitored in a thread, where I can then process the output.
我想将其重定向到同一进程中的另一个位置。在Unix 上,我使用 asocketpair
和 a完成了此操作thread
:套接字的一端是我发送stderr(通过调用dup2
)的地方,另一端在线程中受到监视,然后我可以在其中处理输出。
This does not work on Windowsthough because a socket is not the same as a file handle.
这在Windows 上不起作用,因为套接字与文件句柄不同。
All documents I have found on the web show how to redirect output from a child process, which is not what I want. How can I redirect stderrwithin the same process getting a callback of some sort when output is written? (and before you say so, I've tried SetStdHandle
but cannot find any way to make this work)...
我在网上找到的所有文档都展示了如何重定向子进程的输出,这不是我想要的。如何在写入输出时在同一进程中重定向stderr以获得某种回调?(在你这么说之前,我已经尝试过SetStdHandle
但找不到任何方法来完成这项工作)......
采纳答案by Greg Hewgill
You can use a similar technique on Windows, you just need to use different words for the same concepts. :) This article: http://msdn.microsoft.com/en-us/library/ms682499.aspxuses a win32 pipe to handle I/O from another process, you just have to do the same thing with threads within the same process. Of course, in your case all output to stderr from anywhere in the process will be redirected to your consumer.
您可以在 Windows 上使用类似的技术,您只需要为相同的概念使用不同的词。:) 这篇文章:http: //msdn.microsoft.com/en-us/library/ms682499.aspx使用 win32 管道来处理来自另一个进程的 I/O,您只需要对同一进程中的线程执行相同的操作过程。当然,在您的情况下,从流程中任何地方到 stderr 的所有输出都将重定向到您的使用者。
Actually, other pieces of the puzzle you may need are _fdopenand _open_osfhandle. In fact, here's a related example from some codeI released years ago:
实际上,您可能需要的其他拼图是_fdopen和_open_osfhandle。事实上,这是我多年前发布的一些代码中的一个相关示例:
DWORD CALLBACK DoDebugThread(void *)
{
AllocConsole();
SetConsoleTitle("Copilot Debugger");
// The following is a really disgusting hack to make stdin and stdout attach
// to the newly created console using the MSVC++ libraries. I hope other
// operating systems don't need this kind of kludge.. :)
stdout->_file = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
stdin->_file = _open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT);
debug();
stdout->_file = -1;
stdin->_file = -1;
FreeConsole();
CPU_run();
return 0;
}
In this case, the main process was a GUI process which doesn't start with stdio handles at all. It opens a console, then shoves the right handles into stdout and stdin so the debug() function (which was designed as a stdio interactive function) can interact with the newly created console. You should be able to open some pipes and do the same sort of thing to redirect stderr.
在这种情况下,主进程是一个 GUI 进程,它根本不以 stdio 句柄开始。它打开一个控制台,然后将正确的句柄推入 stdout 和 stdin,以便 debug() 函数(它被设计为 stdio 交互函数)可以与新创建的控制台交互。您应该能够打开一些管道并执行相同的操作来重定向 stderr。
回答by Greg Hewgill
You have to remember that what MSVCRT calls "OS handles" are not Win32 handles, but another layer of handles added just to confuse you. MSVCRT tries to emulate the Unix handle numbers where stdin
= 0, stdout
= 1, stderr
= 2 and so on. Win32 handles are numbered differently and their values always happen to be a multiple of 4. Opening the pipe and getting all the handles configured properly will require getting your hands messy. Using the MSVCRT source code and a debugger is probably a requirement.
您必须记住,MSVCRT 所称的“操作系统句柄”不是 Win32 句柄,而是添加的另一层句柄只是为了让您感到困惑。MSVCRT 尝试模拟 Unix 句柄编号,其中stdin
= 0、stdout
= 1、stderr
= 2 等等。Win32 句柄的编号不同,它们的值总是碰巧是 4 的倍数。打开管道并正确配置所有句柄将需要弄乱您的手。可能需要使用 MSVCRT 源代码和调试器。
回答by Len Holgate
You mention that you don't want to use a named pipe for internal use; it's probably worth poining out that the documentation for CreatePipe()states, "Anonymous pipes are implemented using a named pipe with a unique name. Therefore, you can often pass a handle to an anonymous pipe to a function that requires a handle to a named pipe."So, I suggest that you just write a function that creates a similar pipe with the correct settings for async reading. I tend to use a GUID as a string (generated using CoCreateGUID()
and StringFromIID()
) to give me a unique name and then create the server and client ends of the named pipe with the correct settings for overlapped I/O (more details on this, and code, here: http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html).
您提到您不想将命名管道用于内部使用;可能值得指出的是,CreatePipe()的文档指出,“匿名管道是使用具有唯一名称的命名管道实现的。因此,您通常可以将匿名管道的句柄传递给需要命名管道句柄的函数。管道。” 因此,我建议您只编写一个函数来创建一个类似的管道,该管道具有正确的异步读取设置。我倾向于使用 GUID 作为字符串(使用CoCreateGUID()
和生成StringFromIID()
)来给我一个唯一的名称,然后使用重叠 I/O 的正确设置创建命名管道的服务器端和客户端(有关此的更多详细信息和代码,这里: http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html)。
Once I have that I wire up some code that I have to read a file using overlapped I/O with an I/O Completion Port and, well, then I just get async notifications of the data as it arrives... However, I've got a fair amount of well tested library code in there that makes it all happen...
一旦我连接了一些代码,我必须使用带有 I/O 完成端口的重叠 I/O 读取文件,然后我只是在数据到达时收到异步通知......但是,我那里有大量经过良好测试的库代码,可以让这一切发生......
It's probably possible to set up the named pipe and then just do an overlapped read with an event in your OVERLAPPED
structure and check the event to see if data was available... I don't have any code available that does that though.
可能可以设置命名管道,然后只对OVERLAPPED
结构中的事件进行重叠读取,并检查事件以查看数据是否可用......不过我没有任何可用的代码可以做到这一点。