重定向的标准输入管道被创建的子进程忽略
Redirected stdin pipe being ignored by created child process
编辑:按照 Harry Johnston 的建议,解决方法是关闭 Child_In_Write 句柄。
有点讽刺的是,我早些时候曾尝试关闭 Child_In_Read 句柄。这不起作用,写入句柄是唯一应该关闭的句柄。
对于我正在尝试制作的工具,我需要能够启动一个进程并通过标准输入为其提供数据——就好像我是通过带有管道的命令行调用它一样
足够简单的想法。
I've primarily I've followed this guide from Microsoft and got things "working".
在我自己的测试程序中,我可以很好地读取标准输入。但是当我尝试使用其他程序时,例如 cat,它们除了挂起什么都不做——就好像它们还在等待输入一样。
相关代码位如下:
初始化管道。
// From Cao/Main.cpp
static HANDLE Child_In_Read = NULL;
static HANDLE Child_In_Write = NULL;
static HANDLE Child_Out_Read = NULL;
static HANDLE Child_Out_Write = NULL;
// Create and initialize standard in pipe.
{
bool createPipeSuccess =
CreatePipe(
&Child_In_Read,
&Child_In_Write,
&secAttr,
0);
if (!createPipeSuccess)
{
// @logging log error.
printf("Could not create standard in pipe!\n");
goto textData_cleanup;
}
bool setPipeFlagSuccess = SetHandleInformation(Child_In_Write, HANDLE_FLAG_INHERIT, 0);
if (!setPipeFlagSuccess)
{
// @logging log error.
printf("Could not set standard in pipe information!\n");
goto textData_cleanup;
}
}
写入刚刚初始化的管道,然后启动进程。
// From Cao/Main.cpp
// Write to the processes' standard in.
{
DWORD inBytesWritten = 0;
bool writeSuccess =
WriteFile(
Child_In_Write,
text, // Simple char array.
text_numBytes,
&inBytesWritten,
NULL);
if (!writeSuccess)
{
// @logging log error.
printf("Could not write to child's standard in!\n");
goto textData_cleanup;
}
}
// Create the child process.
{
STARTUPINFO startupInfo = { 0 };
startupInfo.cb = sizeof(startupInfo);
startupInfo.hStdInput = Child_In_Read;
startupInfo.hStdError = Child_Out_Write;
startupInfo.hStdOutput = Child_Out_Write;
startupInfo.dwFlags = STARTF_USESTDHANDLES;
bool createProcessSuccess = CreateProcessW(
NULL,
commandLine,
NULL,
NULL,
true,
0,
NULL,
NULL,
&startupInfo,
&ChildProcInfo);
if (!createProcessSuccess)
{
printf("Could not start child process with command line: %ls", commandLine);
goto textData_cleanup;
}
isChildRunning = true;
ModifyMenu(IconMenu, IconMenu_RunCancel, MF_BYCOMMAND, IconMenu_RunCancel, L"Cancel");
// newHandle is always 0x00000000 so I'm assuming I don't need to clean it up.
HANDLE newHandle;
RegisterWaitForSingleObject(&newHandle, ChildProcInfo.hProcess, LaunchedProcessExitedOrCancelled, NULL, INFINITE, WT_EXECUTEONLYONCE);
}
我的阅读代码似乎运行良好:
// From Echoer/Main.cpp
printf("via stdin:\n");
{
const int readBuffer_size = 5000;
char *readBuffer[readBuffer_size];
{
HANDLE standardIn = GetStdHandle(STD_INPUT_HANDLE);
DWORD bytesRead = 0;
bool readSuccess =
ReadFile(
standardIn,
readBuffer,
readBuffer_size,
&bytesRead,
NULL);
if (!readSuccess)
{
printf("Could not read from standard in!\n");
}
CloseHandle(standardIn);
}
printf("%s", readBuffer);
}
我是否遗漏了需要发送给 "get the ball rolling" 的内容?我需要附加“\r\n”或类似的东西吗? shell 如何管理它?
一些应用程序,包括 cat
,将在退出前等待标准输入 end-of-file。您可以通过关闭管道的末端来实现这一点。
(您还必须确保管道末端的句柄未被子进程或任何其他进程继承,但您的代码已经正确处理了这一点。)
编辑:按照 Harry Johnston 的建议,解决方法是关闭 Child_In_Write 句柄。
有点讽刺的是,我早些时候曾尝试关闭 Child_In_Read 句柄。这不起作用,写入句柄是唯一应该关闭的句柄。
对于我正在尝试制作的工具,我需要能够启动一个进程并通过标准输入为其提供数据——就好像我是通过带有管道的命令行调用它一样
足够简单的想法。 I've primarily I've followed this guide from Microsoft and got things "working". 在我自己的测试程序中,我可以很好地读取标准输入。但是当我尝试使用其他程序时,例如 cat,它们除了挂起什么都不做——就好像它们还在等待输入一样。
相关代码位如下:
初始化管道。
// From Cao/Main.cpp
static HANDLE Child_In_Read = NULL;
static HANDLE Child_In_Write = NULL;
static HANDLE Child_Out_Read = NULL;
static HANDLE Child_Out_Write = NULL;
// Create and initialize standard in pipe.
{
bool createPipeSuccess =
CreatePipe(
&Child_In_Read,
&Child_In_Write,
&secAttr,
0);
if (!createPipeSuccess)
{
// @logging log error.
printf("Could not create standard in pipe!\n");
goto textData_cleanup;
}
bool setPipeFlagSuccess = SetHandleInformation(Child_In_Write, HANDLE_FLAG_INHERIT, 0);
if (!setPipeFlagSuccess)
{
// @logging log error.
printf("Could not set standard in pipe information!\n");
goto textData_cleanup;
}
}
写入刚刚初始化的管道,然后启动进程。
// From Cao/Main.cpp
// Write to the processes' standard in.
{
DWORD inBytesWritten = 0;
bool writeSuccess =
WriteFile(
Child_In_Write,
text, // Simple char array.
text_numBytes,
&inBytesWritten,
NULL);
if (!writeSuccess)
{
// @logging log error.
printf("Could not write to child's standard in!\n");
goto textData_cleanup;
}
}
// Create the child process.
{
STARTUPINFO startupInfo = { 0 };
startupInfo.cb = sizeof(startupInfo);
startupInfo.hStdInput = Child_In_Read;
startupInfo.hStdError = Child_Out_Write;
startupInfo.hStdOutput = Child_Out_Write;
startupInfo.dwFlags = STARTF_USESTDHANDLES;
bool createProcessSuccess = CreateProcessW(
NULL,
commandLine,
NULL,
NULL,
true,
0,
NULL,
NULL,
&startupInfo,
&ChildProcInfo);
if (!createProcessSuccess)
{
printf("Could not start child process with command line: %ls", commandLine);
goto textData_cleanup;
}
isChildRunning = true;
ModifyMenu(IconMenu, IconMenu_RunCancel, MF_BYCOMMAND, IconMenu_RunCancel, L"Cancel");
// newHandle is always 0x00000000 so I'm assuming I don't need to clean it up.
HANDLE newHandle;
RegisterWaitForSingleObject(&newHandle, ChildProcInfo.hProcess, LaunchedProcessExitedOrCancelled, NULL, INFINITE, WT_EXECUTEONLYONCE);
}
我的阅读代码似乎运行良好:
// From Echoer/Main.cpp
printf("via stdin:\n");
{
const int readBuffer_size = 5000;
char *readBuffer[readBuffer_size];
{
HANDLE standardIn = GetStdHandle(STD_INPUT_HANDLE);
DWORD bytesRead = 0;
bool readSuccess =
ReadFile(
standardIn,
readBuffer,
readBuffer_size,
&bytesRead,
NULL);
if (!readSuccess)
{
printf("Could not read from standard in!\n");
}
CloseHandle(standardIn);
}
printf("%s", readBuffer);
}
我是否遗漏了需要发送给 "get the ball rolling" 的内容?我需要附加“\r\n”或类似的东西吗? shell 如何管理它?
一些应用程序,包括 cat
,将在退出前等待标准输入 end-of-file。您可以通过关闭管道的末端来实现这一点。
(您还必须确保管道末端的句柄未被子进程或任何其他进程继承,但您的代码已经正确处理了这一点。)