直接调用p.exe无stdout输出,经bat中转则正常,求原因
问题分析与解决方案
核心原因推测
直接调用p.exe无输出,通过bat中转却正常,大概率是以下几个因素共同作用:
- 输入缺少换行符:手动输入时实际传递的是
hello\r\n(回车+换行),但你的测试代码仅写入了hello,p.exe可能需要换行符才会触发输入处理逻辑。 - stdio缓冲机制差异:当
p.exe的stdout连接到管道时,C/C++默认的stdio会从行缓冲切换为全缓冲,输出内容会被暂存,直到缓冲区满或程序退出才会刷新到管道;而通过bat中转时,p.exe的stdout指向控制台,行缓冲生效,输出会立即刷新。 - 输入管道未发送EOF信号:
p.exe可能在等待输入结束的EOF信号,才会完成处理并输出结果;bat中转时,echo命令发送完内容后会自动关闭输入流,触发EOF。
具体修复步骤
1. 补充输入换行符
修改测试代码中写入的内容,添加Windows标准换行符\r\n:
std::string data = "hello\r\n"; // 替换原有的"hello" DWORD dwWritten; bool result = WriteFile(hStdInPipeWrite, data.c_str(), data.length(), &dwWritten, NULL);
2. 关闭输入管道触发EOF
在写入数据后,关闭输入管道的写端,让p.exe感知到输入已结束:
// 写入数据后立即关闭输入管道 CloseHandle(hStdInPipeWrite);
3. 等待进程处理完成
ReadFile默认是阻塞调用,但需要确保p.exe有足够时间处理输入并输出结果,添加进程等待逻辑:
// 等待子进程处理完成再读取输出 WaitForSingleObject(pi.hProcess, INFINITE);
4. (可选)修改p.exe的缓冲设置
如果有权限修改p.exe的源码,可在程序开头添加缓冲配置,强制关闭stdio缓冲:
#include <stdio.h> int main() { setvbuf(stdout, NULL, _IONBF, 0); // 关闭stdout缓冲 setvbuf(stdin, NULL, _IONBF, 0); // 关闭stdin缓冲 // 原有业务逻辑... }
或者在每次输出后调用fflush(stdout);,确保内容立即写入管道。
验证修改后的完整测试代码
TEST_METHOD(SO_TEST) { std::string path = "p.exe"; HANDLE hStdInPipeWrite; HANDLE hStdOutPipeRead; SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; HANDLE hStdInPipeRead = NULL; HANDLE hStdOutPipeWrite = NULL; if (!CreatePipe(&hStdInPipeRead, &hStdInPipeWrite, &sa, 0) || !CreatePipe(&hStdOutPipeRead, &hStdOutPipeWrite, &sa, 0)) { abort(); } SetHandleInformation(hStdInPipeWrite, HANDLE_FLAG_INHERIT, 0); SetHandleInformation(hStdOutPipeRead, HANDLE_FLAG_INHERIT, 0); STARTUPINFOA si = {}; si.cb = sizeof(STARTUPINFO); si.dwFlags |= STARTF_USESTDHANDLES; si.hStdError = hStdOutPipeWrite; si.hStdOutput = hStdOutPipeWrite; si.hStdInput = hStdInPipeRead; PROCESS_INFORMATION pi = {}; if (!CreateProcessA(NULL, const_cast<char*>(path.c_str()), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { DWORD lastError = GetLastError(); abort(); } // 关闭子进程持有的管道端 CloseHandle(hStdOutPipeWrite); CloseHandle(hStdInPipeRead); // 写入带换行的输入 std::string data = "hello\r\n"; DWORD dwWritten; WriteFile(hStdInPipeWrite, data.c_str(), data.length(), &dwWritten, NULL); // 关闭输入管道触发EOF CloseHandle(hStdInPipeWrite); // 等待子进程处理完成 WaitForSingleObject(pi.hProcess, INFINITE); // 读取输出 char buf[1024 + 1]; DWORD dwRead; if (ReadFile(hStdOutPipeRead, buf, 1024, &dwRead, NULL)) { buf[dwRead] = '\0'; } // 清理资源 CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(hStdOutPipeRead); }
内容的提问来源于stack exchange,提问作者Casper Thule Hansen
相关产品推荐
相关产品推荐

