#include "stdafx.h" #include "GlobalData.h" #include "Process.h" #include "util.h" #define C_szUserBreakString "\tUser break.\r\n" #define C_lTimeIntervalForErrorChecking 2000 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Launch a new process using CreateProcess and return immediatly // _szExeName contains the name of the executable with FULL PATH. // Note: _szCommandLine can be NULL. // return TRUE if process was created normally or FALSE if not. // Also fill _p_Info with process informations (handle...) // Display a dialog box to the user in case of error on CreateProcess. BOOL fn_bSpawnProcess( char *_szExeName, char *_szCommandLine, LPPROCESS_INFORMATION _p_Info ) { STARTUPINFO stWinInfo; char szDirectory[512]; CString csMessage; int iPathLength; // Spawn process GetStartupInfo( &stWinInfo ); // Get path of executable iPathLength = strrchr( _szExeName, '\\' ) - _szExeName; strncpy( szDirectory, _szExeName, iPathLength ); szDirectory[iPathLength] = 0; // Create process. if( ! CreateProcess( _szExeName, _szCommandLine, NULL, NULL, FALSE, 0, NULL, szDirectory, &stWinInfo, _p_Info ) ) { csMessage = _T("Can't execute '"); csMessage += _szExeName; csMessage += _T("' !\nMake sure path is correct and executable does exist."); AfxMessageBox( csMessage, MB_OK | MB_ICONSTOP ); ZeroMemory( _p_Info, sizeof(_p_Info) ); return FALSE; } return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void fn_vCloseProcessHandles( LPPROCESS_INFORMATION _p_stProcess ) { if( _p_stProcess->hProcess ) CloseHandle( _p_stProcess->hProcess ); if( _p_stProcess->hThread ) CloseHandle( _p_stProcess->hThread ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - tdeStatus fn_eSpawnAndWaitForProcess( char *_szExeName, char *_szCommandLine, HANDLE _hEventStop /*= INVALID_HANDLE_VALUE*/ ) { HANDLE a_hObjectsToWaitFor[2]; int iNbObjectsToWaitFor; DWORD dwWaitReturn, dwExitCode; char szMessage[1024]; PROCESS_INFORMATION stProcess; char szShortExeName[128]; fn_vGetShortExeName( szShortExeName, _szExeName ); // spawn process if( ! fn_bSpawnProcess( _szExeName, _szCommandLine, &stProcess ) ) { sprintf( szMessage, "\tError launching %s\r\n", _szExeName ); fn_vOutputLine( szMessage ); fn_vCloseProcessHandles( &stProcess ); return STATUS_C_Error; } // Prepare to wait for end of process iNbObjectsToWaitFor = 0; a_hObjectsToWaitFor[iNbObjectsToWaitFor++] = stProcess.hProcess; // Test if we must wait for abort event too. if( _hEventStop != INVALID_HANDLE_VALUE ) a_hObjectsToWaitFor[iNbObjectsToWaitFor++] = _hEventStop; do { // Wait for process or abort dwWaitReturn = WaitForMultipleObjects( iNbObjectsToWaitFor, a_hObjectsToWaitFor, FALSE, C_lTimeIntervalForErrorChecking ); // Test if user wants to stop (=abort) if( iNbObjectsToWaitFor > 1 && (dwWaitReturn == WAIT_OBJECT_0+1 || dwWaitReturn == WAIT_ABANDONED_0+1) ) { // Ask for confirmation sprintf( szMessage, "Are you sure you want to terminate '%s' ?", _szExeName ); if( AfxMessageBox( szMessage, MB_YESNO | MB_ICONQUESTION ) == IDYES ) { // Abort is confirmed, we kill the process PostThreadMessage( stProcess.dwThreadId, WM_QUIT, 0, NULL ); dwWaitReturn = WaitForSingleObject( stProcess.hProcess, 3500 ); if( dwWaitReturn == WAIT_TIMEOUT ) TerminateProcess( stProcess.hProcess, 199 ); // We exit if process was killed fn_vCloseProcessHandles( &stProcess ); fn_vOutputLine( C_szUserBreakString ); fn_bCloseSytemErrorDialogBox( szShortExeName, TRUE ); return STATUS_C_UserBreak; } else g_stTheGlobalData.p_oMainDlg -> m_fn_vCancelStopWorkInProgress(); // User does not want to stop anymore, we go for another wait. ResetEvent( _hEventStop ); } else if( dwWaitReturn == WAIT_OBJECT_0 || dwWaitReturn == WAIT_ABANDONED_0 ) { GetExitCodeProcess( stProcess.hProcess, &dwExitCode ); if( dwExitCode != 0 ) { sprintf( szMessage, "\t'%s' has exited with error code %i\r\n", _szExeName, dwExitCode ); fn_vOutputLine( szMessage ); fn_vCloseProcessHandles( &stProcess ); return STATUS_C_Error; } // Process has exited normally. We exit the wait loop. break; } else if( dwWaitReturn == WAIT_TIMEOUT ) { // Here, the time has come to check if an error occured. // We try to find and close any system error dialog box related with the exe if( fn_bCloseSytemErrorDialogBox( szShortExeName ) ) { // if we found one of these boxes, we kill the process and exit. TerminateProcess( stProcess.hProcess, 199 ); fn_vCloseProcessHandles( &stProcess ); sprintf( szMessage, "\tError detected with '%s'\r\n", _szExeName ); fn_vOutputLine( szMessage ); return STATUS_C_Error; } // We found nothing... We go for another wait. } else { // Error. fn_vOutputLine( "\r\n\tInternal error: Error on WaitForMultipleObjects !!!\r\n" ); fn_vCloseProcessHandles( &stProcess ); return STATUS_C_Error; } } while( 1 ); fn_vCloseProcessHandles( &stProcess ); // we deal we an enventual dialog box (saying "access violation" or whatever) if( fn_bCloseSytemErrorDialogBox( szShortExeName ) ) { // If there was an error dialog box, we return an error. sprintf( szMessage, "\tError detected with '%s'\r\n", _szExeName ); fn_vOutputLine( szMessage ); return STATUS_C_Error; } return STATUS_C_OK; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - tdeStatus fn_eWaitForMultipleProcesses( int _iNbProcesses, LPPROCESS_INFORMATION _pa_stInfo, LPCTSTR _szExeNames[], int *_p_iProcessesEnded ) { HANDLE a_hObjectsToWaitFor[64]; int i; DWORD dwWaitReturn, dwExitCode; char szMessage[1024]; // Prepare to wait for end of process for( i=0; i<_iNbProcesses; i ++ ) { a_hObjectsToWaitFor[i] = _pa_stInfo[i].hProcess; } // we must also wait for abort event. a_hObjectsToWaitFor[_iNbProcesses] = g_stTheGlobalData.hEventStop; // Wait for the end of one process or abort dwWaitReturn = WaitForMultipleObjects( _iNbProcesses+1, a_hObjectsToWaitFor, FALSE, INFINITE ); // Test if user wants to stop (=abort) if( dwWaitReturn == WAIT_OBJECT_0+_iNbProcesses || dwWaitReturn == WAIT_ABANDONED_0+_iNbProcesses ) { // Abort is confirmed, we kill the process for( i=0; i<_iNbProcesses; i ++ ) { PostThreadMessage( _pa_stInfo[i].dwThreadId, WM_QUIT, 0, NULL ); } dwWaitReturn = WaitForMultipleObjects( _iNbProcesses, a_hObjectsToWaitFor, TRUE, 3500 ); if( dwWaitReturn == WAIT_TIMEOUT ) { for( i=0; i<_iNbProcesses; i ++ ) TerminateProcess( _pa_stInfo[i].hProcess, 199 ); } // We exit if processes were killed for( i=0; i<_iNbProcesses; i ++ ) fn_vCloseProcessHandles( &_pa_stInfo[i] ); fn_vOutputLine( C_szUserBreakString ); return STATUS_C_UserBreak; } else { for( i=0; i<_iNbProcesses; i ++ ) { if( dwWaitReturn == WAIT_OBJECT_0+i ) { // Mark witch process has exited. *_p_iProcessesEnded = i; GetExitCodeProcess( _pa_stInfo[i].hProcess, &dwExitCode ); fn_vCloseProcessHandles( &_pa_stInfo[i] ); if( dwExitCode != 0 ) { sprintf( szMessage, "\t'%s' has exited with error code %i\r\n", _szExeNames[i], dwExitCode ); fn_vOutputLine( szMessage ); return STATUS_C_Error; } break; } } if( i == _iNbProcesses ) { // Error. fn_vOutputLine( "\r\n\tInternal error: Error on WaitForMultipleObjects !!!\r\n" ); for( i=0; i<_iNbProcesses; i ++ ) fn_vCloseProcessHandles( &_pa_stInfo[i] ); return STATUS_C_Error; } } return STATUS_C_OK; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - tdeStatus fn_eSpawnAndWaitForProcessWithTimeout( char *_szExeName, char *_szCommandLine, DWORD _dwMilliseconds /*=INFINITE*/ ) { HANDLE a_hObjectsToWaitFor[2]; DWORD dwWaitReturn, dwExitCode; char szMessage[1024]; PROCESS_INFORMATION stProcess; DWORD dwStartTime = GetTickCount(); DWORD dwElapsedTime = 0; char szShortExeName[128]; fn_vGetShortExeName( szShortExeName, _szExeName ); // spawn process if( ! fn_bSpawnProcess( _szExeName, _szCommandLine, &stProcess ) ) { sprintf( szMessage, "\tError launching %s\r\n", _szExeName ); fn_vOutputLine( szMessage ); fn_vCloseProcessHandles( &stProcess ); return STATUS_C_Error; } // Prepare to wait for end of process a_hObjectsToWaitFor[0] = stProcess.hProcess; a_hObjectsToWaitFor[1] = g_stTheGlobalData.hEventStop; do { // Wait for process, abort or timeout // We wait for 1500 millisecond, then we check for a system error dialog box. dwWaitReturn = WaitForMultipleObjects( 2, a_hObjectsToWaitFor, FALSE, C_lTimeIntervalForErrorChecking ); dwElapsedTime = GetTickCount() - dwStartTime; // If total time is greater than user timeout, we kill the process if( dwElapsedTime >= _dwMilliseconds ) { fn_vOutputLine( "\t*** Timeout! Killing process...***\r\n" ); PostThreadMessage( stProcess.dwThreadId, WM_QUIT, 0, NULL ); dwWaitReturn = WaitForSingleObject( stProcess.hProcess, 1500 ); if( dwWaitReturn == WAIT_TIMEOUT ) TerminateProcess( stProcess.hProcess, 199 ); fn_vCloseProcessHandles( &stProcess ); // Ok, now we deal we an enventual dialog box (saying "acces violation" or whatever) fn_bCloseSytemErrorDialogBox( szShortExeName, TRUE ); // We exit return STATUS_C_Error; } // Test if user wants to stop (=abort) if( dwWaitReturn == WAIT_OBJECT_0+1 || dwWaitReturn == WAIT_ABANDONED_0+1 ) { // Ask for confirmation sprintf( szMessage, "Are you sure you want to terminate '%s' ?", _szExeName ); if( AfxMessageBox( szMessage, MB_YESNO | MB_ICONQUESTION ) == IDYES ) { // Abort is confirmed, we kill the process PostThreadMessage( stProcess.dwThreadId, WM_QUIT, 0, NULL ); dwWaitReturn = WaitForSingleObject( stProcess.hProcess, 3500 ); if( dwWaitReturn == WAIT_TIMEOUT ) TerminateProcess( stProcess.hProcess, 199 ); // We exit if process was killed fn_vCloseProcessHandles( &stProcess ); fn_vOutputLine( C_szUserBreakString ); // we deal we an enventual dialog box (saying "acces violation" or whatever) fn_bCloseSytemErrorDialogBox( szShortExeName, TRUE ); return STATUS_C_UserBreak; } else g_stTheGlobalData.p_oMainDlg -> m_fn_vCancelStopWorkInProgress(); // User does not want to stop anymore, we go for another wait. ResetEvent( g_stTheGlobalData.hEventStop ); } else if( dwWaitReturn == WAIT_OBJECT_0 || dwWaitReturn == WAIT_ABANDONED_0 ) { GetExitCodeProcess( stProcess.hProcess, &dwExitCode ); if( dwExitCode != 0 ) { sprintf( szMessage, "\t'%s' has exited with error code %i\r\n", _szExeName, dwExitCode ); fn_vOutputLine( szMessage ); fn_vCloseProcessHandles( &stProcess ); // we deal we an enventual dialog box (saying "acces violation" or whatever) fn_bCloseSytemErrorDialogBox( szShortExeName ); return STATUS_C_Error; } // Process has exited normally. We exit the wait loop. break; } else if( dwWaitReturn == WAIT_TIMEOUT ) { // Here, the time has come to check if an error occured. // We try to find and close any system error dialog box related with the exe if( fn_bCloseSytemErrorDialogBox( szShortExeName ) ) { // if we found one of these boxes, we kill the process and exit. TerminateProcess( stProcess.hProcess, 199 ); fn_vCloseProcessHandles( &stProcess ); sprintf( szMessage, "\tError detected with '%s'\r\n", _szExeName ); fn_vOutputLine( szMessage ); return STATUS_C_Error; } // We found nothing... We go for another wait. } else { // Error. fn_vOutputLine( "\r\n\tInternal error: Error on WaitForMultipleObjects !!!\r\n" ); fn_vCloseProcessHandles( &stProcess ); return STATUS_C_Error; } } while( 1 ); fn_vCloseProcessHandles( &stProcess ); // we deal we an enventual dialog box (saying "access violation" or whatever) if( fn_bCloseSytemErrorDialogBox( szShortExeName ) ) { // If there was an error dialog box, we return an error. sprintf( szMessage, "\tError detected with '%s'\r\n", _szExeName ); fn_vOutputLine( szMessage ); return STATUS_C_Error; } return STATUS_C_OK; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - tdeStatus fn_eSpawnAndWaitForProcessWithInputEvents( char *_szExeName, char *_szCommandLine ) { HANDLE a_hObjectsToWaitFor[32]; DWORD dwWaitReturn, dwExitCode; char szMessage[1024]; PROCESS_INFORMATION stProcess; MSG stMsg; char szShortExeName[128]; fn_vGetShortExeName( szShortExeName, _szExeName ); // spawn process if( ! fn_bSpawnProcess( _szExeName, _szCommandLine, &stProcess ) ) { sprintf( szMessage, "\tError launching %s\r\n", _szExeName ); fn_vOutputLine( szMessage ); fn_vCloseProcessHandles( &stProcess ); return STATUS_C_Error; } // Prepare to wait for end of process a_hObjectsToWaitFor[0] = stProcess.hProcess; a_hObjectsToWaitFor[1] = g_stTheGlobalData.hEventStop; do { // Wait for process or abort dwWaitReturn = MsgWaitForMultipleObjects( 2, a_hObjectsToWaitFor, FALSE, C_lTimeIntervalForErrorChecking, QS_ALLINPUT ); // Test if user wants to stop (=abort) if( dwWaitReturn == WAIT_OBJECT_0+1 || dwWaitReturn == WAIT_ABANDONED_0+1 ) { // Ask for confirmation sprintf( szMessage, "Are you sure you want to terminate '%s' ?", _szExeName ); if( AfxMessageBox( szMessage, MB_YESNO | MB_ICONQUESTION ) == IDYES ) { // Abort is confirmed, we kill the process PostThreadMessage( stProcess.dwThreadId, WM_QUIT, 0, NULL ); dwWaitReturn = WaitForSingleObject( stProcess.hProcess, 3500 ); if( dwWaitReturn == WAIT_TIMEOUT ) TerminateProcess( stProcess.hProcess, 199 ); // We exit if process was killed fn_vCloseProcessHandles( &stProcess ); fn_bCloseSytemErrorDialogBox( szShortExeName, TRUE ); fn_vOutputLine( C_szUserBreakString ); return STATUS_C_UserBreak; } else g_stTheGlobalData.p_oMainDlg -> m_fn_vCancelStopWorkInProgress(); // User does not want to stop anymore, we go for another wait. ResetEvent( g_stTheGlobalData.hEventStop ); } else if( dwWaitReturn == WAIT_OBJECT_0 || dwWaitReturn == WAIT_ABANDONED_0 ) { GetExitCodeProcess( stProcess.hProcess, &dwExitCode ); if( dwExitCode != 0 ) { sprintf( szMessage, "\t'%s' has exited with error code %i\r\n", _szExeName, dwExitCode ); fn_vOutputLine( szMessage ); fn_vCloseProcessHandles( &stProcess ); return STATUS_C_Error; } // Process has exited normally. We exit the wait loop. break; } else if( dwWaitReturn == WAIT_OBJECT_0 + 2 ) { // Else, a user event has arrived: treat it. while( PeekMessage( &stMsg, g_stTheGlobalData.p_oMainDlg -> m_hWnd, 0, 0, PM_REMOVE ) ) if( ! g_stTheGlobalData.p_oMainDlg -> PreTranslateMessage( &stMsg ) ) DispatchMessage( &stMsg ); } else if( dwWaitReturn == WAIT_TIMEOUT ) { // Here, the time has come to check if an error occured. // We try to find and close any system error dialog box related with the exe if( fn_bCloseSytemErrorDialogBox( szShortExeName ) ) { // if we found one of these boxes, we kill the process and exit. TerminateProcess( stProcess.hProcess, 199 ); fn_vCloseProcessHandles( &stProcess ); sprintf( szMessage, "\tError detected with '%s'\r\n", _szExeName ); fn_vOutputLine( szMessage ); return STATUS_C_Error; } // We found nothing... We go for another wait. } else { // Error. fn_vOutputLine( "\r\n\tInternal error: Error on MsgWaitForMultipleObjects !!!\r\n" ); fn_vCloseProcessHandles( &stProcess ); return STATUS_C_Error; } } while( 1 ); fn_vCloseProcessHandles( &stProcess ); // we deal we an enventual dialog box (saying "access violation" or whatever) if( fn_bCloseSytemErrorDialogBox( szShortExeName ) ) { // If there was an error dialog box, we return an error. sprintf( szMessage, "\tError detected with '%s'\r\n", _szExeName ); fn_vOutputLine( szMessage ); return STATUS_C_Error; } return STATUS_C_OK; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - tdeStatus fn_eSpawnThreadAndWaitWithInputEvents( AFX_THREADPROC _p_fn_uiThread, LPVOID _p_vParamForThread ) { HANDLE a_hEvents[64]; DWORD dwWaitReturn; MSG stMessage; DWORD dwExitCode = 0; CWinThread *p_oThread = AfxBeginThread( _p_fn_uiThread, _p_vParamForThread ); if( p_oThread == NULL ) { AfxMessageBox( "Unable to create thread !.", MB_OK | MB_ICONEXCLAMATION ); return STATUS_C_Error; } // Disable autodelete (to use handle to thread after it is terminated). p_oThread->m_bAutoDelete = FALSE; // Now, we enter wait loop that wait either for thread end or for input message a_hEvents[0] = p_oThread->m_hThread; while( 1 ) { dwWaitReturn = MsgWaitForMultipleObjects( 1, a_hEvents, FALSE, INFINITE, QS_ALLINPUT ); // If an input event has arrived, we dispatch it. if( dwWaitReturn == WAIT_OBJECT_0 + 1 ) { while( PeekMessage( &stMessage, g_stTheGlobalData.p_oMainDlg->m_hWnd, 0, 0, PM_REMOVE ) ) if( g_stTheGlobalData.p_oMainDlg -> PreTranslateMessage( &stMessage ) == 0 ) DispatchMessage( &stMessage ); } // if thread has exited else if( dwWaitReturn == WAIT_OBJECT_0 || dwWaitReturn == WAIT_ABANDONED_0 ) { break; } else { // Error. TCHAR szMessage[1024]; ::FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language szMessage, 1024, NULL ); fn_vOutputLine( "\r\n\tInternal error: Error on MsgWaitForMultipleObjects :\r\n\t" ); fn_vOutputLine( szMessage ); fn_vOutputLine( "\r\n" ); delete p_oThread; return STATUS_C_Error; } } GetExitCodeThread( p_oThread->m_hThread, &dwExitCode ); // if( dwExitCode == STATUS_C_UserBreak ) // fn_vOutputLine( C_szUserBreakString ); delete p_oThread; return (tdeStatus)dwExitCode; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - typedef struct tdstEnumWinStruct_ { char *p_szExeName; BOOL bActionDone; UINT uiNumberOfButton; } tdstEnumWinStruct; // Callback to enumerate all controls in a window. BOOL CALLBACK EnumChildWindowProc( HWND _hwnd, LPARAM _p_stParam ) { char szTitle[512]; tdstEnumWinStruct *p_stEnumChild = (tdstEnumWinStruct *)_p_stParam; DWORD dwID = GetClassLong( _hwnd, GCW_ATOM ); // We only check statics switch( dwID ) { case 0xC01B : GetWindowText( _hwnd, szTitle, 512 ); // Check if caption contains the name of the exe if( stristr( szTitle, p_stEnumChild->p_szExeName ) != NULL ) { // Name is detected p_stEnumChild->bActionDone = TRUE; } break; case 0xC015: p_stEnumChild->uiNumberOfButton++; break; default: break; } return TRUE; } BOOL fn_bCheckWindow( HWND _hMessageBox, char *_szString, UINT *_p_uiNbButtons = NULL ) { tdstEnumWinStruct stEnumChild; stEnumChild.p_szExeName = _szString; stEnumChild.bActionDone = FALSE; stEnumChild.uiNumberOfButton = 0; // Search in controls if one of them contains the given string EnumChildWindows( _hMessageBox, EnumChildWindowProc, (LPARAM)&stEnumChild ); if( _p_uiNbButtons ) *_p_uiNbButtons = stEnumChild.uiNumberOfButton; return stEnumChild.bActionDone; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Callback to enumerate all windows. // (called by fn_bCloseSytemErrorDialogBox) BOOL CALLBACK EnumWindowProc( HWND _hwnd, LPARAM _p_stParam ) { char szTitle[512]; DWORD dwID = GetClassLong( _hwnd, GCW_ATOM ); tdstEnumWinStruct *p_stEnumWin = (tdstEnumWinStruct *)_p_stParam; UINT uiNbButtons; GetWindowText( _hwnd, szTitle, 512 ); // If window is a dialog box if( dwID == 0x8002 ) { // Check if it's an "application error" box. if( stristr( szTitle, p_stEnumWin->p_szExeName ) && (stristr( szTitle, "erreur d'application" ) || stristr( szTitle, "application error" )) ) { // Now, we close that box ! ::PostMessage( _hwnd, WM_CLOSE, 0, 0 ); p_stEnumWin->bActionDone = TRUE; // Return FALSE to stop enumeration return FALSE; } // Else, it may be an assert box. else if( (stristr( szTitle, "Debug Lib" ) || stristr( szTitle, "Runtime Lib" )) && fn_bCheckWindow( _hwnd, "??" ) && fn_bCheckWindow( _hwnd, p_stEnumWin->p_szExeName, &uiNbButtons ) && uiNbButtons == 3 ) { ::PostMessage( _hwnd, WM_CLOSE, 0, 0 ); p_stEnumWin->bActionDone = TRUE; // Return FALSE to stop enumeration return FALSE; } // Check if it's an "illegal operation" box. else { char *p_szExtension = strrchr( p_stEnumWin->p_szExeName, '.' ); if( p_szExtension ) *p_szExtension = 0; if( stristr( szTitle, p_stEnumWin->p_szExeName ) && fn_bCheckWindow( _hwnd, "Opération non conforme", &uiNbButtons ) && uiNbButtons >= 2 && uiNbButtons < 4 ) { // Now, we close that box ! ::PostMessage( _hwnd, WM_CLOSE, 0, 0 ); p_stEnumWin->bActionDone = TRUE; // Return FALSE to stop enumeration return FALSE; } if( p_szExtension ) *p_szExtension = '.'; } } // We also handle dr watson's windows... else if( stristr( szTitle, "Watson" ) != NULL ) { // Check if this dr. Watson's window talks about us ! if( fn_bCheckWindow( _hwnd, p_stEnumWin->p_szExeName ) ) { ::PostMessage( _hwnd, WM_CLOSE, 0, 0 ); p_stEnumWin->bActionDone = TRUE; // Return FALSE to stop enumeration return FALSE; } } // Window not found, we continue return TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get all windows, check if this is a system or dr. watson's window // and it is related to ExeName, then eventually close it. // Return TRUE if a window was closed, FALSE otherwise. BOOL fn_bCloseSytemErrorDialogBox( char *_szExeName, BOOL bForceClose /*=FALSE*/) { tdstEnumWinStruct stEnumWin; if( ! g_stTheGlobalData.bAutoDetectErrors && ! bForceClose ) return FALSE; stEnumWin.p_szExeName = _szExeName; stEnumWin.bActionDone = FALSE; EnumWindows( EnumWindowProc, (LPARAM)&stEnumWin ); return stEnumWin.bActionDone; }