简体   繁体   English

无法从CreateProcess()线程读取管道

[英]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. 基本上,我试图在线程中打开cmd.exe并为其提供输入,并从父级读取它的输出。 Like, assigning a tty in linux, since there's no such thing in windows. 就像在Linux中分配tty一样,因为Windows中没有这样的东西。 I have a good understanding of linux systems but can't say the same thing about windows. 我对linux系统有很好的了解,但对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. 实际上,出于测试目的,我从另一个关于stackoverflow的问题和MSDN中复制了很多内容,因为我无法在我的主程序上使用它。 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? 为什么cmd_thread中的while循环在启动时执行,然后挂在那里等待世界的尽头? I tried to close the pipe out_write handle from the parent before reading, but that makes other parts not working. 我试图在读取之前关闭父管道的out_write句柄,但这会使其他部分无法正常工作。

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). pipewrite()似乎可以工作,但是我不确定cmd.exe线程是否可以接收和处理输入...由于我没有输出://我考虑过对程序进行分段/跟踪或将其运行到调试器中,但我不知道有什么工具...奇怪的是, 原始作品有效(我从那里获得了代码)。 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. 您不会始终检查错误,并且有时在没有错误发生时有时会调用GetLastError()。 (Those problems are in the original code too.) (这些问题也在原始代码中。)

You also need to put the call to CloseHandle(cmd_out_wr); 您还需要将调用置于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. 哦,顺便说一句, cmd.exe是一个进程 ,而不是线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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