suriyamohan
October 21st, 2002, 11:49 AM
Hi,
My doubt is as follows.Let us consider a file samp.exe (program 1) which is susceptible to runtime errors (say for example "Divide by zero error"). This is an example given by me to denote an "exe" where a run time error occur. But actually this is an exe file (program 1) given by a customer where the run time error occurs. so we cannot touch the codings of program 1.so my job is to call that exe (program 1) from program 2 and trap the run time error from program 2 itself. so we are not allowed to include the try-except method of exception handling in program 1. so what i did is, i called program 1's exe from program 2 using the CreateProcess(). so I include the try-except exception handling in program 2. But still the run time error is not trapped. That is, as i said earlier a message box appears indicating "Integer division by zero" (this is an example only. The customer program may contain any run time error) and the program stops abruptly.so my requirement is, I should call the program 2 from program 1 and trap the run time that occurs in program 1 without touching the codings of program 1. So all exception handling should be done in program 2 only. The sample coding of program 2 is given below.so please help me in this regard. Any help regarding this will be appreciable.
/* Inclusion of exception handling in program 2 */
#include <Windows.h>
#include <stdio.h>
#include <iostream.h>
/* Function Prototypes */
void DisplayError(char *pszAPI);
void ReadAndHandleOutput(HANDLE hPipeRead);
void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr);
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam);
void do_exception_record(LPEXCEPTION_RECORD e);
bool fatal_thrown_hardware_exp(LPEXCEPTION_POINTERS e);
/* Global Definition */
HANDLE hChildProcess = NULL;
HANDLE hStdIn = NULL; // Handle to parents std input.
BOOL bRunThread = TRUE;
void main ()
{
HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
HANDLE hInputWriteTmp,hInputRead,hInputWrite;
HANDLE hErrorWrite;
HANDLE hThread;
DWORD ThreadId;
SECURITY_ATTRIBUTES sa;
// Set up the security attributes struct.
sa.nLength= sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
// Create the child output pipe.
if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
DisplayError("CreatePipe");
// Create a duplicate of the output write handle for the std error
// write handle. This is necessary in case the child application
// closes one of its std output handles.
if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
GetCurrentProcess(),&hErrorWrite,0,
TRUE,DUPLICATE_SAME_ACCESS))
DisplayError("DuplicateHandle"); // Create the child input pipe.
if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
DisplayError("CreatePipe");
// Create new output read handle and the input write handles. Set
// the Properties to FALSE. Otherwise, the child inherits the
// properties and, as a result, non-closeable handles to the pipes
// are created.
if (!DuplicateHandle(GetCurrentProcess(),
hOutputReadTmp,
GetCurrentProcess(),
&hOutputRead, // Address of new handle.
0,
FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS))
DisplayError("DupliateHandle");
if (!DuplicateHandle(GetCurrentProcess(),
hInputWriteTmp,
GetCurrentProcess(),
&hInputWrite, // Address of new handle.
0,
FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS))
DisplayError("DuplicateHandle");
// Close inheritable copies of the handles you do not want to be
// inherited.
if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle");
if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle");
if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE )
DisplayError("GetStdHandle");
PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite);
if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle");
if (!CloseHandle(hInputRead )) DisplayError("CloseHandle");
if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle");
// Launch the thread that gets the input and sends it to the child.
hThread = CreateThread(NULL,0,GetAndSendInputThread,
(LPVOID)hInputWrite,0,&ThreadId);
if (hThread == NULL) DisplayError("CreateThread");
// Read the child's output.
ReadAndHandleOutput(hOutputRead);
// Redirection is complete
// Force the read on the input to return by closing the stdin handle.
if (!CloseHandle(hStdIn)) DisplayError("CloseHandle");
// Tell the thread to exit and wait for thread to die.
bRunThread = FALSE;
if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
DisplayError("WaitForSingleObject");
if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle");
if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle");
}
void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
// Set up the start up info struct.
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hChildStdOut;
si.hStdInput = hChildStdIn;
si.hStdError = hChildStdErr;
si.wShowWindow = SW_HIDE;
__try
{
if (!CreateProcess(NULL,
"D:\\Debug\\samp.exe aaa bbb",
NULL,
NULL,
TRUE,
0,//CREATE_DEFAULT_ERROR_MODE,//CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi))
DisplayError("CreateProcess");
}
__except(fatal_thrown_hardware_exp(GetExceptionInformation()))
{
fprintf(stderr,"error has occured");
cerr<<"\n another way to write to stderr using standard c++ lib"<<endl;
exit(0);
}
// Set global child process handle to cause threads to exit.
hChildProcess = pi.hProcess; // Close any unnecessary handles.
if (!CloseHandle(pi.hThread)) DisplayError("CloseHandle");
}
bool fatal_thrown_hardware_exp(LPEXCEPTION_POINTERS e)
{
cerr<<"Fatal hardware type exception."<<endl;
do_exception_record(e->ExceptionRecord);
return true;
}
void do_exception_record(LPEXCEPTION_RECORD e)
{
char address[64];
sprintf(address,"%X",e->ExceptionAddress);
switch(e->ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
cerr<<"Access Violation"<<endl;
if(e->NumberParameters >= 2)
{
if(e->ExceptionInformation[0] == 0)
cerr<<"Process tried to read"<<endl;
else
cerr<<"Process tried to write"<<endl;
}
sprintf(address,"%X",e->ExceptionInformation[1]);
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
cerr<<"Divide By Zero"<<endl;
break;
default:
cerr<<"unknown"<<endl;
break;
}
if(e->ExceptionFlags == EXCEPTION_NONCONTINUABLE)
cerr<<"Execution must terminate"<<endl;
else
cerr<<"Execution could continue"<<endl;
if(e->ExceptionRecord != NULL)
{
cerr<<"*->Next Exception in chain*->"<<endl;
do_exception_record(e->ExceptionRecord);
}
}
void ReadAndHandleOutput(HANDLE hPipeRead)
{
CHAR lpBuffer[256];
DWORD nBytesRead;
DWORD nCharsWritten;
nBytesRead = sizeof(lpBuffer);
memset(lpBuffer,0,sizeof(lpBuffer));
while(TRUE)
{
if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
&nBytesRead,NULL) || !nBytesRead)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
break; // pipe done - normal exit path.
else
DisplayError("ReadFile"); // Something bad happened.
}
// Display the character read on the screen.
if (!WriteConsole(GetStdHandle(STD_ERROR_HANDLE),lpBuffer,
nBytesRead,&nCharsWritten,NULL))
DisplayError("WriteConsole");
}
}
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam)
{
CHAR read_buff[256];
DWORD nBytesRead,nBytesWrote;
HANDLE hPipeWrite = (HANDLE)lpvThreadParam;
// Get input from our console and send it to child through the pipe.
while (bRunThread)
{
if(!ReadConsole(hStdIn,read_buff,1,&nBytesRead,NULL))
DisplayError("ReadConsole");
read_buff[nBytesRead] = '\0'; // Follow input with a NULL.
if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL))
{
if (GetLastError() == ERROR_NO_DATA)
break; // Pipe was closed (normal exit path).
else
DisplayError("WriteFile");
}
}
return 1;
}
My doubt is as follows.Let us consider a file samp.exe (program 1) which is susceptible to runtime errors (say for example "Divide by zero error"). This is an example given by me to denote an "exe" where a run time error occur. But actually this is an exe file (program 1) given by a customer where the run time error occurs. so we cannot touch the codings of program 1.so my job is to call that exe (program 1) from program 2 and trap the run time error from program 2 itself. so we are not allowed to include the try-except method of exception handling in program 1. so what i did is, i called program 1's exe from program 2 using the CreateProcess(). so I include the try-except exception handling in program 2. But still the run time error is not trapped. That is, as i said earlier a message box appears indicating "Integer division by zero" (this is an example only. The customer program may contain any run time error) and the program stops abruptly.so my requirement is, I should call the program 2 from program 1 and trap the run time that occurs in program 1 without touching the codings of program 1. So all exception handling should be done in program 2 only. The sample coding of program 2 is given below.so please help me in this regard. Any help regarding this will be appreciable.
/* Inclusion of exception handling in program 2 */
#include <Windows.h>
#include <stdio.h>
#include <iostream.h>
/* Function Prototypes */
void DisplayError(char *pszAPI);
void ReadAndHandleOutput(HANDLE hPipeRead);
void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr);
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam);
void do_exception_record(LPEXCEPTION_RECORD e);
bool fatal_thrown_hardware_exp(LPEXCEPTION_POINTERS e);
/* Global Definition */
HANDLE hChildProcess = NULL;
HANDLE hStdIn = NULL; // Handle to parents std input.
BOOL bRunThread = TRUE;
void main ()
{
HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
HANDLE hInputWriteTmp,hInputRead,hInputWrite;
HANDLE hErrorWrite;
HANDLE hThread;
DWORD ThreadId;
SECURITY_ATTRIBUTES sa;
// Set up the security attributes struct.
sa.nLength= sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
// Create the child output pipe.
if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
DisplayError("CreatePipe");
// Create a duplicate of the output write handle for the std error
// write handle. This is necessary in case the child application
// closes one of its std output handles.
if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
GetCurrentProcess(),&hErrorWrite,0,
TRUE,DUPLICATE_SAME_ACCESS))
DisplayError("DuplicateHandle"); // Create the child input pipe.
if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
DisplayError("CreatePipe");
// Create new output read handle and the input write handles. Set
// the Properties to FALSE. Otherwise, the child inherits the
// properties and, as a result, non-closeable handles to the pipes
// are created.
if (!DuplicateHandle(GetCurrentProcess(),
hOutputReadTmp,
GetCurrentProcess(),
&hOutputRead, // Address of new handle.
0,
FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS))
DisplayError("DupliateHandle");
if (!DuplicateHandle(GetCurrentProcess(),
hInputWriteTmp,
GetCurrentProcess(),
&hInputWrite, // Address of new handle.
0,
FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS))
DisplayError("DuplicateHandle");
// Close inheritable copies of the handles you do not want to be
// inherited.
if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle");
if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle");
if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE )
DisplayError("GetStdHandle");
PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite);
if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle");
if (!CloseHandle(hInputRead )) DisplayError("CloseHandle");
if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle");
// Launch the thread that gets the input and sends it to the child.
hThread = CreateThread(NULL,0,GetAndSendInputThread,
(LPVOID)hInputWrite,0,&ThreadId);
if (hThread == NULL) DisplayError("CreateThread");
// Read the child's output.
ReadAndHandleOutput(hOutputRead);
// Redirection is complete
// Force the read on the input to return by closing the stdin handle.
if (!CloseHandle(hStdIn)) DisplayError("CloseHandle");
// Tell the thread to exit and wait for thread to die.
bRunThread = FALSE;
if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
DisplayError("WaitForSingleObject");
if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle");
if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle");
}
void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
// Set up the start up info struct.
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hChildStdOut;
si.hStdInput = hChildStdIn;
si.hStdError = hChildStdErr;
si.wShowWindow = SW_HIDE;
__try
{
if (!CreateProcess(NULL,
"D:\\Debug\\samp.exe aaa bbb",
NULL,
NULL,
TRUE,
0,//CREATE_DEFAULT_ERROR_MODE,//CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi))
DisplayError("CreateProcess");
}
__except(fatal_thrown_hardware_exp(GetExceptionInformation()))
{
fprintf(stderr,"error has occured");
cerr<<"\n another way to write to stderr using standard c++ lib"<<endl;
exit(0);
}
// Set global child process handle to cause threads to exit.
hChildProcess = pi.hProcess; // Close any unnecessary handles.
if (!CloseHandle(pi.hThread)) DisplayError("CloseHandle");
}
bool fatal_thrown_hardware_exp(LPEXCEPTION_POINTERS e)
{
cerr<<"Fatal hardware type exception."<<endl;
do_exception_record(e->ExceptionRecord);
return true;
}
void do_exception_record(LPEXCEPTION_RECORD e)
{
char address[64];
sprintf(address,"%X",e->ExceptionAddress);
switch(e->ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
cerr<<"Access Violation"<<endl;
if(e->NumberParameters >= 2)
{
if(e->ExceptionInformation[0] == 0)
cerr<<"Process tried to read"<<endl;
else
cerr<<"Process tried to write"<<endl;
}
sprintf(address,"%X",e->ExceptionInformation[1]);
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
cerr<<"Divide By Zero"<<endl;
break;
default:
cerr<<"unknown"<<endl;
break;
}
if(e->ExceptionFlags == EXCEPTION_NONCONTINUABLE)
cerr<<"Execution must terminate"<<endl;
else
cerr<<"Execution could continue"<<endl;
if(e->ExceptionRecord != NULL)
{
cerr<<"*->Next Exception in chain*->"<<endl;
do_exception_record(e->ExceptionRecord);
}
}
void ReadAndHandleOutput(HANDLE hPipeRead)
{
CHAR lpBuffer[256];
DWORD nBytesRead;
DWORD nCharsWritten;
nBytesRead = sizeof(lpBuffer);
memset(lpBuffer,0,sizeof(lpBuffer));
while(TRUE)
{
if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
&nBytesRead,NULL) || !nBytesRead)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
break; // pipe done - normal exit path.
else
DisplayError("ReadFile"); // Something bad happened.
}
// Display the character read on the screen.
if (!WriteConsole(GetStdHandle(STD_ERROR_HANDLE),lpBuffer,
nBytesRead,&nCharsWritten,NULL))
DisplayError("WriteConsole");
}
}
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam)
{
CHAR read_buff[256];
DWORD nBytesRead,nBytesWrote;
HANDLE hPipeWrite = (HANDLE)lpvThreadParam;
// Get input from our console and send it to child through the pipe.
while (bRunThread)
{
if(!ReadConsole(hStdIn,read_buff,1,&nBytesRead,NULL))
DisplayError("ReadConsole");
read_buff[nBytesRead] = '\0'; // Follow input with a NULL.
if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL))
{
if (GetLastError() == ERROR_NO_DATA)
break; // Pipe was closed (normal exit path).
else
DisplayError("WriteFile");
}
}
return 1;
}