c ++ - Kan ikke læse rør fra CreateProcess () tråd

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg er fast på dette siden dage, jeg er gået skør.
Dybest set prøver jeg at åbne cmd.exe i en tråd og give den input og læs output fra den, fra forældre. Som at tildele en tty i linux, da der ikke er sådan noget i Windows. Jeg har en god forståelse af Linux-systemer, men kan ikke sige det samme om Windows.


Så her er 'min' kode:


  #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
", 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
WriteFile returned: \%d
", 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
", "Error creating pipes");
        return 1;
    }

    if (!SetHandleInformation(cmd\_out\_rd, HANDLE\_FLAG\_INHERIT, 0)) {
        printf("\%s
", "Error setting handle infos");
        return 1;
    }

    if (!CreatePipe(&cmd\_in\_rd, &cmd\_in\_wr, &cmd\_sa, 0)) {
        printf("\%s
", "Error creating pipes");
        return 1;
    }

    if (!SetHandleInformation(cmd\_in\_rd, HANDLE\_FLAG\_INHERIT, 0)) {
        printf("\%s
", "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
");

    return 0;
  }


Jeg prøvede faktisk til testning meget af et andet spørgsmål om stackoverflow og fra MSDN, da jeg ikke kunne få det til at fungere på mit hovedprogram. De ting, jeg ikke forstår, er:


Hvorfor mens sløjfen inde i cmd\_thread bliver henrettet ved opstart og hænger der og venter på verdens ende? Jeg forsøgte at lukke røret out\_write håndtaget fra forældrene før læsning, men det gør andre dele ikke til at fungere.


pipewrite () synes at virke, men jeg kan ikke være sikker på at cmd.exe-tråden modtager og virker indgangen ... Da jeg ikke får nogen output:/
Jeg tænkte på stracing/ltracing programmet eller kører det til en debugger, men jeg ved ikke noget værktøj til det ...
Det mærkelige er, at den oprindelige arbejder (den hvorfra jeg fik koden). Jeg forsøgte at se forskellen mellem de to, men selv når jeg ser dem ved siden af ​​hinanden, synes de at gøre nøjagtig samme ting.

Bedste reference


Barneprocessen dør, så snart den forsøger at læse fra standardindgangen, fordi:


if (!SetHandleInformation(cmd\_in\_rd, HANDLE\_FLAG\_INHERIT, 0)) {


Dette burde have været:


if (!SetHandleInformation(cmd\_in\_wr, HANDLE\_FLAG\_INHERIT, 0)) {


som i den oprindelige kode.


Også din fejlhåndtering er stort set ukorrekt; Du kontrollerer ikke konsekvent fejl, og du kalder undertiden GetLastError (), når der ikke er nogen fejl. (Disse problemer er også i den oprindelige kode.)


Du skal også stille opkaldet til CloseHandle(cmd\_out\_wr); tilbage, fordi du ellers ikke kan fortælle, hvornår barnet kommer ud.


Åh, og for øvrigt er cmd.exe en proces , ikke en tråd.