我在WinMain中有以下片段,我从控制台启动这个GUI应用程序。我想将输出重定向到启动我的应用程序的控制台。我得到“句柄无效”。 GetStdHandle()之后的错误。
但是,如果我使用AllocConsole而不是AttachConsole,它可以正常工作。另外,如果我使用STD_ERROR_HANDLE而不是STD_OUTPUTHANDLE,那么fprintf(stderr,“errror”)工作正常。
我看到一个博客条目有同样的问题,但没有解决方案。我在64位Windows 7上使用vc 2010编译器。
谢谢!
bConsole = AttachConsole(ATTACH_PARENT_PROCESS) != FALSE;
if (bConsole)
{
int fd = 0;
long lStdOut;
lStdOut = (long)GetStdHandle(STD_OUTPUT_HANDLE);
fd = _open_osfhandle(lStdOut, _O_TEXT);
if (fd > 0)
{
*stdout = *_fdopen(fd, "w");
setvbuf(stdout, NULL, _IONBF, 0 );
}
}
printf("Test!!!!!!!!!!!!");
答案 0 :(得分:6)
AttachConsole
确实将您的流程与控制台相关联,但stdout
已经打开(并连接到旧句柄,无论它是什么)。
直接覆盖stdout
是个糟糕的主意。相反,您必须freopen("CONOUT$", "w", stdout);
才能stdout
进入控制台。
但是还有很多其他细节。请查看我的问题Where do writes to stdout go when launched from a cygwin shell, no redirection,其中涵盖了您在问题中的问题,然后询问有关某些角落案例的问题。最后是一个包含所有内容的代码示例。
答案 1 :(得分:5)
Windows子系统进程(即具有WinMain
的进程)将没有STDOUT,STDERR或STDIN,除非在发布时专门给出了一个。假设是因为它是一个Windows程序,你通过Windows与它进行交互。
即。 GetStdHandle没有返回STDOUT的句柄,因为你没有STDOUT。
为了给它一个,启动它:
winprog.exe > output.txt 2>&1
如果以这种方式启动,它将同时具有STDOUT和STDERR,它们都将进入命名文件。
正如其他用户已经指出的那样,AttachConsole将为您提供一个控制台(最近的unix / linux等价物是一个TTY),但它不会给你一个STDOUT。如果您需要,则必须将其设置为单独的步骤。如果你想让它成为控制台,你也可以拥有它。
另一方面,控制台子系统程序(具有main
的程序)默认情况下将STDIN,STDOUT和STDERR都设置为控制台。您可以从控制台分离进程,并根据需要关闭它们。
答案 2 :(得分:2)
我将以下代码添加到默认的Visual Studio C ++ GUI项目中,就在WinMain
的开头。
if (AttachConsole(ATTACH_PARENT_PROCESS))
{
if (GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE)
MessageBox(0, L"Invalid Handle", NULL, 0);
else
MessageBox(0, L"Valid Handle", NULL, 0);
}
当我从调试器或资源管理器运行GUI程序时,不会显示任何消息框。换句话说,我们无法附加控制台。当我从cmd运行时,我看到“有效处理”消息。
我的结论是,这种基本方法实际上没有任何问题,但是你没有向我们展示的东西导致了这个问题。
答案 3 :(得分:0)
我认为你的问题在这里:
long lStdOut;
lStdOut = (long)GetStdHandle(STD_OUTPUT_HANDLE);
fd = _open_osfhandle(lStdOut, _O_TEXT);
我对Win32 API不太满意,但我认为句柄有自己的HANDLE
类型,我认为它们本质上是指针,而Win64则是64位。由于某种原因,Win64中的long
类型仍然是32位。
这是MSDN的声明:
HANDLE WINAPI GetStdHandle(
__in DWORD nStdHandle
);
_open_osfhandle声明:
int _open_osfhandle (
intptr_t osfhandle,
int flags
);
答案 4 :(得分:0)
要将输出重定向到控制台,请使用以下代码:
AllocConsole();
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
然后您可以使用 WriteFile()写入控制台。
WriteFile(
hConsole,
L"this is a debug line\n",
21, // string length
NULL, // bytes written
NULL);