我的问题已经在其他答案中得到了很好的解释。
控制台应用程序使用名为
isatty()
的函数来检测它们的
stdout
处理程序是否连接到管道或实际控制台。
如果是管道,所有输出都会被缓冲并以块方式刷新,除非直接调用
fflush()
。如果是实际控制台,则输出是不带缓冲区的,并直接打印到控制台输出。
在Linux中,您可以使用
openpty()
创建一个伪终端,并在其中创建进程。结果,该进程将认为它在实际终端上运行并使用不带缓冲区的输出。
Windows似乎没有这样的选项。
经过大量查阅winapi文档,我发现这是
不正确的。实际上,您可以创建自己的控制台屏幕缓冲区,并将其用于进程的
stdout
,然后该输出将不带缓冲区。
可惜这不是一个非常舒适的解决方案,因为没有事件处理程序,我们需要轮询新数据。此外,目前我不确定如何处理当此屏幕缓冲区满时的滚动。
但是即使还有一些问题没有解决,我认为我已经为那些曾经想要获取未缓冲(未刷新)的Windows控制台进程输出的人创建了一个非常有用(且有趣)的起点。
#include <windows.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
char cmdline[] = "application.exe";
HANDLE scrBuff;
CONSOLE_SCREEN_BUFFER_INFO scrBuffInfo;
COORD scrBuffSize = {80, 25};
SECURITY_ATTRIBUTES sa;
PROCESS_INFORMATION procInfo;
STARTUPINFO startInfo;
DWORD procExitCode;
DWORD NumberOfCharsWritten;
COORD pos = {0, 0};
bool quit = false;
sa.nLength = sizeof(sa);
scrBuff = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa, CONSOLE_TEXTMODE_BUFFER, NULL);
SetConsoleScreenBufferSize(scrBuff, scrBuffSize);
FillConsoleOutputCharacter(scrBuff, '\0', scrBuffSize.X * scrBuffSize.Y,
pos, &NumberOfCharsWritten);
ZeroMemory(&procInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&startInfo, sizeof(STARTUPINFO));
startInfo.cb = sizeof(STARTUPINFO);
startInfo.hStdOutput = scrBuff;
startInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
startInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
startInfo.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess(NULL, cmdline, NULL, NULL, FALSE,
0, NULL, NULL, &startInfo, &procInfo);
CloseHandle(procInfo.hThread);
while(!quit)
{
GetExitCodeProcess(procInfo.hProcess, &procExitCode);
if(procExitCode != STILL_ACTIVE) quit = true;
GetConsoleScreenBufferInfo(scrBuff, &scrBuffInfo);
if (pos.X != scrBuffInfo.dwCursorPosition.X ||
pos.Y != scrBuffInfo.dwCursorPosition.Y)
{
DWORD len = (scrBuffInfo.dwCursorPosition.Y - pos.Y)
* scrBuffInfo.dwSize.X
+(scrBuffInfo.dwCursorPosition.X - pos.X);
char buffer[len];
ReadConsoleOutputCharacter(scrBuff, buffer, len, pos, &len);
for(int i = 0; i < len; i++)
{
if(buffer[i] != '\0') printf("%c",buffer[i]);
else
{
printf("\n");
while((i + 1) < len && buffer[i + 1] == '\0')i++;
}
}
pos = scrBuffInfo.dwCursorPosition;
}
else Sleep(100);
}
CloseHandle(scrBuff);
CloseHandle(procInfo.hProcess);
return 0;
}
while (!feof(pipe))
是错误的。 - too honest for this site