【发布时间】:2014-07-24 23:11:43
【问题描述】:
我正在尝试捕获子进程的输出(stdout/stderr),特别是如果它异常退出,我可能会得到一些有用的错误输出。
我创建了一个输出文件,并将这个(和STARTF_USESTDHANDLES)设置在我随后传递给CreateProcess() 的STARTUPINFO 结构上。
现在,对于我的子进程中的不同操作,我得到以下行为:
(1) 无冲洗
printf("Hello world!\n");
结果:在子级从父级终止后(通过TerminateProcess):文件中没有输出。
(2) 在每次printf 调用后使用fflsuh()
printf("Hello world!\n");
fflush(stdout);
结果:在子级从父级终止后(通过TerminateProcess):“Hello World!” (如预期)
(3)异常终止
printf("Hello world!\n");
int *p = NULL; *p = 5; // Access violation
结果:文件中没有输出。
我可以尝试在每个printf() 之后添加fflush() 调用(糟糕!),或者尝试获得TerminateProcess() 的替代方法,以确保首先关闭文件句柄。但这对异常退出无济于事——这是首先要捕获 stdout/stderr 的要点。
我尝试的另一件事是创建带有FILE_FLAG_NO_BUFFERING 标志集的文件,但我的尝试不起作用 - CreateFile() 失败(错误 87“参数不正确”)。知道我做错了什么吗?或者是否有其他方法可以实现这一目标?
我已经为 CreateFile() dwFlagsAndAttributes 值尝试了 3 种不同的选项,结果如下。
FILE_ATTRIBUTE_NORMAL- 文件创建正常,但出现上述行为(因此我错过了异常终止的数据)。FILE_FLAG_NO_BUFFERING或FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING-CreateFile()失败,GetLastError= 87 和FormatMessage返回“参数不正确”。我只是在这里错误地使用了标志吗?还是我的文件系统不支持此选项?
这是我用来创建输出文件和子进程的代码。我已经在下面标记了我已经为 CreateFile() dwFlagsAndAttributes 值尝试了几个不同的选项。
SECURITY_ATTRIBUTES security = {sizeof(SECURITY_ATTRIBUTES), NULL, true}; // Allow the handle to be inherited by child process
HANDLE myfile = CreateFile(myfilename,
FILE_APPEND_DATA,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
&security,
OPEN_ALWAYS,
FILE_FLAG_NO_BUFFERING, // I've tried 3 different things here - see above
NULL);
STARTUPINFO startupInfo = {0};
startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
startupInfo.wShowWindow = SW_HIDE;
startupInfo.hStdError = myfile;
startupInfo.hStdOutput = myfile;
PROCESS_INFORMATION processInfo = {0};
CreateProcess(NULL,
executable,
NULL, NULL,
true, // Allow stdout/err file handle to be inherited
0, NULL, NULL,
&startupInfo,
&processInfo))
CloseHandle(myfile); // The child owns this now
感谢您的帮助!
【问题讨论】:
-
使用 FILE_FLAG_NO_BUFFERING 选项时存在对齐约束。请参阅msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx 一种推荐的解决方案是使用 VirtualAlloc 来分配缓冲区。虽然这不能解释为什么你会在 CreateFile 中收到错误。
-
其他网站提到访问参数也可能是原因。将 FILE_APPEND_DATA 替换为 GENERIC_READ | 会发生什么? GENERIC_WRITE?
-
如果您想通过 CRT 禁用缓冲,请致电
setvbuf(stdout, NULL, _IONBF, 0)。这大致相当于在每次输出调用后调用fflush。 -
FILE_FLAG_NO_BUFFERING标志用于当您担心操作系统可能崩溃或计算机可能会断电时。如果您只是担心进程崩溃,则没有必要。您需要按照 Igor 的建议关闭 CRT 缓冲。 -
感谢 Igor 和 Harry - 删除
NO_BUFFERING标志并按照建议使用setvbuf似乎有效。我仍然没有从异常中得到任何输出,但我认为这是因为我得到了一个 Windows“程序已停止工作”错误对话框,所以这是一个单独的问题。