我正在尝试在Windows 10上将Bash.exe作为c ++脚本中的子进程生成。我想将连接保持打开并在父进程和bash之间来回传递数据。
有许多问题(例如this)与此相关,但是,我能找到的所有内容早于Windows 10“Creators”更新,其中包括Windows / Linux互操作性。
如果我生成本机Windows进程(如netstat.exe),下面的代码将按预期工作。如果我生成bash.exe并尝试从管道读取,则读取将无限期挂起。这让我觉得数据没有被发送到STDOUT用于该过程,甚至后期创建者更新。输出发送到哪里 - 有没有办法访问它?
#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#include <iostream>
HANDLE childStdInRead = NULL;
HANDLE childStdInWrite = NULL;
HANDLE childStdOutRead = NULL;
HANDLE childStdOutWrite = NULL;
HANDLE activeConsoleScreenBuffer = NULL;
CHAR returnedFromChild[4096] = {0};
CONSOLE_SCREEN_BUFFER_INFO currentConsoleScreenBuffer;
void CreateChildProcess();
void WriteToPipe(HANDLE writeTo, char passedChar);
void ReadFromPipe(HANDLE readFrom, CHAR* readto);
void ErrorExit(PTSTR);
int main()
{
SECURITY_ATTRIBUTES saAttr;
// 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(&childStdOutRead, &childStdOutWrite, &saAttr, 0))
printf("Error: StdOutRead CreatePipe! \n");
// Ensure the read handle to the pipe for STDOUT is not inherited.
if (!SetHandleInformation(childStdOutRead, HANDLE_FLAG_INHERIT, 0))
printf("Error: StdOut SetHandleInformation \n");
// Create a pipe for the child process's STDIN.
if (!CreatePipe(&childStdInRead, &childStdInWrite, &saAttr, 0))
printf("Error: StdInRead CreatePipe! \n");
// Ensure the write handle to the pipe for STDIN is not inherited.
if (!SetHandleInformation(childStdInWrite, HANDLE_FLAG_INHERIT, 0))
printf("Error: StdIn SetHandleInformation \n");
//HANDLE activeConsoleScreenBuffer = GetStdHandle(11);
printf("creating child process\n");
CreateChildProcess();
printf("waiting 3 seconds\n");
Sleep(3000);
printf("writing to pipe\n");
WriteToPipe(childStdInWrite, 't');
WriteToPipe(childStdInWrite, 'o');
WriteToPipe(childStdInWrite, 'u');
WriteToPipe(childStdInWrite, 'c');
WriteToPipe(childStdInWrite, 'h');
WriteToPipe(childStdInWrite, ' ');
WriteToPipe(childStdInWrite, '/');
WriteToPipe(childStdInWrite, 't');
WriteToPipe(childStdInWrite, 'm');
WriteToPipe(childStdInWrite, 'p');
WriteToPipe(childStdInWrite, '/');
WriteToPipe(childStdInWrite, 'a');
WriteToPipe(childStdInWrite, '\n');
WriteToPipe(childStdInWrite, 'e');
WriteToPipe(childStdInWrite, 'x');
WriteToPipe(childStdInWrite, 'i');
WriteToPipe(childStdInWrite, 't');
WriteToPipe(childStdInWrite, '\n');
printf("waiting 3 seconds\n");
Sleep(3000);
//CloseHandle(childStdOutWrite);
//printf("activeConsoleScreenBuffer = ")
printf("reading from pipe\n");
ReadFromPipe(childStdOutRead, returnedFromChild);
printf("%s\n", returnedFromChild);
printf("waiting 5 seconds\n");
Sleep(5000);
}
void CreateChildProcess(){
// In order to launch bash in System32, program must be built as x64
LPCTSTR applicationAddress = L"C:\\Windows\\System32\\bash.exe";
//LPCTSTR applicationAddress = L"C:\\Windows\\System32\\NETSTAT.EXE";
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
// 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 = childStdOutWrite;
siStartInfo.hStdOutput = childStdOutWrite;
siStartInfo.hStdInput = childStdInRead;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
BOOL success = CreateProcess(
applicationAddress, // absolute path to the application
NULL, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
CREATE_NO_WINDOW, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
if (!success)
printf("CreateProcess failed (%d).\n", GetLastError());
}
void WriteToPipe(HANDLE writeTo, char passedChar)
{
DWORD read;
BOOL success = FALSE;
// writes passedChar to childStdinWrite pipe
success = WriteFile(childStdInWrite, &passedChar, 1, &read, NULL);
if (success) {
printf("Successful write to pipe \n");
}
else {
printf("Write to pipe failed");
}
}
void ReadFromPipe(HANDLE readFrom, CHAR* readTo)
{
DWORD read;
BOOL success = FALSE;
success = ReadFile(readFrom, readTo, 1024, &read, NULL);
if (success) {
printf("Successful read from pipe \n");
}
else {
printf("failed");
ErrorExit(TEXT("ReadFromPipe failed"));
}
}
void ErrorExit(PTSTR lpszFunction)
// Format a readable error message, display a message box,
// and exit from the application.
{
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0, NULL);
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(1);
}