Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Redirecting STDOUT of a child process under Windows NT

Posted on 2000-04-07
9
Medium Priority
?
441 Views
Last Modified: 2013-11-20
I have a program that calls `ping.exe'.
The program then displays the result in a dialog-thingy.
This is all working fine under Win9x, but not on NT...

Relevant code:

HANDLE hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup, hSaveStdout;
      SECURITY_ATTRIBUTES      saAttr;
      PROCESS_INFORMATION piProcInfo;
      STARTUPINFO                  siStartInfo;  
      BOOL                        fSuccess;
      char                        szBuf[BUFSIZE];
      CString                  strAddr;
      DWORD                        dwRead;
      
      if ( ((CSupportDlg*)(AfxGetApp()->m_pMainWnd))->m_bIsWindowsNT == TRUE ) {
            strAddr.Format("%s\\ping.exe %s", GetSysDir(), tmpdlg->m_strPingAddr);
      } else {
            strAddr.Format("%s\\ping.exe %s", GetWinDir(), tmpdlg->m_strPingAddr);
      }
      
      saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
      saAttr.bInheritHandle = TRUE;
      saAttr.lpSecurityDescriptor = NULL;
      
      // Save the handle to the current STDOUT.
      hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
      
      // Create a pipe for the child process's STDOUT.  
      if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
            return 1;

      // Set a write handle to the pipe to be STDOUT.  
      if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
            return 2;

      // Create noninheritable read handle and close the inheritable read handle.
      fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, GetCurrentProcess(), &hChildStdoutRdDup , 0,
                                                            FALSE, DUPLICATE_SAME_ACCESS);
      if (!fSuccess)
            return 3;
      CloseHandle(hChildStdoutRd);

      // Create process.
      ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
      siStartInfo.cb = sizeof(STARTUPINFO);  // Create the child process.  
      siStartInfo.dwFlags = STARTF_USESHOWWINDOW;
      siStartInfo.wShowWindow = SW_HIDE;
      fSuccess = CreateProcess(NULL,      
            (LPTSTR)(LPCTSTR)strAddr,       // command line
            NULL,                                          // process security attributes
            NULL,                                          // primary thread security attributes
            TRUE,                                          // handles are inherited
            0,                                                // creation flags
            NULL,                                          // use parent's environment
            NULL,                                          // use parent's current directory
            &siStartInfo,                              // STARTUPINFO pointer
            &piProcInfo);                              // receives PROCESS_INFORMATION

      
      if (!fSuccess)
            AfxMessageBox("Unable to spawn child process, 'Ping.exe' could not be run.");

      if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
            return 8;
      
      
      tmpdlg->m_bRunning = TRUE;

      // Close the write end of the pipe before reading from the
      // read end of the pipe.
       CloseHandle(hChildStdoutWr);

      do
      {
            memset( szBuf, 0, BUFSIZE);
            tmpdlg->m_strOutput += szBuf;
            TRACE(szBuf);
            ::SendMessage( tmpdlg->GetSafeHwnd(), WM_UPDMSG, 0, 0);
      }
      while(ReadFile( hChildStdoutRdDup, szBuf, BUFSIZE, &dwRead, NULL) && dwRead != 0);
                  
      CloseHandle(hChildStdoutRdDup);
      
      tmpdlg->m_bRunning = FALSE;
      return 0;
0
Comment
Question by:niven
[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
  • 4
  • 3
  • 2
9 Comments
 
LVL 8

Expert Comment

by:gelbert
ID: 2693810
Try:
siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
siStartInfo.hStdInput = hChildStdinRd;
siStartInfo.hStdOutput = hChildStdoutWr;
siStartInfo.hStdError = hChildStdoutWr;

STARTF_USESTDHANDLES sets the standard input, standard output, and standard error handles for the process to the handles specified in the hStdInput, hStdOutput, and hStdError members of the STARTUPINFO structure. The CreateProcess function's fInheritHandles parameter must be set to TRUE for this to work properly.
0
 

Author Comment

by:niven
ID: 2693896
Doesn't seem to work...

Do you know what the difference could be between NT and W9x?

0
 

Author Comment

by:niven
ID: 2693927
Doesn't seem to work...

Do you know what the difference could be between NT and W9x?

0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 8

Expert Comment

by:gelbert
ID: 2694112
Take a look at:"INFO: Redirection Issues on Windows 95 MS-DOS Applications"
ID: Q150956
0
 

Author Comment

by:niven
ID: 2694164
I have, and it's just telling me to do exactly what I'm already doing...
(the code is even practically the same)
0
 
LVL 1

Expert Comment

by:charlass
ID: 2699493
You have to set:
saAttr.dwFlags |= STARTF_USESTDHANDLES;

By that is CreateProcess() looking for the new handles in saAttr.hStdOut and ...

SetStdHandle() and DuplicateHandle() are not required (my experience with WinNT).

Feel free to ask for the (wicked) code.
Bye!

0
 

Author Comment

by:niven
ID: 2699719
That's what I'm doing, but it just doesn't do anything...
Could you post some example code?

0
 
LVL 1

Expert Comment

by:charlass
ID: 2699737
Here we go...
(U can't compile it without removing some of my own stuff but the code should be self-explaining)


//===========================================================================
// Execute a console(!) applicatin. Can redirect stdio.
//===========================================================================
// IN:      application            Full(!) name of the application to execute
// IN:      cmd_line            Optional arguments for the app - can be NULL
// IN:      work_dir            Optional - can be NULL (means the current dir)
// IN:      flags                  See GenOsse.h
// RET: 0 == success
//===========================================================================
// Redirection of stdio:
//      The required/created files must/will reside in "work_dir".
//===========================================================================
// WIN32:
//      The code creates the redirection files and hides the console window.
// MAC:
//      The console app is itself responsible to create the redirect files
//      and to hide the window.
//===========================================================================
// Once you called the app, check the redirected files for data.
//===========================================================================
DLLAPI extern int os_execconsole(       const char* application,
                                                      const char* cmd_line,
                                                      const char* work_dir,
                                                      const unsigned flags)
{
// Param check
      if( ! application) { return -1; }

// Remember automatically the previous work dir
      OS_DirectoryStack ds;

// Will contain the expanded redirction file names
      const char stdin_file [] = {"stdin.txt"};
      const char stdout_file[] = {"stdout.txt"};
      const char stderr_file[] = {"stderr.txt"};

// Change into the workdir, if given
      if( work_dir)
            if( os_chdir( work_dir) == -1)
                  return os_errno();

//-----------------------------------------------------------------------------
#ifdef WIN32
// NOTE: All functions/structures are ASCII-forced!
//       You see it by the trails "A".

// WIN32 parameters
      SECURITY_ATTRIBUTES      sa = { sizeof(sa) };      // Open files in inheritable mode
      STARTUPINFOA            si = { sizeof(si) };      // Input for CreateProcess()
      PROCESS_INFORMATION      pi = {0};                        // Output of CreateProcess()

      sa.bInheritHandle            = TRUE;            // Allow inheritance
      sa.lpSecurityDescriptor = NULL;            // handles to the child process

      si.dwFlags |= STARTF_USESHOWWINDOW;
      si.dwFlags |= (flags & OS_EC_REDIRECT_MASK) ? STARTF_USESTDHANDLES : 0;
      si.wShowWindow = (flags & OS_EC_HIDDEN) ? SW_HIDE : 0;

// Open/create the stdio-redirections with the inherited security handle
      if( flags & OS_EC_REDIRECT_STDIN)
            if( (si.hStdOutput = CreateFileA( stdin_file, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, 0, NULL)) == NULL)
                  return GetLastError();

      if( flags & OS_EC_REDIRECT_STDOUT)
            if( (si.hStdOutput = CreateFileA( stdout_file, GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, 0, NULL)) == NULL)
                  return GetLastError();

      if( flags & OS_EC_REDIRECT_STDERR)
            if( (si.hStdError = CreateFileA( stderr_file,  GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, 0, NULL)) == NULL)
                  return GetLastError();

// Build the command line to call
      char cmd[4*MAX_PATH];
      sprintf( cmd, "%s %s", application, (cmd_line ? cmd_line : ""));

// Call the process now! Hot! Only 1.29 USD/min!
      int err = CreateProcessA(NULL,                        // name of process - is done in "cmd"
                                          cmd,                        // the complete command to execute
                                          NULL,                        // lpProcessAttr
                                          NULL,                        // lpThreadAttr
                                          (flags & OS_EC_REDIRECT_MASK),      // bInheritHandles
                                          0,                              // dwCreationFlags
                                          NULL,                        // lpEnvironment
                                          NULL,                        // lpCurrDir
                                          &si,                        // StartupInfo - contains the StdHandles!
                                          &pi);                        // lpProcessInfo
      if( err == FALSE)
      {
      // Oops. "err" is only a boolean flag - get here the correct error value;
            err = GetLastError();
      }
      else
      {
            if( flags & OS_EC_WAIT)
            {
                  switch( err = WaitForSingleObject( pi.hProcess, INFINITE))
                  {
                        case WAIT_ABANDONED:      err = 0;      break;
                        case WAIT_OBJECT_0:            err = 0;      break;
                        case WAIT_TIMEOUT:            break;
                        case WAIT_FAILED:            break;
                        default:                        break;
                  }
            }
            else
            {
                  err = 0;
            }
      }

// Close the opened files, if the call was blocking
      if( err || (flags & OS_EC_WAIT))
      {
            if( si.hStdInput)  { CloseHandle( si.hStdInput); }
            if( si.hStdOutput) { CloseHandle( si.hStdOutput); }
            if( si.hStdError)  { CloseHandle( si.hStdError); }
      }

      return err;
#endif
//-----------------------------------------------------------------------------


0
 
LVL 1

Accepted Solution

by:
charlass earned 300 total points
ID: 2699740
Oops.
Just saw that all tabs are gone.
Request it again at charlass@saxsys.de
0

Featured Post

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

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

Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Want to learn how to record your desktop screen without having to use an outside camera. Click on this video and learn how to use the cool google extension called "Screencastify"! Step 1: Open a new google tab Step 2: Go to the left hand upper corn…
Suggested Courses

721 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