[英]Redirect Input\Output pipes from parent process to cmd child process C/C++ WinApi
I have been trying to run a parent process that acts like a cmd input\output console.我一直在尝试运行一个类似于 cmd 输入\输出控制台的父进程。 the purpose of this is for future use, but for now I am trying to isolate this function in order to get things right.
这样做的目的是为了将来使用,但现在我正在尝试隔离这个 function 以使事情正确。
What I am trying to achieve here is an input from user send it to a simple cmd child process, get the output and keep on sending commands, while keeping the process running.The problem is that the cmd process closes right after the first command is executed.我在这里想要实现的是用户的输入将其发送到一个简单的 cmd 子进程,获取 output 并继续发送命令,同时保持进程运行。问题是 ZDFFF0A7FA1A55C8C45A4966C19ZFDA 进程在第一个命令之后关闭执行。 I pasted an output of what happens right after the first command,the issue that rises once I try to keep on going and inputting more commands is that the handle is not valid (since the process is terminated).
我粘贴了 output 在第一个命令之后发生的事情,一旦我尝试继续输入更多命令,就会出现的问题是句柄无效(因为进程终止)。
Help would be much appreciated!帮助将不胜感激!
Main code:主要代码:
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>
#include <strsafe.h>
#define bzero(p,size) (void) memset((p), 0 , (size))
// Constant
#define BUFSIZE 4096
// Global variables
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE g_hInputFile = NULL;
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
PROCESS_INFORMATION CreateChildProcess()
{
// The following should be the child executable, see the next program example
// Change the path accordingly...
WCHAR szCmdline[] = L"cmd.exe";
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bSuccess = FALSE;
// Set up members of the PROCESS_INFORMATION structure
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure
// This structure specifies the STDIN and STDOUT handles for redirection
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process
bSuccess = CreateProcess(NULL, // Use szCmdLine
szCmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
CREATE_NEW_CONSOLE, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
// If an error occurs, exit the application.
if (!bSuccess)
printf("Error creating process, %d\n", GetLastError());
else
{
wprintf(L"\nChild process ID is : %u\n", GetCurrentProcessId());
wprintf(L"Child thread ID is : %u\n", GetCurrentThreadId());
/*
if (CloseHandle(piProcInfo.hProcess) != 0)
wprintf(L"piProcInfo.hProcess handle was closed!\n");
else
printf("Error closing process , %d\n", GetLastError());
if (CloseHandle(piProcInfo.hThread) != 0)
wprintf(L"piProcInfo.hThread handle was closed!\n");
else
printf("Error closing process thread handle, %d\n", GetLastError());
*/
}
return piProcInfo;
}
void WriteToPipe(char * command)
{
DWORD dwWritten;
DWORD dwRead;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
bSuccess = WriteFile(g_hChildStd_IN_Wr, (LPVOID)command , (DWORD)strlen(command), &dwWritten, NULL);
printf("Command: %s\n", command);
if (!bSuccess)
{
wprintf(L"\nWriteFile() - Failed to write to pipe for child\'s STDIN! Error %u\n", GetLastError());
//break;
}
else
wprintf(L"\nWriteFile() - writing to the pipe for the child\'s STDIN...\n");
// Close the pipe handle so the child process stops reading
if (!CloseHandle(g_hChildStd_IN_Wr))
printf("Error closing STDIN handle, %d\n", GetLastError());
else
wprintf(L"Closing the pipe handle...\n");
//Read from pipe
bSuccess = FALSE;
bzero(chBuf, sizeof(chBuf));
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (!CloseHandle(g_hChildStd_OUT_Wr))
printf("Error closing STDOUT handle, %d\n", GetLastError());
for (;;)
{
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if (!bSuccess || dwRead == 0)
{
wprintf(L"\nReadFile() from child's standard output failed! Error %u\n", GetLastError());
break;
}
bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
if (!bSuccess)
{
wprintf(L"\nWriteFile() to parent's standard output failed! Error %u\n", GetLastError());
break;
}
}
}
int main()
{
PROCESS_INFORMATION pi;
char filename[100];
ZeroMemory(&filename, sizeof(filename));
strcpy(filename, "commands.txt");
SECURITY_ATTRIBUTES saAttr;
wprintf(L"Parent process ID %u\n", GetCurrentProcessId());
// Set the bInheritHandle flag so pipe handles are inherited
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
printf("Create pipe for STDOUT failed,%d\n", GetLastError());
else
wprintf(L"CreatePipe() - pipe for child process\'s STDOUT pipe was created!\n");
// Ensure the read handle to the pipe for STDOUT is not inherited
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
printf("Create handle for STDOUT failed,%d\n", GetLastError());
else
wprintf(L"SetHandleInformation() - pipe STDOUT read handle is not inherited!\n");
// Create a pipe for the child process's STDIN
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
printf("Create pipe for STDIN failed,%d\n", GetLastError());
else
wprintf(L"CreatePipe() - pipe for child process\'s STDIN was created!\n");
// Ensure the write handle to the pipe for STDIN is not inherited
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
printf("Error getting handle on STDIN,%d\n", GetLastError());
else
wprintf(L"Stdin SetHandleInformation() - pipe STDIN read handle is not inherited!\n");
// Create the child process
wprintf(L"Creating the child process...\n");
pi = CreateChildProcess();
char chr[1000];
for (;;)
{
bzero(chr, sizeof(chr));
printf("Enter a character: ");
scanf("%s", chr);
strcat(chr, "\n");
if(strncmp(chr,"exit",4) == 0)
break;
WriteToPipe(chr);
}
if (CloseHandle(pi.hProcess) != 0)
wprintf(L"piProcInfo.hProcess handle was closed!\n");
else
printf("Error closing process , %d\n", GetLastError());
if (CloseHandle(pi.hThread) != 0)
wprintf(L"piProcInfo.hThread handle was closed!\n");
else
printf("Error closing process thread handle, %d\n", GetLastError());
printf("End of parent execution.\n");
return 0;
}
Output: Output:
Parent process ID 10580
CreatePipe() - pipe for child process's STDOUT pipe was created!
SetHandleInformation() - pipe STDOUT read handle is not inherited!
CreatePipe() - pipe for child process's STDIN was created!
Stdin SetHandleInformation() - pipe STDIN read handle is not inherited!
Creating the child process...
Child process ID is : 10580
Child thread ID is : 1880
Enter a character: whoami
Command: whoami
WriteFile() - writing to the pipe for the child's STDIN...
Closing the pipe handle...
Microsoft Windows [Version 10.0.18363.836]
(c) 2019 Microsoft Corporation. All rights reserved.
C:\Users\Administrator\Desktop>whoami
Administrator
C:\Users\Administrator\Desktop>Clink v0.4.9 [git:2fd2c2] Copyright (c) 2012-2016 Martin Ridgers
http://mridgers.github.io/clink
ReadFile() from child's standard output failed! Error 109
Enter a character:
The problem is that the cmd process closes right after the first command is executed.
问题是 cmd 进程在执行第一个命令后立即关闭。
The child process exits after this line executed:执行此行后,子进程退出:
if (!CloseHandle(g_hChildStd_IN_Wr))
To solve this problem you can use separate threads.要解决此问题,您可以使用单独的线程。 One thread for reading command from console input.
从控制台输入读取命令的一个线程。 Another thread for reading result of executed command and print them out.
另一个线程用于读取执行命令的结果并打印出来。 Without closing
g_hChildStd_IN_Wr
handle.不关闭
g_hChildStd_IN_Wr
句柄。
In main()
method:在
main()
方法中:
HANDLE rThread = CreateThread(NULL, 0, ReceiveCommand, NULL, 0, NULL);
HANDLE oThread = CreateThread(NULL, 0, OutputResult, NULL, 0, NULL);
WaitForSingleObject(rThread, INFINITE);
Split WriteToPipe
function to two parts: WriteToPipe
and ReadFromPipe
. WriteToPipe
function 拆分为两部分: WriteToPipe
和ReadFromPipe
。
void WriteToPipe(char * command)
{
DWORD dwWritten;
BOOL bSuccess = FALSE;
bSuccess = WriteFile(g_hChildStd_IN_Wr, (LPVOID)command, (DWORD)strlen(command), &dwWritten, NULL);
printf("Command: %s\n", command);
if (!bSuccess)
{
wprintf(L"\nWriteFile() - Failed to write to pipe for child\'s STDIN! Error %u\n", GetLastError());
//break;
}
else
wprintf(L"\nWriteFile() - writing to the pipe for the child\'s STDIN...\n");
}
void ReadFromPipe()
{
DWORD dwWritten;
DWORD dwRead;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
DWORD availableBytes;
DWORD bytesToRead;
//Read from pipe
bSuccess = FALSE;
bzero(chBuf, sizeof(chBuf));
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (!CloseHandle(g_hChildStd_OUT_Wr))
printf("Error closing STDOUT handle, %d\n", GetLastError());
for (;;)
{
PeekNamedPipe(g_hChildStd_OUT_Rd, NULL, NULL, NULL, &availableBytes, NULL);
while (availableBytes > 0)
{
if (availableBytes <= BUFSIZE)
{
bytesToRead = availableBytes;
}
else
{
bytesToRead = BUFSIZE;
}
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, bytesToRead, &dwRead, NULL);
if (!bSuccess || dwRead == 0)
{
wprintf(L"\nReadFile() from child's standard output failed! Error %u\n", GetLastError());
break;
}
availableBytes -= bytesToRead;
bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
if (!bSuccess)
{
wprintf(L"\nWriteFile() to parent's standard output failed! Error %u\n", GetLastError());
break;
}
}
}
}
Using GetConsoleScreenBufferInfo
to monitor cursor position to wait the output from child process print completely.使用
GetConsoleScreenBufferInfo
监控 cursor position 等待 output 从子进程打印完全。 Before that don't start to receive new command.在此之前不要开始接收新命令。
DWORD WINAPI ReceiveCommand(LPVOID lpParameter)
{
char chr[1000];
CONSOLE_SCREEN_BUFFER_INFO cbsi;
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cbsi))
{
curPos = cbsi.dwCursorPosition;
}
for (;;)
{
while (TRUE)
{
Sleep(50);
if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cbsi))
{
// printf error message
return 0;
}
if ((curPos.X == cbsi.dwCursorPosition.X) && (curPos.Y == cbsi.dwCursorPosition.Y))
{
// All output of the last command executed have been printed completely.
break;
}
curPos = cbsi.dwCursorPosition;
}
bzero(chr, sizeof(chr));
printf("Enter a character: ");
scanf("%s", chr);
strcat(chr, "\n");
if (strncmp(chr, "exit", 4) == 0)
break;
WriteToPipe(chr);
}
return 0;
}
DWORD WINAPI OutputResult(LPVOID lpParameter)
{
ReadFromPipe();
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.