Using a compiler from within C# runtime code

I am writing a program in Builder 4 which creates a text skeleton of a program from an object diagram. I want to be able to compile this from within my program using something like the GNU free mingw32 compiler when the user clicks some button. Any suggestions?

Secondly can I get access to any output error messages etc? Ideally I would like this to appear to run as part of my own program rather than opening the dos window and being a separate entity. I want to give the user feedback from the compiler without them having to go back to my program for themselves. Is this possible?
jukevAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
DanRollinsConnect With a Mentor Commented:
jukey,
Here is a useful utility function that actually does all that you want:

CString ExecAndGetOutput(LPCSTR szCommand, LPCSTR szParms )
{
     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_NORMAL; // SW_HIDE; //SW_MINIMIZE;
     rSI.hStdOutput=  hWritePipe;
     rSI.hStdError=   hWritePipe;

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

     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;
          // MessageBox("Error reading pipe");
     }
     return( nBytesRead );
}

It uses a few MFC classes, but of course, the program that you compile would not need to use MFC, and it's not too hard to convert it to different classes such as std::string or just char array buffers.

To use the function, call like this:

CString sProgOutput=
ExecAndGetOutput( "c:\\mydir\\mingw32.exe", "abc.cpp" );

The final parameter needs to be a string containing all of the command-line parameters typically used to execute the mingw32 compiler (or whatever free compiler you end up selecting) and compile a particular module.  You will need to research that yourself.

-- Dan
0
 
BitTwiddlerCommented:
You could create the process with CreateProcess() and use the hStdInput, hStdOutput, and hStdError fields of the STARTUP_INFO struct you pass to CreateProcess().  This would allow you to grab the input, output, and error information from the compiler.  A simple example follows...

    startInfo.dwFlags     = STARTF_USESTDHANDLES;
    startInfo.hStdInput   = GetStdHandle(STD_INPUT_HANDLE);
    startInfo.hStdOutput  = GetStdHandle(STD_OUTPUT_HANDLE);
    startInfo.hStdError   = GetStdHandle(STD_ERROR_HANDLE);

    b = CreateProcess(
            progname,
            buf,
            NULL,
            NULL,
            TRUE,
            0,
            NULL,
            NULL,
            &startInfo,
            &pidInfo);

The example isn't complete, as you'd need to fill in additional fields of startInfo, pidInfo, etc., but this should get you going in the right direction.

HTH
0
 
DanRollinsCommented:
Hi BitTwiddler,
Welcome to EE!
The experts in this section have agreed to post Comments rather than Answers.  That prevents the question from being 'locked' -- keeps the question in the upper part of the list so that more experts will see it and provide help.

As you said yourself, your post is not a complete answer, and nothing less than a 'complete and only-possible valid' solution should be marked as an 'Answer'.

So in the future, please post Comments, like everybody else.  Thanks!

-- Dan
0
 
jukevAuthor Commented:
No offence BitTwiddler but I need a bit more help than this. At least a bit of an explanation of  what that code does. I will have a go with what you have submitted but I want to open this back up to see if you or anyone else can give me a bit more info
0
 
jukevAuthor Commented:
thanx so much
0
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.

All Courses

From novice to tech pro — start learning today.