将输入/输出管道从父进程重定向到cmd子进程C/C++;WinApi
我一直在尝试运行一个类似于cmd输入\输出控制台的父进程。这个函数的目的是为了将来使用,但是现在我正在尝试隔离这个函数,以便使事情正确 我在这里试图实现的是用户的输入,将其发送到一个简单的cmd子进程,获取输出并继续发送命令,同时保持进程运行。问题是cmd进程在执行第一个命令后立即关闭。我粘贴了第一个命令之后发生的事情的输出,当我尝试继续输入更多命令时,出现的问题是句柄无效(因为进程被终止) 非常感谢您的帮助 主代码:将输入/输出管道从父进程重定向到cmd子进程C/C++;WinApi,c,winapi,C,Winapi,我一直在尝试运行一个类似于cmd输入\输出控制台的父进程。这个函数的目的是为了将来使用,但是现在我正在尝试隔离这个函数,以便使事情正确 我在这里试图实现的是用户的输入,将其发送到一个简单的cmd子进程,获取输出并继续发送命令,同时保持进程运行。问题是cmd进程在执行第一个命令后立即关闭。我粘贴了第一个命令之后发生的事情的输出,当我尝试继续输入更多命令时,出现的问题是句柄无效(因为进程被终止) 非常感谢您的帮助 主代码: #define _CRT_SECURE_NO_WARNINGS #incl
#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;
}
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:
问题是cmd进程在第一次启动后立即关闭
命令被执行
执行此行后,子进程退出:
if (!CloseHandle(g_hChildStd_IN_Wr))
要解决此问题,可以使用单独的线程。一个线程用于从控制台输入读取命令。另一条阅读线索
执行命令的结果,并将其打印出来。不结束
g_hChildStd_IN_Wr
handle.
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;
}
}
}
}
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;
}
在main()
方法中:
HANDLE rThread = CreateThread(NULL, 0, ReceiveCommand, NULL, 0, NULL);
HANDLE oThread = CreateThread(NULL, 0, OutputResult, NULL, 0, NULL);
WaitForSingleObject(rThread, INFINITE);
将WriteToPipe
函数拆分为两部分: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;
}
}
}
}
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;
}
问题是cmd进程在第一次启动后立即关闭
命令被执行
执行此行后,子进程退出:
if (!CloseHandle(g_hChildStd_IN_Wr))
要解决此问题,可以使用单独的线程。一个线程用于从控制台输入读取命令。另一条阅读线索
执行命令的结果,并将其打印出来。不结束
g_hChildStd_IN_Wr
handle.
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;
}
}
}
}
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;
}
在main()
方法中:
HANDLE rThread = CreateThread(NULL, 0, ReceiveCommand, NULL, 0, NULL);
HANDLE oThread = CreateThread(NULL, 0, OutputResult, NULL, 0, NULL);
WaitForSingleObject(rThread, INFINITE);
将WriteToPipe
函数拆分为两部分: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;
}
}
}
}
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;
}
这里有一个使用管道和子进程发送命令的完整示例。不幸的是,这篇文章远远超出了我对WinApi的理解。我希望有人能告诉我该进程在发布的代码中的什么位置存在,以及我如何保持它的打开状态,因为它部分工作。这里有一个使用管道和子进程的完整示例发送命令。不幸的是,这篇文章远远超出了我对WinApi的理解。我希望有人能告诉我进程在发布的代码中的什么位置存在,以及我如何保持它的开放性,因为它部分工作。非常感谢!如果控制台窗口被隐藏,这会有任何影响吗@丽塔·哈纳马津:非常感谢!如果控制台窗口被隐藏,这会有任何影响吗@丽塔·韩