简体   繁体   中英

Cannot read pipe from CreateProcess() thread

I'm stuck on this since days, i'm goind crazy. Basically i'm trying to open cmd.exe in a thread and give it input and read output from it, from the parent. Like, assigning a tty in linux, since there's no such thing in windows. I have a good understanding of linux systems but can't say the same thing about windows.

So, here's "my" code:

  #undef UNICODE


  #include <windows.h>
  #include <tchar.h>
  #include <stdio.h>
  #include <strsafe.h>


  //using namespace std;
  #define BUFFER_SIZE 99

  // handles for cmd thread pipes
  HANDLE cmd_in_rd = NULL;
  HANDLE cmd_in_wr = NULL;
  HANDLE cmd_out_rd = NULL;
  HANDLE cmd_out_wr = NULL;

  HANDLE cmd_thread_handle;


  void PrintError(char *text, int err) {
    DWORD retSize;
    LPTSTR pTemp = NULL;

    if (!err) return;

    retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_ARGUMENT_ARRAY,
        NULL,
        err,
        LANG_NEUTRAL,
        (LPTSTR)&pTemp,
        0,
        NULL);


    if (pTemp) printf("%s: %s\n", text, pTemp);
    LocalFree((HLOCAL)pTemp);
    return;

  }


  int pipewrite(char *command) {
    DWORD dwRead, dwWritten;
    BOOL bSuccess = FALSE;
    SetLastError(0);
    WriteFile(cmd_in_wr, command, strlen(command), &dwWritten, NULL);
    bSuccess = GetLastError();
    PrintError("WriteToPipe", bSuccess);
    return (bSuccess == 0) || (bSuccess == ERROR_IO_PENDING);
  }

  int __stdcall cmd_thread(int arg) {
    // this function only prints when data is ready
    DWORD dwRead, dwWritten;
    CHAR chBuf[BUFFER_SIZE];
    BOOL bSuccess = FALSE;
    HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

    int rf_ret, wf_ret;

    //CloseHandle(cmd_out_wr); makes readfile fail!!

    SetLastError(0);
    while (1) { // only executes once!!!!!!!
        (rf_ret = ReadFile(cmd_out_rd, chBuf, BUFFER_SIZE, &dwRead, NULL))
            &&
            (wf_ret = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL));
        printf("ReadFile returned: %d\nWriteFile returned: %d\n", rf_ret, wf_ret);
        bSuccess = GetLastError();
        PrintError("ReadingFromPipe", bSuccess);
    }

    bSuccess = GetLastError();
    return (bSuccess == 0) || (bSuccess == ERROR_IO_PENDING);
  }


  int main(void) {

    char buffer[BUFFER_SIZE];

    // init the pipes
    SECURITY_ATTRIBUTES cmd_sa;
    cmd_sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    cmd_sa.bInheritHandle = TRUE;
    cmd_sa.lpSecurityDescriptor = NULL;

    if (!CreatePipe(&cmd_out_rd, &cmd_out_wr, &cmd_sa, 0)) {
        printf("%s\n", "Error creating pipes");
        return 1;
    }

    if (!SetHandleInformation(cmd_out_rd, HANDLE_FLAG_INHERIT, 0)) {
        printf("%s\n", "Error setting handle infos");
        return 1;
    }

    if (!CreatePipe(&cmd_in_rd, &cmd_in_wr, &cmd_sa, 0)) {
        printf("%s\n", "Error creating pipes");
        return 1;
    }

    if (!SetHandleInformation(cmd_in_rd, HANDLE_FLAG_INHERIT, 0)) {
        printf("%s\n", "Error setting handle infos");
        return 1;
    }

    // create the cmd thread
    PROCESS_INFORMATION cmd_pi;
    STARTUPINFO cmd_si;
    ZeroMemory(&cmd_pi, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&cmd_si, sizeof(STARTUPINFO));
    cmd_si.cb = sizeof(STARTUPINFO);
    cmd_si.hStdError = cmd_out_wr;
    cmd_si.hStdOutput = cmd_out_wr;
    cmd_si.hStdInput = cmd_in_rd;
    cmd_si.dwFlags |= STARTF_USESTDHANDLES;

    TCHAR comm[] = TEXT("cmd.exe");
    BOOL th = CreateProcess(NULL,
        comm,
        NULL,
        NULL,
        TRUE, // handles are inherited
        0,
        NULL,
        NULL,
        &cmd_si,
        &cmd_pi);

    if (th) {
        CloseHandle(cmd_pi.hProcess);
        CloseHandle(cmd_pi.hThread);
    }

    cmd_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)cmd_thread, NULL, 0, NULL);

    // read commands from shell and send them to cmd
    ZeroMemory(&buffer, BUFFER_SIZE);
    while (1) {
        fgets(buffer, BUFFER_SIZE, stdin);
        if (!pipewrite(buffer)) break;
    }
    printf("Program terminated\n");

    return 0;
  }

I actually, for testing purposes, copied a lot from another question on stackoverflow and from MSDN since i couldn't get it to work on my main program. The things I don't understand are:

Why the while loop inside cmd_thread gets executed at startup and then hangs there waiting for the end of the world? I tried to close the pipe out_write handle from the parent before reading, but that makes other parts not working.

pipewrite() seems to work, but I can't be sure that the cmd.exe thread receives and works the input... Since i get no output :/ I thought about stracing/ltracing the program or running it into a debugger, but I know no tool for that... The strange thing is that the original works (the one from where i got the code). I tried to spot the difference between the two, but even when I look to them side by side, they seem to do the exact same things.

The child process is dying as soon as it attempts to read from standard input, because:

if (!SetHandleInformation(cmd_in_rd, HANDLE_FLAG_INHERIT, 0)) {

This should have been:

if (!SetHandleInformation(cmd_in_wr, HANDLE_FLAG_INHERIT, 0)) {

like in the original code.

Also, your error handling is largely incorrect; you don't consistently check for errors and you sometimes call GetLastError() when no error has occurred. (Those problems are in the original code too.)

You also need to put the call to CloseHandle(cmd_out_wr); back in because otherwise you won't be able to tell when the child exits.

Oh, and incidentally, cmd.exe is a process , not a thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM