//***************************************************************************** // This function will handle ignore codes and tell the user what is happening. //***************************************************************************** bool _DbgBreakCheck( LPCSTR szFile, int iLine, LPCSTR szExpr, BOOL fConstrained) { STATIC_CONTRACT_THROWS; STATIC_CONTRACT_GC_NOTRIGGER; STATIC_CONTRACT_FORBID_FAULT; STATIC_CONTRACT_DEBUG_ONLY; RaiseExceptionOnAssert(rTestAndRaise); if (DebugBreakOnAssert()) { DebugBreak(); } DBGIGNORE* pDBGIFNORE = GetDBGIGNORE(); _DBGIGNOREDATA *psData; int i; // Check for ignore all. for (i = 0, psData = pDBGIFNORE->Ptr(); i < pDBGIFNORE->Count(); i++, psData++) { if (psData->iLine == iLine && SString::_stricmp(psData->rcFile, szFile) == 0 && psData->bIgnore == true) { return false; } } CONTRACT_VIOLATION(FaultNotFatal | GCViolation | TakesLockViolation); SString debugOutput; SString dialogOutput; SString modulePath; SString dialogTitle; SString dialogIgnoreMessage; BOOL formattedMessages = FALSE; // If we are low on memory we cannot even format a message. If this happens we want to // contain the exception here but display as much information as we can about the exception. if (!fConstrained) { EX_TRY { ClrGetModuleFileName(0, modulePath); debugOutput.Printf( W("\nAssert failure(PID %d [0x%08x], Thread: %d [0x%04x]): %hs\n") W(" File: %hs Line: %d\n") W(" Image: "), GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId(), szExpr, szFile, iLine); debugOutput.Append(modulePath); debugOutput.Append(W("\n\n")); // Change format for message box. The extra spaces in the title // are there to get around format truncation. dialogOutput.Printf( W("%hs\n\n%hs, Line: %d\n\nAbort - Kill program\nRetry - Debug\nIgnore - Keep running\n") W("\n\nImage:\n"), szExpr, szFile, iLine); dialogOutput.Append(modulePath); dialogOutput.Append(W("\n")); dialogTitle.Printf(W("Assert Failure (PID %d, Thread %d/0x%04x)"), GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId()); dialogIgnoreMessage.Printf(W("Ignore the assert for the rest of this run?\nYes - Assert will never fire again.\nNo - Assert will continue to fire.\n\n%hs\nLine: %d\n"), szFile, iLine); formattedMessages = TRUE; } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); }
//***************************************************************************** // This function will handle ignore codes and tell the user what is happening. //***************************************************************************** int _DbgBreakCheck( LPCSTR szFile, int iLine, LPCSTR szExpr) { TCHAR rcBuff[1024+_MAX_PATH]; TCHAR rcPath[_MAX_PATH]; TCHAR rcTitle[64]; _DBGIGNOREDATA *psData; long i; if (DebugBreakOnAssert()) { DebugBreak(); } DBGIGNORE* pDBGIFNORE = GetDBGIGNORE(); // Check for ignore all. for (i=0, psData = pDBGIFNORE->Ptr(); i<pDBGIFNORE->Count(); i++, psData++) { if (psData->iLine == iLine && _stricmp(psData->rcFile, szFile) == 0 && psData->bIgnore == true) return (false); } // Give assert in output for easy access. WszGetModuleFileName(0, rcPath, NumItems(rcPath)); swprintf(rcBuff, L"Assert failure(PID %d [0x%08x], Thread: %d [0x%x]): %hs\n" L" File: %hs, Line: %d Image:\n%s\n", GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId(), szExpr, szFile, iLine, rcPath); WszOutputDebugString(rcBuff); // Write out the error to the console printf("%S\n", rcBuff); LogAssert(szFile, iLine, szExpr); FlushLogging(); // make certain we get the last part of the log fflush(stdout); if (NoGuiOnAssert()) { TerminateOnAssert(); } if (DebugBreakOnAssert()) { return(true); // like a retry } // Change format for message box. The extra spaces in the title // are there to get around format truncation. swprintf(rcBuff, L"%hs\n\n%hs, Line: %d\n\nAbort - Kill program\nRetry - Debug\nIgnore - Keep running\n" L"\n\nImage:\n%s\n", szExpr, szFile, iLine, rcPath); swprintf(rcTitle, L"Assert Failure (PID %d, Thread %d/%x) ", GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId()); // Tell user there was an error. _DbgBreakCount++; int ret = WszMessageBoxInternal(NULL, rcBuff, rcTitle, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION | COMPLUS_MB_SERVICE_NOTIFICATION); --_DbgBreakCount; HMODULE hKrnl32; switch(ret) { // For abort, just quit the app. case IDABORT: TerminateProcess(GetCurrentProcess(), 1); // WszFatalAppExit(0, L"Shutting down"); break; // Tell caller to break at the correct loction. case IDRETRY: hKrnl32 = WszLoadLibrary(L"kernel32.dll"); _ASSERTE(hKrnl32 != NULL); if(hKrnl32) { typedef BOOL (WINAPI *t_pDbgPres)(); t_pDbgPres pFcn = (t_pDbgPres) GetProcAddress(hKrnl32, "IsDebuggerPresent"); // If this function is available, use it. if (pFcn) { if (pFcn()) { SetErrorMode(0); } else LaunchJITDebugger(); } FreeLibrary(hKrnl32); } return (true); // If we want to ignore the assert, find out if this is forever. case IDIGNORE: swprintf(rcBuff, L"Ignore the assert for the rest of this run?\nYes - Assert will never fire again.\nNo - Assert will continue to fire.\n\n%hs\nLine: %d\n", szFile, iLine); if (WszMessageBoxInternal(NULL, rcBuff, L"Ignore Assert Forever?", MB_ICONQUESTION | MB_YESNO | COMPLUS_MB_SERVICE_NOTIFICATION) != IDYES) break; if ((psData = pDBGIFNORE->Append()) == 0) return (false); psData->bIgnore = true; psData->iLine = iLine; strcpy(psData->rcFile, szFile); break; } return (false); }