Redirecting Console Application Stdin/out

I would like to be able to spawn from a Windows application a console application (such as ftp) and redirect the standard input and output.  In particular, I would like to be able to take the standard output/error and send it to a text box on the screen instead of appearing in a DOS window.  Microsoft's developer studio does this when it compiles code.  How do I do this?  I believe it has something to do with CreateProcess and the handles you can specify in the STARTUPINFO structure, but I don't know which handles to specify or how to link them to a text box in my windows application.
ardolinoAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

chensuCommented:
HOWTO: Spawn Console Processes with Redirected Standard Handles
http://support.microsoft.com/support/kb/articles/q190/3/51.asp

INFO: Redirection Issues on Windows 95 MS-DOS Applications
http://support.microsoft.com/support/kb/articles/Q150/9/56.ASP
0
ardolinoAuthor Commented:
These articles are helpful, but only answer half of my question.  I need to know how to take the information that is coming in/going out from the child's process standard handles and send it to/from a text box in a windows application.
0
jkrCommented:
Try the following code:

DWORD StartCommandLine( HWND hDlg )
{
   OSVERSIONINFO osvi;
   STARTUPINFO si;
   PROCESS_INFORMATION pi;
   HANDLE hInputRead, hInputWrite;
   HANDLE hOutputRead, hOutputWrite;
   HANDLE hDupInputWrite;
   HANDLE hDupOutputRead;
   BOOL bStatus;
   DWORD dwRead, dwAvail, dwMsg;
   char szInput[ 1024 ];

 
   memset( &si, 0, sizeof(STARTUPINFO) );             //  Initialize structures
   memset( &pi, 0, sizeof(PROCESS_INFORMATION) );
                                        //  Create pipe for console -> GUI data
   bStatus = CreatePipe( &hInputRead, &hInputWrite, NULL, 1024 );
   if( ! bStatus )
      return( FALSE );
                                        //  Create pipe for GUI -> console data
   bStatus = CreatePipe( &hOutputRead, &hOutputWrite, NULL, 1024 );
   if( ! bStatus )
   {
      CloseHandle( hInputRead );           //  Close first pipe if second fails
      CloseHandle( hInputWrite );
      return( FALSE );
   }
                                   //  Make an inheritable pipe endpoint handle
   DuplicateHandle( GetCurrentProcess(), hInputWrite,
                    GetCurrentProcess(), &hDupInputWrite, 0L, TRUE,
                    DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS );
                                            //  and a second for GUI -> console
   DuplicateHandle( GetCurrentProcess(), hOutputRead,
                    GetCurrentProcess(), &hDupOutputRead, 0L, TRUE,
                    DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS );

   si.cb = sizeof(STARTUPINFO);
   si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
   si.wShowWindow = SW_HIDE;        //  Don't show the console window (DOS box)
   si.hStdOutput = hDupInputWrite;             //  Redirect command line to GUI
   si.hStdError = hDupInputWrite;
   si.hStdInput = hDupOutputRead;  //  and send stuff from here to command line

   hPipeOut = hOutputWrite;                  //  Global so window can access it

   memset( &osvi, 0, sizeof(OSVERSIONINFO) );     //  Initialize version struct
   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);           //  Fill in size
   GetVersionEx( &osvi );                               //  Get OS version info
                                                            //  Start a DOS box
   if( osvi.dwPlatformId == VER_PLATFORM_WIN32_NT )           //  If it's WinNT
      bStatus = CreateProcess( NULL, "cmd /K", NULL, NULL, TRUE,
                               0, NULL, NULL, &si, &pi );       //  Use CMD.EXE
   else                                           //  Use command.com for Win95
      bStatus = CreateProcess( NULL, "c:\\command.com", NULL, NULL, TRUE,
                               0, NULL, NULL, &si, &pi );

   CloseHandle( hDupInputWrite );               //  Close duplicates so GUI end
   CloseHandle( hDupOutputRead );                         //  can use the pipes

   if( ! bStatus )
   {
      CloseHandle( hInputRead );
      CloseHandle( hInputWrite );
      CloseHandle( hOutputRead );
      CloseHandle( hOutputWrite );
      return( FALSE );
   }
                     //  Loop until either the window closure sets the event or
   while( WaitForSingleObject( hThreadEvent, 0 ) != WAIT_OBJECT_0 )
   {                                                  //  The dos box is closed
      if( WaitForSingleObject( pi.hProcess, 0 ) == WAIT_OBJECT_0 )
      {
         pi.hProcess = NULL;
         break;
      }

                                                //  If there's anything to read
      if( PeekNamedPipe( hInputRead, szInput, 1024, &dwRead,
                         &dwAvail, &dwMsg ) )
      {                                               //  Read it into a buffer
         ReadFile( hInputRead, szInput, dwAvail, &dwRead, NULL );
         if( dwRead )                        //  and send to the window control
            SendDlgItemMessage( hDlg, 100, LB_ADDSTRING, 0, (LPARAM)szInput );
      }
      Sleep( 100 );                        //  Sit a spell...kick yer shoes off
   }

   if( pi.hProcess )                     //  If the dos box is running, kill it
      TerminateProcess( pi.hProcess, 0 );

   CloseHandle( hInputWrite );
   CloseHandle( hOutputRead );
   return( TRUE );                                      //  And exit the thread
}
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ardolinoAuthor Commented:
This really isn't what I wanted, but it was sort of helpful.
0
dbusherCommented:
I cut an pasted this code into my :
void CDialitDlg::OnDialButton()
function and did a build all (VC++ v4)
and got this error:

error C2599: 'StartCommandLine' : local functions are not supported

I am sure it is a basic error - I am a
new programmer.  Any help in fixing this?
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.