executing a console program from within a DLL and reading the output

I'm trying to get a DLL i wrote to run a console program (i.e. "PKZIP c:\temp\afile.txt" ) and read the output to a CString var... the DLL runs on a web server with an application server as the DLL caller

Here's how i do it on my sun box (solaris);
----- start code ------

FILE *ptr;
char buf[BUFSIZ];
char stdErr[BUFSIZ];
char cmdStr[256];

strcpy( cmdStr, "/bin/gzip /tmp/afile.txt" ); // just an example

// open a pipe and execute command string / read stderr for command outputs
if ((ptr = popen(cmdStr, "r")) != NULL)
{
      strcpy( stdErr, "" );

      while ( fgets( buf, BUFSIZ, ptr ) != NULL )
      {
            strcat( stdErr, "<br>" );
            strcat( stdErr, buf );
      }
}
else
{
      char Err[1024];
      sprintf( Err, "Can't create pipe (popen failed)" );
      exit(1);
}
pclose( ptr );

----- end code ------

I deperately need an equivalent to work in a Windows environment MFC DLL... oh and i use CSting in Windows as opposed to
char whatever[123]; if that is relavent at all

i know i may not be very clear here but this is as close to explaining it as i can get atm. Any help at this point would be greatly appreciated.

zeek
zeek_jaAsked:
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.

Kyle AbrahamsSenior .Net DeveloperCommented:
what do you need help with, creating the pipe or executing the command?
0
mnashadkaCommented:
You can do the same thing on a windows machine, but popen is _popen and pclose is _pclose.  Just #include <stdio.h>.  There are also Win32 API's like CreatePipe and ReadFile that will do the same thing, but there's nothing wrong with using _popen and _pclose.  Good luck.
0
jkrCommented:
mnashadka is correct, '_popen()' works on Win32 also. If you need all the 'bells an whistles' Win32 has to offer, see http://support.microsoft.com/default.aspx?scid=kb;en-us;190351 ("HOWTO: Spawn Console Processes with Redirected Standard Handles")
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
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

zeek_jaAuthor Commented:
i know that it should work in windows.... but i keep getting the error... here is the code in windows:

---- start win code ----
FILE *ptr;
char buf[BUFSIZ];
char pipeOut[256];

if( ( ptr = _popen( ( cmdString ), "r" ) ) != NULL )
{
      while (  fgets( buf, BUFSIZ, ptr ) != NULL )
      {
            strcat( pipeOut, "<br>" );
            strcat( pipeOut, buf );
      }
}
else
{
      strError = "Can't create pipe (_popen failed)";

      if ( pRequest->AttributeExists( "THROWEXCEPTION" ) )
      {
            pRequest->ThrowException( TAG_ERROR_HEADER, strError ) ;
            exit(1);
      }
}

_pclose( ptr );

---- end win code ----

it seems like i can;t create a pipe... so i tried system( cmdString ); and nothing.. there is no result

I'm stumped here... perhaps a pure win32 approach would be better...

can someone give me the above pasted code in win32 format with CreateProcess or WinExec.... not sure if this is the way to go because the code looks fine to me...

zeek
0
zeek_jaAuthor Commented:
i've tried a different approach... but it only works when the command line does not contain a pipe symbol and i don't get all the output... can anyone add to or give me a better solution... here's what i got so far:

--- start new code ---
CString ExecAndGetOutput( LPCSTR szCommand )
{
    CString sRet= "";
    SECURITY_ATTRIBUTES rSA;
    rSA.nLength=              sizeof(SECURITY_ATTRIBUTES);
    rSA.bInheritHandle=       TRUE;
    rSA.lpSecurityDescriptor= 0;

    HANDLE hReadPipe, hWritePipe;
    CreatePipe( &hReadPipe, &hWritePipe, &rSA, 250000 );
   
   PROCESS_INFORMATION rPI;
    STARTUPINFO rSI;
   memset( &rSI, 0, sizeof(STARTUPINFO));
   rSI.cb=          sizeof(STARTUPINFO);
    rSI.dwFlags=     STARTF_USESHOWWINDOW |STARTF_USESTDHANDLES;
    rSI.wShowWindow= SW_HIDE; //SW_MINIMIZE;
    rSI.hStdOutput=  hWritePipe;
    rSI.hStdError=   hWritePipe;

    CString sCmd; sCmd.Format( "%s", (LPCSTR)szCommand );

    BOOL fRet=CreateProcess(NULL,(LPSTR)(LPCSTR)sCmd, NULL,NULL,TRUE,0,0,0, &rSI, &rPI );
    if ( !fRet ) {
         return( "" );
    }
    //------------------------- wait for the program to end
    WaitForSingleObject( rPI.hProcess, INFINITE);

    //------------------------- read the pipe
    char dest[1000];
    while ( ReadFromPipeNoWait( hReadPipe, dest, sizeof(dest) ) > 0 ) {
         sRet += dest;
    }

    CloseHandle( hReadPipe  );
    CloseHandle( hWritePipe );
    CloseHandle( rPI.hThread);
    CloseHandle( rPI.hProcess);
   
      return( sRet );
}
int ReadFromPipeNoWait( HANDLE hPipe, char* pDest, int nMax )
{
    DWORD nBytesRead= 0;
    DWORD nAvailBytes;
    char cTmp;
    memset( pDest, 0, nMax );

    PeekNamedPipe( hPipe, &cTmp, 1, NULL, &nAvailBytes, NULL );
    if ( nAvailBytes == 0 ) {
         return( nBytesRead );
    }
    BOOL fNoErr= ReadFile( hPipe, pDest, nMax-1, &nBytesRead, NULL);

    if ( !fNoErr ) {  // error
         nBytesRead= 0;
         strError = "Error reading pipe";
    }
    return( nBytesRead );
}

---- end new code ----

so if i use something like

CString cmdLine = "c:\\temp\\pkzip.exe -t -v c:\\temp\afile.txt"; // this is just an example... don't take pkzip literally
ExecAndGetOutput( cmdLine ); it'll work

but if i try something like:

CString cmdLine = "type someFile.txt | c:\\temp\\pkzip.exe -t -v c:\\temp\afile.txt"; // this is just an example... don't take pkzip literally
ExecAndGetOutput( cmdLine ); // it doesn't work


any ideas ???


zeek
0
jkrCommented:
Try

CString cmdLine = "cmd.exe /c type someFile.txt | c:\\temp\\pkzip.exe -t -v c:\\temp\afile.txt";
0
zeek_jaAuthor Commented:
i also need to be able to read all outputs and error outputs... in the code above the cmd.exe /c did do the trick,,thx... but the question also touches on the outputs.. this is critical

any thoughts?

zeek
0
jkrCommented:
:o)
CString cmdLine = "cmd.exe /c  echo << type someFile.txt | c:\\temp\\pkzip.exe -t -v c:\\temp\afile.txt 1>&2" ;
0
zeek_jaAuthor Commented:
when i run cmd.exe /c  echo << type someFile.txt | c:\\temp\\pkzip.exe -t -v c:\\temp\afile.txt 1>&2 i get

<< was unexpected at this time

is this going to give me "all" outputs that would normally be sent to a command window? i.e stdout and stderr ?

zeek
0
zeek_jaAuthor Commented:
fixed it... cmd.exe /c  echo | type someFile.txt | c:\\temp\\pkzip.exe -t -v c:\\temp\afile.txt 1>&2 works perfectly

thanks for the point in the right direction jkr though i had this working great in unix and could have gotten the first method i posted.. i wanted the "bells and whistles"... more info is certainly better than not enough

cheers

zeek
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.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.