Pipes (tuberias) sincronas, estancadas (Solucionado)

Iniciado por Usuario887, 11 Noviembre 2021, 22:29 PM

0 Miembros y 1 Visitante están viendo este tema.

Usuario887

Hola,

Estoy intentando escribir la entrada y leer la salida de un proceso (independientemente hijo o "detached") como cmd.exe (da igual que proceso es, porque estoy haciendo esto por practica) y mi programa se estanca en ReadFile:

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

int main()
{
   HANDLE hPipeOutWr, hPipeOutRd,
          hPipeInWr, hPipeInRd;

   char szBuffer[BUFSIZ];
   char szAns[BUFSIZ];
   DWORD dwRead;

   STARTUPINFO si;
   PROCESS_INFORMATION pi;
   SECURITY_ATTRIBUTES sa;

   ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));

   printf("\r\nCreating pipes... ");

   sa.nLength=sizeof(SECURITY_ATTRIBUTES);
   sa.lpSecurityDescriptor=NULL;
   sa.bInheritHandle=TRUE;

   if(!CreatePipe(&hPipeInRd, &hPipeInWr, &sa, 0))
   {
       return ("\r\nError: Windows RTL: CreatePipe(): %d", GetLastError());
       return -1;
   }

   if(!CreatePipe(&hPipeOutRd, &hPipeOutWr, &sa, 0))
   {
       return ("\r\nError: Windows RTL: CreatePipe(): %d", GetLastError());
       return -1;
   }

   printf("ok ");


   ZeroMemory(&si, sizeof(STARTUPINFO));
   ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
   ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));

   si.cb=sizeof(STARTUPINFO);
   si.dwFlags=STARTF_USESTDHANDLES;

   si.hStdError=hPipeOutWr;
   si.hStdInput=hPipeInRd;
   si.hStdOutput=hPipeOutWr;

   printf("\r\nCreating process... ");

   if(!CreateProcess("C:\\Windows\\System32\\cmd.exe",
                     NULL,
                     NULL,
                     NULL,
                     TRUE,
                     0,
                     NULL,
                     NULL,
                     &si,
                     &pi))
   {
       printf("\r\nError: Windows RTL: CreateProcess: %d", GetLastError());
       return -1;
   }

   printf("ok ");

   CloseHandle(hPipeOutWr);
   CloseHandle(hPipeInRd);

   printf("\r\nStarting communication... ");

   while(strcmp(szBuffer, "exit")&&\
         strcmp(szBuffer, "end"))
   {

       if(ReadFile(hPipeOutRd,
                       szAns,
                       BUFSIZ,
                       &dwRead,
                       NULL))
       {
           while(ReadFile(hPipeOutRd,
                           szBuffer,
                           BUFSIZ,
                           &dwRead,
                           NULL))
           {
                   zBuffer[dwRead]='\0';
               strcat(szAns, szBuffer);
           }
       }
       printf("%s", szAns);
       ZeroMemory(szAns, BUFSIZ);

       gets(szBuffer);
       szBuffer[strlen(szBuffer)]='\n';
       szBuffer[strlen(szBuffer)+1]='\0';
       if(!WriteFile(hPipeInWr,
                     szBuffer,
                     strlen(szBuffer),
                     &dwRead,
                     NULL))
       {
           printf("\r\nError: Windows RTL: WriteFile(): %d", GetLastError());
       }
   }

   TerminateProcess(pi.hProcess, 0);
   return 0;
}


Se como hacer que funcione, el punto es que no quiero que funcione de esa manera porque es una manera no optima. Si pongo un Sleep(1000); antes de ReadFile, el programa funciona, porque le da tiempo al proceso (hijo, en este caso) de ejecutarse y meter datos en el buffer de la tuberia.

Esto no tiene sentido. Es un segundo de ejecucion que no esta haciendo nada.

¿Alguien sabe una forma eficiente de hacer tuberias en Windows?

He hecho tuberias nombradas y no he tenido ningun problema, aunque tambien es cierto que el programa hijo en ese momento lo hice yo especificamente para ser un programa hijo con tuberias, asi que no aplica en este caso.

En realidad me gustaria saber como hacer una tuberia anonima, asincrona y estable. No encuentro ningun ejemplo de ello en Windows.

Cualquier informacion me seria util.

Gracias.

Buenas noches.




PD: El problema no esta en el while(ReadFile... Porque ya lo quite y tampoco funciona asi. Ademas eso solo confirma que no hay mas entradas.

Si la funcion no detecta ningun byte deberia fallar y ya. No quedarse en un ciclo infinito  :huh: :huh: :huh:




Solucion:

Ya quisieramos tu y yo que fuera posible hacer async listen con tuberias en Windows. La unica forma aparentemente es crear hilos que escuchen

Como se que me explico como el c*** mejor dejo el codigo y ya:

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

    DWORD AsyncListen(HANDLE hPipeOutRd)
    {
        char szBuffer[BUFSIZ];
        DWORD dwRead;

        while(ReadFile(hPipeOutRd,
                       szBuffer,
                        BUFSIZ,
                        &dwRead,
                        NULL))
        {
            szBuffer[dwRead]='\0';
            printf("%s", szBuffer);
        }
    }

    int main()
    {
        HANDLE hPipeOutWr, hPipeOutRd,
               hPipeInWr, hPipeInRd;

        char szBuffer[BUFSIZ];
        char szAns[BUFSIZ];
        DWORD dwRead;

        HANDLE hAsyncReadT;

        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        SECURITY_ATTRIBUTES sa;

        ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));

        printf("\r\nCreating pipes... ");

        sa.nLength=sizeof(SECURITY_ATTRIBUTES);
        sa.lpSecurityDescriptor=NULL;
        sa.bInheritHandle=TRUE;

        if(!CreatePipe(&hPipeInRd, &hPipeInWr, &sa, 0))
        {
            return ("\r\nError: Windows RTL: CreatePipe(): %d", GetLastError());
            return -1;
        }

        if(!CreatePipe(&hPipeOutRd, &hPipeOutWr, &sa, 0))
        {
            return ("\r\nError: Windows RTL: CreatePipe(): %d", GetLastError());
            return -1;
        }

        printf("ok ");


        ZeroMemory(&si, sizeof(STARTUPINFO));
        ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
        ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));

        si.cb=sizeof(STARTUPINFO);
        si.dwFlags=STARTF_USESTDHANDLES;

        si.hStdError=hPipeOutWr;
        si.hStdInput=hPipeInRd;
        si.hStdOutput=hPipeOutWr;

        printf("\r\nCreating process... ");

        if(!CreateProcess("C:\\Windows\\System32\\cmd.exe",
                          NULL,
                          NULL,
                          NULL,
                          TRUE,
                          0,
                          NULL,
                          NULL,
                          &si,
                          &pi))
        {
            printf("\r\nError: Windows RTL: CreateProcess(): %d", GetLastError());
            return -1;
        }

        printf("ok ");

        CloseHandle(hPipeOutWr);
        CloseHandle(hPipeInRd);

        printf("\r\nStarting communication... ");

        ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
        sa.nLength=sizeof(SECURITY_ATTRIBUTES);
        sa.lpSecurityDescriptor=NULL;
        sa.bInheritHandle=TRUE;

        if((hAsyncReadT=CreateThread(&sa, 0, (LPTHREAD_START_ROUTINE)AsyncListen, (PHANDLE)hPipeOutRd, 0, NULL))==NULL)
        {
            printf("\r\nError: Windows RTL: CreateThread(): %d", GetLastError());
            return -1;
        }

        while(strcmp(szBuffer, "exit")&&\
              strcmp(szBuffer, "end"))
        {
            printf("\r\n");
            gets(szBuffer);
            szBuffer[strlen(szBuffer)]='\n';
            szBuffer[strlen(szBuffer)+1]='\0';
            if(!WriteFile(hPipeInWr,
                          szBuffer,
                          strlen(szBuffer),
                          &dwRead,
                          NULL))
            {
                printf("\r\nError: Windows RTL: WriteFile(): %d", GetLastError());
            }
        }

        TerminateProcess(pi.hProcess, 0);
        return 0;
    }


Aun asi!!!! Si alguien conoce una forma mas eficiente, "Navaja-suiziosa" de hacer esto, le agradeceria un comentario.

Y gracias de antemano, sin embargo.

Un saludo y buenas noches.