从Windows10 / WSL上的bash.exe子进程捕获stdout

时间:2017-09-08 15:55:57

标签: c++ windows-10 stdout windows-subsystem-for-linux

我正在尝试在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);
}

0 个答案:

没有答案