?
Solved

CreatePipe() guru(s) needed

Posted on 2003-02-24
13
Medium Priority
?
700 Views
Last Modified: 2008-02-01
I have 3 programs:

filesrc.exe : This file reads a text file and spits out all data

filefilter.exe :  This file takes in data coming from filesrc.exe and does few checks and then spits it out

filewrite.exe:  This file takes in data coming form filefilter and then puts it in some file.

(Thats how i should copy one file to another)

I have all the above 3 files working but can't figure out how will i write one main application to control the above 3 files. In other words i want to make a main file that would execute the above programs and properly pass on the required data to one another using handles , CreateProcess() and CreatePipe().


So far i have this much(below), but i am lost as to how will i hand over a handle from one process to another( data bouncing in b/w the above three files). More or less copy file from one to another with the help of above files and in above mentioned manner.


int main(int argc, char *argv[])
{
   SECURITY_ATTRIBUTES pipeAttr;
 
   pipeAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
   pipeAttr.bInheritHandle = TRUE;
   pipeAttr.lpSecurityDescriptor = NULL;

   if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &pipeAttr, 0))
   {

        cout << "error creating pipe" << endl;
          exit (1);
     }
   .........?



0
Comment
Question by:MellowD0c
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 3
  • 2
  • +2
13 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 304 total points
ID: 8013481
You will find a complete sample at http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B190351 ("HOWTO: Spawn Console Processes with Redirected Standard Handles") - the topic is slightly different, but it covers the issue. If you want to take a look ar named pipes also, I would suggest http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ipc/base/multithreaded_pipe_server.asp ("Multithreaded Pipe Server")
0
 
LVL 12

Expert Comment

by:Salte
ID: 8015156
You should CreatePipe() twice in your program.

This provides 4 file handles, 2 for each pipe A and B.

Each of these pipe have a read handle and a write handle, the read handle for A is RA and WA is the write handle. Similarly for RB and WB.

Ok. Then you CreateProcess for the first filesrc.exe provide the arguments (presumably the file to read from is an argument) but most importantly provide it a STDOUT handle of WA. I.e. you provide WA as that process' stdout handle.

Then you CreateProcess for the filefilter and provide RA as the STDIN handle and WB as the STDOUT handle.

Then you CreateProcess for the filewrite.exe and provide RB as the STDIN handle and presumably an argument for the file to write to.

Then you just sit and wait for the processes to finish. Specifically the last process to finish is the filewrite.exe process so a good bet is to wait for that process. You should probably also wait for the others but that can be done after filewrite.exe has stopped.

If all processes exit with success (normally with 0 as exit-code) the job is done.

If you write the code for the processes you determine if they return 0 or other code for success/failure but the regular thing to do is 0 for success and 1 for failure. However, some programs do things differently, be aware that shell scripting etc usually assume 0 -> success, 1 -> failure.

If you don't know how to CreateProcess() to create a process and provide a specific handle as STDIN/STDOUT etc the above html link provided by jkr will tell you the details on how to do that.

Alf
0
 

Expert Comment

by:eranborovik
ID: 8016326
You can use regular shell pipes instead of programmatically do it. (It should work on any unix shell and also on windows/msdos shell).

Just write from a shell:
filesrc.exe | filefilter.exe | filewrite.exe > fileName

fileName is the name of the file you want to write too.

If you want, you can also run the above command programmatically  using
the "system" system call. Just pass the above string
to system and it will create a shell that do the rest.

Hope it helps.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Expert Comment

by:eranborovik
ID: 8016334
You can use regular shell pipes instead of programmatically do it. (It should work on any unix shell and also on windows/msdos shell).

Just write from a shell:
filesrc.exe | filefilter.exe | filewrite.exe > fileName

fileName is the name of the file you want to write too.

If you want, you can also run the above command programmatically  using
the "system" system call. Just pass the above string
to system and it will create a shell that do the rest.

Hope it helps.
0
 

Author Comment

by:MellowD0c
ID: 8018092
int main (int argc, char* argv [])


{
     DWORD i;
     HANDLE hReadPipe, hWritePipe;
     char command1 [MAX_PATH];
     char command2 [MAX_PATH];
     SECURITY_ATTRIBUTES PipeSA = {sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
               /* Init for inheritable handles. */
         
     PROCESS_INFORMATION ProcInfo1, ProcInfo2;//, ProcInfo3;
     STARTUPINFO StartInfoCh1, StartInfoCh2;//, StartInfoCh3;
     

     /* Startup info for the two child processes. */

     GetStartupInfo (&StartInfoCh1);
     GetStartupInfo (&StartInfoCh2);
     //GetStartupInfo (&StartInfoCh3);

     

     /* Create an anonymous pipe with default size.
          The handles are inheritable. */

     if (!CreatePipe (&hReadPipe, &hWritePipe, &PipeSA, 0))
     {
          cerr << "Anon pipe create failed." <<endl;
          return true;
     }

     /* Set the output handle to the inheritable pipe handle,
          and create the first processes. */

     StartInfoCh1.hStdInput  = GetStdHandle (STD_INPUT_HANDLE);
     StartInfoCh1.hStdError  = GetStdHandle (STD_ERROR_HANDLE);
     StartInfoCh1.hStdOutput = hWritePipe;
     StartInfoCh1.dwFlags = STARTF_USESTDHANDLES;

     strcpy(command1, "filesrc.exe ");
     strcat(command1, argv[1]);

     if (!CreateProcess (NULL, command1, NULL, NULL,
               TRUE,               /* Inherit handles. */
               0, NULL, NULL, &StartInfoCh1, &ProcInfo1))
     {
          cout << "CreateProc1 failed." <<endl;
          return true;
     }
     CloseHandle (ProcInfo1.hThread);
     CloseHandle (hWritePipe);

     /* Repeat (symmetrically) for the second process. */

     StartInfoCh2.hStdInput  = hReadPipe;
     StartInfoCh2.hStdError  = GetStdHandle (STD_ERROR_HANDLE);
     StartInfoCh2.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
     StartInfoCh2.dwFlags = STARTF_USESTDHANDLES;

     strcpy(command2, "filewrite.exe ");
     strcat(command2, argv[2]);

     if (!CreateProcess (NULL, command2, NULL, NULL,
               TRUE,               /* Inherit handles. */
               0, NULL, NULL, &StartInfoCh2, &ProcInfo2))
     {
          cout << "CreateProc1 failed." <<endl;
          return true;
     }
     CloseHandle (ProcInfo2.hThread);
     CloseHandle (hReadPipe);

     /* Wait for both processes to complete.
          The first one should finish first, although it really does not matter. */
     cout << "i am here" << endl;
     WaitForSingleObject (ProcInfo1.hProcess, INFINITE);
     WaitForSingleObject (ProcInfo2.hProcess, INFINITE);
     CloseHandle (ProcInfo1.hProcess);
     CloseHandle (ProcInfo2.hProcess);
     return 0;
}

Salte, actually what you told is what i wanted to do, but i am still not sure as to how i will hand over handle from one process to another. Is it like i start process and then for instance my source.exe will read and write to stdout and then other process comes and read THAT stdout as stdin and processes it. Then will come my third process read the stdout of last process and make it as stdin and then make stdout to a file mentioned as argv[2] in command line. But... for the time i have take out my middle file just to have an idea of how things are working, so here is what above code SHOULD do, but it doesn't.

User types: pipe sometexttoread.txt sometexttowrite.txt

Now the above program should start and call my sourc.exe function to read the file and then put that to stdout and my filewrite.exe to get that into stdin and write out to file. However, it just does nothing, though it goes all the way and prints out "i am here" in end. What am i doing wrong here?

0
 
LVL 12

Expert Comment

by:Salte
ID: 8018694
I am not 100% sure of the STARTF_USE_STDHANDLES. I assume it means that the hStdInput etc contain valid values and as such that part seems ok.

The only question is if the handles are inheritable and what the filesrc.exe does with that handle.

Is it possible for you to write some debug info to some other place. For example proc1 has stderr set to same place as the parent process so the reader program could write some info to cerr, indicating it is starting up - reading from pipe etc... and so on until you see it working.

The code you wrote above appear to be correct but it could be some nitty details in the CreateProcess() call.

One thing is that you should wait for process2 before waiting for process 1. This is because when process2 is done you "know" that process1 is already done and so WaitForSingleObject on process1 shouldn't actually do any waiting.

Not sure if closing the handle to the thread is necessarily a good idea. If you move that to after WaitForSingleObject etc, would that help?

Kinda hard for me to check your code as I am sitting on a linux machine at the moment :-) I have windows at home and can check out some stuff when I get home though.

Bottom line: I am kinda suspicious concerning the inheritability of the handles and the setup. It appear correct but there could be a detail or two that we both overlook. I am also suspicous about that closehandle on the thread, it should be OK to close the thread though so I doubt it is a problem but I am not 100% confident it is no problem. The pipe should be safe to close though if the child process has started and gotten it from startupinfo.

Alf
0
 
LVL 86

Expert Comment

by:jkr
ID: 8018884
Have you checked the link I posted? The sample code on the page covers this issue...

0
 

Author Comment

by:MellowD0c
ID: 8019842
Ok guys, here is it finally, The following program Works 100%, if i make a few changes and that is that, if i take out 3rd process from program, it works fine and copies the file. But if i insert the third process now, it works too but it creates a copy of blank file 0 bytes. Can anyone check and tell me what i have done wrong? i am pretty sure that the information from 2nd process doesn't seem to be passing on to 3rd one, but what specifically i would be doing wrong and how can i correct it so that pipes up correctly and hands over data from 1st process to 3rd as is.



#include <iostream>
#include <windows.h>
#include <winbase.h>
#include <iomanip.h>

using namespace std;

void DisplayError(char *pszAPI);

int main (int argc, char* argv [])


{
      //DWORD i;
      HANDLE hReadPipe, hWritePipe, hReadPipe2, hWritePipe2;
      char command1 [MAX_PATH];
      char command2 [MAX_PATH];
      SECURITY_ATTRIBUTES PipeSA = {sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
                  /* Init for inheritable handles. */
            
      PROCESS_INFORMATION ProcInfo1, ProcInfo2, ProcInfo3;
      STARTUPINFO StartInfoCh1, StartInfoCh2, StartInfoCh3;
      

      /* Startup info for the two child processes. */

      GetStartupInfo (&StartInfoCh1);
      GetStartupInfo (&StartInfoCh2);
      GetStartupInfo (&StartInfoCh3);

      

      /// Create an anonymous pipe with default size.
            //The handles are inheritable.

      if (!CreatePipe (&hReadPipe, &hWritePipe, &PipeSA, 0))
      {
            DisplayError("Pipe create failed." );
      }

      if (!CreatePipe (&hReadPipe2, &hWritePipe2, &PipeSA, 0))
      {
            DisplayError("Pipe create failed." );
      }
      // Set the output handle to the inheritable pipe handle,
      //and create the first processes.

      StartInfoCh1.hStdInput  = GetStdHandle (STD_INPUT_HANDLE);
      StartInfoCh1.hStdError  = GetStdHandle (STD_ERROR_HANDLE);
      StartInfoCh1.hStdOutput = hWritePipe;
      StartInfoCh1.dwFlags = STARTF_USESTDHANDLES;
      
      strcpy(command1, "source.exe ");
      strcat(command1, argv[1]);

      
      if (!CreateProcess (NULL, command1, NULL, NULL,
                  TRUE,                  // Inherit handles.
                  0, NULL, NULL, &StartInfoCh1, &ProcInfo1))
      {
            DisplayError("CreateProc1 failed.");
                  
      }
      CloseHandle (ProcInfo1.hThread);
      CloseHandle (hWritePipe);

   
      StartInfoCh2.hStdInput  = hReadPipe;
      StartInfoCh2.hStdError  = GetStdHandle (STD_ERROR_HANDLE);
      StartInfoCh2.hStdOutput = hWritePipe2;
      StartInfoCh2.dwFlags = STARTF_USESTDHANDLES;
      //HANDLE hwritefile;
      //StartInfoCh2.hStdOutput = hwritefile;

      
      strcpy(command2, "filter.exe ");
      //strcat(command2, argv[2]);
      
      
      if (!CreateProcess (NULL, command2, NULL, NULL,
                  TRUE,                  // Inherit handles.
                  0, NULL, NULL, &StartInfoCh2, &ProcInfo2))
      {
            DisplayError("CreateProc2 failed." );
            //exit(1);
      }
      CloseHandle (ProcInfo2.hThread);
      CloseHandle (hReadPipe);
      CloseHandle (hWritePipe2);


      //Repeat (symmetrically) for the second process.
      HANDLE hwritefile;
      hwritefile= argv[2];
      StartInfoCh3.hStdInput  = hReadPipe2;
      StartInfoCh3.hStdError  = GetStdHandle (STD_ERROR_HANDLE);
      StartInfoCh3.hStdOutput = hwritefile;
      //StartInfoCh3.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
      StartInfoCh3.dwFlags = STARTF_USESTDHANDLES;
      
      
      strcpy(command2, "sink.exe ");
      strcat(command2, argv[2]);
      
      
      if (!CreateProcess (NULL, command2, NULL, NULL,
                  TRUE,                  /* Inherit handles. */
                  0, NULL, NULL, &StartInfoCh3, &ProcInfo3))
      {
            DisplayError("CreateProc3 failed." );
            //exit(1);
      }
      CloseHandle (ProcInfo3.hThread);
      CloseHandle (hReadPipe2);
      //CloseHandle (ProcInfo1.hThread);
      CloseHandle (hwritefile);



      


      // Wait for both processes to complete.
      WaitForSingleObject (ProcInfo2.hProcess, INFINITE);
      WaitForSingleObject (ProcInfo1.hProcess, INFINITE);
      WaitForSingleObject (ProcInfo3.hProcess, INFINITE);
      
      CloseHandle (ProcInfo1.hProcess);
      CloseHandle (ProcInfo2.hProcess);
      CloseHandle (ProcInfo3.hProcess);
      return 0;
}
//********taken from http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B190351***
 ///////////////////////////////////////////////////////////////////////
   // DisplayError
   // Displays the error number and corresponding message.
   ///////////////////////////////////////////////////////////////////////
   void DisplayError(char *pszAPI)
   {
       LPVOID lpvMessageBuffer;
       CHAR szPrintBuffer[512];
       DWORD nCharsWritten;

       FormatMessage(
                FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
                NULL, GetLastError(),
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (LPTSTR)&lpvMessageBuffer, 0, NULL);

       wsprintf(szPrintBuffer,
         "ERROR: API    = %s.\n   error code = %d.\n   message    = %s.\n",
                pszAPI, GetLastError(), (char *)lpvMessageBuffer);

       WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),szPrintBuffer,
                     lstrlen(szPrintBuffer),&nCharsWritten,NULL);

       LocalFree(lpvMessageBuffer);
       ExitProcess(GetLastError());
   }
   //**********************************************************

0
 

Author Comment

by:MellowD0c
ID: 8019853
jkr, thanks to you as welll, i did check it and got lost. There was just too much info an i needed only this much. But hey, i stole that function to display errors, and its cool!
0
 

Author Comment

by:MellowD0c
ID: 8019906
Also, i have uploaded my filter.exe sink.exe and source.exe to these places, so if you want to download and check for what i could be doing wrong??

http://saudaziz.tripod.com/Debug.zip

put mouseover, rightclick and save target

otherwise you will get error from Tripod...
0
 

Author Comment

by:MellowD0c
ID: 8020232
ok guys sorry, but i found the problem, i will find some EE guy to split up the points and give to jkr and salte
0
 
LVL 12

Expert Comment

by:Salte
ID: 8023883
The hwritefile handle seem suspicious, you declare the variable but never provide it a value...

Alf
0
 
LVL 6

Expert Comment

by:Mindphaser
ID: 8033206
MellowD0c

You asked to split points between Salte and jkr
I have reduced the points on this question from 155 to 76 as indicated by your request at Community Support. Please copy the URL and create a new question in this topic area for the other Experts to whom you wish to award points. The title of the question should read "Points for", followed by the Expert's name. In the question itself, you should paste the link to the original question and perhaps a comment stating that the points are for their help with that question. Once you have created the new questions, you can go back to the original, and accept the comment from the Expert for whom you did not create a new question. The Experts will  comment in your new "Points for" question(s), which you then accept and grade to close.
If you have any questions, please don't hesitate to ask.
Thank you.

** Mindphaser - Community Support Moderator **
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.
Suggested Courses

766 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question