home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
crt
/
src
/
dbgrpt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-17
|
29KB
|
1,033 lines
/***
*dbgrpt.c - Debug CRT Reporting Functions
*
* Copyright (c) 1988-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*
*******************************************************************************/
#ifdef _DEBUG
#include <internal.h>
#include <mtdll.h>
#include <malloc.h>
#include <mbstring.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <dbgint.h>
#include <signal.h>
#include <string.h>
#include <awint.h>
#ifdef _WIN32
#include <windows.h>
#define _CrtInterlockedIncrement InterlockedIncrement
#define _CrtInterlockedDecrement InterlockedDecrement
#else /* _WIN32 */
#define FALSE 0
#define TRUE 1
#define BYTE char
#include <macos\msvcmac.h>
#include <macos\Desk.h>
#include <macos\Dialogs.h>
#include <macos\Events.h>
#include <macos\Fonts.h>
#include <macos\Memory.h>
#include <macos\LowMem.h>
#include <macos\Menus.h>
#include <macos\OSUtils.h>
#include <macos\QuickDra.h>
#include <macos\Resource.h>
#include <macos\Types.h>
#include <macos\Windows.h>
#include <macos\TextUtil.h>
#include <macos\SegLoad.h>
#include <macos\files.h>
#include <macos\gestalt.h>
__inline long __cdecl _CrtInterlockedIncrement(long * plVar) { return ++(*plVar); }
__inline long __cdecl _CrtInterlockedDecrement(long * plVar) { return --(*plVar); }
static void __cdecl _CrtOutputDebugString(char * sz);
#endif /* _WIN32 */
/*---------------------------------------------------------------------------
*
* Debug Reporting
*
--------------------------------------------------------------------------*/
static int CrtMessageWindow(
int,
const char *,
const char *,
const char *,
const char *
);
_CRT_REPORT_HOOK _pfnReportHook;
_CRTIMP long _crtAssertBusy = -1;
int _CrtDbgMode[_CRT_ERRCNT] = {
#ifdef _WIN32
_CRTDBG_MODE_DEBUG,
_CRTDBG_MODE_WNDW,
_CRTDBG_MODE_WNDW
#else /* _WIN32 */
_CRTDBG_MODE_DEBUG,
_CRTDBG_MODE_DEBUG,
_CRTDBG_MODE_DEBUG
#endif /* _WIN32 */
};
_HFILE _CrtDbgFile[_CRT_ERRCNT] = { _CRTDBG_INVALID_HFILE,
_CRTDBG_INVALID_HFILE,
_CRTDBG_INVALID_HFILE
};
static const char * _CrtDbgModeMsg[_CRT_ERRCNT] = { "Warning", "Error", "Assertion Failed" };
/***
*void _CrtDebugBreak - call OS-specific debug function
*
*Purpose:
* call OS-specific debug function
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
#undef _CrtDbgBreak
_CRTIMP void _cdecl _CrtDbgBreak(
void
)
{
#ifdef _WIN32
DebugBreak();
#else /* _WIN32 */
Debugger();
#endif /* _WIN32 */
}
/***
*int _CrtSetReportMode - set the reporting mode for a given report type
*
*Purpose:
* set the reporting mode for a given report type
*
*Entry:
* int nRptType - the report type
* int fMode - new mode for given report type
*
*Exit:
* previous mode for given report type
*
*Exceptions:
*
*******************************************************************************/
_CRTIMP int __cdecl _CrtSetReportMode(
int nRptType,
int fMode
)
{
int oldMode;
if (nRptType < 0 || nRptType >= _CRT_ERRCNT)
return -1;
if (fMode == _CRTDBG_REPORT_MODE)
return _CrtDbgMode[nRptType];
/* verify flags values */
if (fMode & ~(_CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW))
return -1;
oldMode = _CrtDbgMode[nRptType];
_CrtDbgMode[nRptType] = fMode;
return oldMode;
}
/***
*int _CrtSetReportFile - set the reporting file for a given report type
*
*Purpose:
* set the reporting file for a given report type
*
*Entry:
* int nRptType - the report type
* _HFILE hFile - new file for given report type
*
*Exit:
* previous file for given report type
*
*Exceptions:
*
*******************************************************************************/
_CRTIMP _HFILE __cdecl _CrtSetReportFile(
int nRptType,
_HFILE hFile
)
{
_HFILE oldFile;
if (nRptType < 0 || nRptType >= _CRT_ERRCNT)
return _CRTDBG_HFILE_ERROR;
if (hFile == _CRTDBG_REPORT_FILE)
return _CrtDbgFile[nRptType];
oldFile = _CrtDbgFile[nRptType];
#ifdef _WIN32
if (_CRTDBG_FILE_STDOUT == hFile)
_CrtDbgFile[nRptType] = GetStdHandle(STD_OUTPUT_HANDLE);
else if (_CRTDBG_FILE_STDERR == hFile)
_CrtDbgFile[nRptType] = GetStdHandle(STD_ERROR_HANDLE);
#else /* _WIN32 */
if (_CRTDBG_FILE_STDOUT == hFile || _CRTDBG_FILE_STDERR == hFile)
return _CRTDBG_HFILE_ERROR;
#endif /* _WIN32 */
else
_CrtDbgFile[nRptType] = hFile;
return oldFile;
}
/***
*_CRT_REPORT_HOOK _CrtSetReportHook() - set client report hook
*
*Purpose:
* set client report hook
*
*Entry:
* _CRT_REPORT_HOOK pfnNewHook - new report hook
*
*Exit:
* return previous hook
*
*Exceptions:
*
*******************************************************************************/
_CRTIMP _CRT_REPORT_HOOK __cdecl _CrtSetReportHook(
_CRT_REPORT_HOOK pfnNewHook
)
{
_CRT_REPORT_HOOK pfnOldHook = _pfnReportHook;
_pfnReportHook = pfnNewHook;
return pfnOldHook;
}
#define MAXLINELEN 64
#define MAX_MSG 4096
#define TOOLONGMSG "_CrtDbgReport: String too long or IO Error"
/***
*int _CrtDbgReport() - primary reporting function
*
*Purpose:
* Display a message window with the following format.
*
* ================= Microsft Visual C++ Debug Library ================
*
* {Warning! | Error! | Assertion Failed!}
*
* Program: c:\test\mytest\foo.exe
* [Module: c:\test\mytest\bar.dll]
* [File: c:\test\mytest\bar.c]
* [Line: 69]
*
* {<warning or error message> | Expression: <expression>}
*
* [For information on how your program can cause an assertion
* failure, see the Visual C++ documentation on asserts]
*
* (Press Retry to debug the application)
*
* ===================================================================
*
*Entry:
* int nRptType - report type
* const char * szFile - file name
* int nLine - line number
* const char * szModule - module name
* const char * szFormat - format string
* ... - var args
*
*Exit:
* if (MessageBox)
* {
* Abort -> aborts
* Retry -> return TRUE
* Ignore-> return FALSE
* }
* else
* return FALSE
*
*Exceptions:
*
*******************************************************************************/
_CRTIMP int __cdecl _CrtDbgReport(
int nRptType,
const char * szFile,
int nLine,
const char * szModule,
const char * szFormat,
...
)
{
int retval;
va_list arglist;
char szLineMessage[MAX_MSG] = {0};
char szOutMessage[MAX_MSG] = {0};
char szUserMessage[MAX_MSG] = {0};
#define ASSERTINTRO1 "Assertion failed: "
#define ASSERTINTRO2 "Assertion failed!"
va_start(arglist, szFormat);
if (nRptType < 0 || nRptType >= _CRT_ERRCNT)
return -1;
/*
* handle the (hopefully rare) case of
*
* 1) ASSERT while already dealing with an ASSERT
* or
* 2) two threads asserting at the same time
*/
if (_CRT_ASSERT == nRptType && _CrtInterlockedIncrement(&_crtAssertBusy) > 0)
{
/* use only 'safe' functions -- must not assert in here! */
#ifdef _WIN32
static int (APIENTRY *pfnwsprintfA)(LPSTR, LPCSTR, ...) = NULL;
if (NULL == pfnwsprintfA)
{
HANDLE hlib = LoadLibrary("user32.dll");
if (NULL == hlib || NULL == (pfnwsprintfA =
(int (APIENTRY *)(LPSTR, LPCSTR, ...))
GetProcAddress(hlib, "wsprintfA")))
return -1;
}
(*pfnwsprintfA)( szOutMessage,
"Second Chance Assertion Failed: File %s, Line %d\n",
szFile, nLine);
OutputDebugString(szOutMessage);
#else /* _WIN32 */
strcpy(szOutMessage, "Second Chance Assertion Failed: File ");
strcat(szOutMessage, szFile);
strcat(szOutMessage, ", Line ");
numtostring(nLine, &szOutMessage[strlen(szOutMessage)]);
strcat(szOutMessage, "\n");
_CrtOutputDebugString(szOutMessage);
#endif /* _WIN32 */
_CrtInterlockedDecrement(&_crtAssertBusy);
_CrtDbgBreak();
return -1;
}
if (szFormat && _vsnprintf(szUserMessage,
MAX_MSG-max(sizeof(ASSERTINTRO1),sizeof(ASSERTINTRO2)),
szFormat,
arglist) < 0)
strcpy(szUserMessage, TOOLONGMSG);
if (_CRT_ASSERT == nRptType)
strcpy(szLineMessage, szFormat ? ASSERTINTRO1 : ASSERTINTRO2);
strcat(szLineMessage, szUserMessage);
if (_CRT_ASSERT == nRptType)
{
if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_FILE)
strcat(szLineMessage, "\r");
strcat(szLineMessage, "\n");
}
if (szFile)
{
if (_snprintf(szOutMessage, MAX_MSG, "%s(%d) : %s",
szFile, nLine, szLineMessage) < 0)
strcpy(szOutMessage, TOOLONGMSG);
}
else
strcpy(szOutMessage, szLineMessage);
/* user hook may handle report */
if (_pfnReportHook && (*_pfnReportHook)(nRptType, szOutMessage, &retval))
{
if (_CRT_ASSERT == nRptType)
_CrtInterlockedDecrement(&_crtAssertBusy);
return retval;
}
if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_FILE)
{
if (_CrtDbgFile[nRptType] != _CRTDBG_INVALID_HFILE)
{
#ifdef _WIN32
DWORD written;
WriteFile(_CrtDbgFile[nRptType], szOutMessage, strlen(szOutMessage), &written, NULL);
#else /* _WIN32 */
long written = strlen(szOutMessage);
FSWrite((short)_CrtDbgFile[nRptType], &written, szOutMessage);
#endif /* _WIN32 */
}
}
if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_DEBUG)
{
#ifdef _WIN32
OutputDebugString(szOutMessage);
#else /* _WIN32 */
_CrtOutputDebugString(szOutMessage);
#endif /* _WIN32 */
}
if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_WNDW)
{
char szLine[20];
retval = CrtMessageWindow(nRptType, szFile, nLine ? _itoa(nLine, szLine, 10) : NULL, szModule, szUserMessage);
if (_CRT_ASSERT == nRptType)
_CrtInterlockedDecrement(&_crtAssertBusy);
return retval;
}
if (_CRT_ASSERT == nRptType)
_CrtInterlockedDecrement(&_crtAssertBusy);
/* ignore */
return FALSE;
}
/***
*static int CrtMessageWindow() - report to a message window
*
*Purpose:
* put report into message window, allow user to choose action to take
*
*Entry:
* int nRptType - report type
* const char * szFile - file name
* const char * szLine - line number
* const char * szModule - module name
* const char * szUserMessage - user message
*
*Exit:
* if (MessageBox)
* {
* Abort -> aborts
* Retry -> return TRUE
* Ignore-> return FALSE
* }
* else
* return FALSE
*
*Exceptions:
*
*******************************************************************************/
#ifdef _WIN32
static int CrtMessageWindow(
int nRptType,
const char * szFile,
const char * szLine,
const char * szModule,
const char * szUserMessage
)
{
int nCode;
char *szShortProgName;
char *szShortModuleName;
char szExeName[MAX_PATH];
char szOutMessage[MAX_MSG];
_ASSERTE(szUserMessage != NULL);
/* Shorten program name */
if (!GetModuleFileName(NULL, szExeName, MAX_PATH))
strcpy(szExeName, "<program name unknown>");
szShortProgName = szExeName;
if (strlen(szShortProgName) > MAXLINELEN)
{
szShortProgName += strlen(szShortProgName) - MAXLINELEN;
strncpy(szShortProgName, "...", 3);
}
/* Shorten module name */
szShortModuleName = (char *) szModule;
if (szShortModuleName && strlen(szShortModuleName) > MAXLINELEN)
{
szShortModuleName += strlen(szShortModuleName) - MAXLINELEN;
strncpy(szShortModuleName, "...", 3);
}
if (_snprintf(szOutMessage, MAX_MSG,
"Debug %s!\n\nProgram: %s%s%s%s%s%s%s%s%s%s%s"
"\n\n(Press Retry to debug the application)",
_CrtDbgModeMsg[nRptType],
szShortProgName,
szShortModuleName ? "\nModule: " : "",
szShortModuleName ? szShortModuleName : "",
szFile ? "\nFile: " : "",
szFile ? szFile : "",
szLine ? "\nLine: " : "",
szLine ? szLine : "",
szUserMessage[0] ? "\n\n" : "",
szUserMessage[0] && _CRT_ASSERT == nRptType ? "Expression: " : "",
szUserMessage[0] ? szUserMessage : "",
_CRT_ASSERT == nRptType ?
"\n\nFor information on how your program can cause an assertion"
"\nfailure, see the Visual C++ documentation on asserts."
: "") < 0)
strcpy(szOutMessage, TOOLONGMSG);
/* Report the warning/error */
nCode = __crtMessageBoxA(szOutMessage,
"Microsoft Visual C++ Debug Library",
MB_TASKMODAL|MB_ICONHAND|MB_ABORTRETRYIGNORE|MB_SETFOREGROUND);
/* Abort: abort the program */
if (IDABORT == nCode)
{
/* raise abort signal */
raise(SIGABRT);
/* We usually won't get here, but it's possible that
SIGABRT was ignored. So exit the program anyway. */
_exit(3);
}
/* Retry: return 1 to call the debugger */
if (IDRETRY == nCode)
return 1;
/* Ignore: continue execution */
return 0;
}
#elif defined (_M_MPPC)
/* Definitions */
#define NIL 0
/* Portable Types */
typedef unsigned char Char;
typedef unsigned long Word;
QDGlobals qd;
static void BlinkButton(int count,Rect *r)
{
long n;
while (count--) {
InvertRoundRect(r,10,10);
Delay(4,&n);
}
}
static int ButtonClicked(Rect *r)
{
int state = 0;
Point pt;
do {
GetMouse(&pt);
if (PtInRect(pt,r)) {
if (0 == state) {
state = 1;
BlinkButton(1,r);
}
}
else if (1 == state) {
state = 0;
BlinkButton(1,r);
}
} while (Button());
if (state)
BlinkButton(3,r);
return state;
}
static int CrtMessageWindow(
int nRptType,
const char * szFile,
const char * szLine,
const char * szModule,
const char * szUserMessage
)
{
#define LEFTMARGIN 15
#define ALINE 14
char szOutMessage[MAX_MSG];
Rect abort,retry,ignore,r;
GrafPtr oldPort;
WindowPtr window;
EventRecord event;
long total, contig;
short currHeight = 20;
int numLines = 13 +
4 * (_CRT_ASSERT == nRptType) +
2 * (szUserMessage[0] != '\0') +
(szModule != NULL) +
2 * (szFile != NULL);
/* center a rectangle on the screen, near the top of the screen */
r.top = 50;
r.bottom = r.top + numLines * ALINE;
r.left = qd.screenBits.bounds.right/2 - 170;
r.right = qd.screenBits.bounds.right/2 + 170;
/*
* NewWindow will hang in insufficient memory conditions. Must
* confirm available memory before use.
*/
contig = 0;
PurgeSpace(&total, &contig);
if (contig < 1024)
return -1;
/* create the window and setup the port */
if ((window = NewWindow(NIL,&r,"\p",TRUE,dBoxProc,(WindowPtr)-1,TRUE,0))
== NULL)
return -1;
GetPort(&oldPort);
SetPort(window);
InitCursor();
TextFont(systemFont);
MoveTo(LEFTMARGIN,currHeight);
TextFace(underline);
DrawString("\pMicrosoft Visual C++ Debug Library");
TextFace(0);
currHeight += 2 * ALINE;
_snprintf(szOutMessage, MAX_MSG, "Debug %s!", _CrtDbgModeMsg[nRptType]);
_c2pstr(szOutMessage);
MoveTo(LEFTMARGIN,currHeight);
TextFace(bold);
DrawString(szOutMessage);
TextFace(0);
currHeight += 2 * ALINE;
MoveTo(LEFTMARGIN,currHeight);
DrawString("\pProgram: ");
DrawString(LMGetCurApName());
currHeight += ALINE;
if (szModule) {
_snprintf(szOutMessage, MAX_MSG, "Module: %s", szModule);
_c2pstr(szOutMessage);
MoveTo(LEFTMARGIN,currHeight);
DrawString(szOutMessage);
currHeight += ALINE;
}
if (szFile) {
_snprintf(szOutMessage, MAX_MSG, "File: %s", szFile);
_c2pstr(szOutMessage);
MoveTo(LEFTMARGIN,currHeight);
DrawString(szOutMessage);
currHeight += ALINE;
}
if (szLine) {
_snprintf(szOutMessage, MAX_MSG, "Line: %s", szLine);
_c2pstr(szOutMessage);
MoveTo(LEFTMARGIN,currHeight);
DrawString(szOutMessage);
currHeight += ALINE;
}
currHeight += ALINE;
if (szUserMessage[0])
{
_snprintf(szOutMessage, MAX_MSG, "%s%s",
(_CRT_ASSERT == nRptType) ? "Expression: " : "",
szUserMessage);
r.top = currHeight-10;
r.bottom = currHeight - 5;
r.left = LEFTMARGIN - 2;
r.right = window->portRect.right - LEFTMARGIN - 2;
TextFace(condense);
TextBox(szOutMessage, strlen(szOutMessage), &r, teJustLeft);
TextFace(0);
currHeight += 2*ALINE;
}
currHeight += ALINE;
if (_CRT_ASSERT == nRptType)
{
MoveTo(LEFTMARGIN,currHeight);
DrawString("\pFor more information on how your program");
currHeight += ALINE;
MoveTo(LEFTMARGIN,currHeight);
DrawString("\pcan cause an assertion failure, see the");
currHeight += ALINE;
MoveTo(LEFTMARGIN,currHeight);
DrawString("\pVisual C++ documentation on asserts.");
currHeight += 2*ALINE;
MoveTo(LEFTMARGIN,currHeight);
DrawString("\p(Press Retry to debug the application)");
currHeight += 2*ALINE;
}
else {
MoveTo(LEFTMARGIN,currHeight);
DrawString("\p(Press Retry to debug the application)");
currHeight += 2*ALINE;
}
/* draw abort button */
abort.top = currHeight;
abort.bottom = abort.top + 20;
abort.left = LEFTMARGIN;
abort.right = abort.left + 75;
FrameRoundRect(&abort,10,10);
MoveTo((short)(abort.left+20),(short)(abort.bottom-6));
DrawString("\pAbort");
/* draw retry button */
retry.top = currHeight;
retry.bottom = retry.top + 20;
retry.left = LEFTMARGIN + 110;
retry.right = retry.left + 75;
FrameRoundRect(&retry,10,10);
MoveTo((short)(retry.left+20),(short)(retry.bottom-6));
DrawString("\pRetry");
/* draw ignore button */
ignore.top = currHeight;
ignore.bottom = ignore.top + 20;
ignore.left = LEFTMARGIN + 110 * 2;
ignore.right = ignore.left + 75;
FrameRoundRect(&ignore,10,10);
MoveTo((short)(ignore.left+17),(short)(ignore.bottom-6));
DrawString("\pIgnore");
/* event loop */
while (TRUE) {
if (GetNextEvent(mDownMask+keyDownMask,&event)) {
if (event.what == keyDown) { /* keyboard shortcuts */
char c = (char)event.message;
/* abort */
if (c == 'a') {
BlinkButton(3,&abort);
ExitToShell();
}
/* retry */
else if (c == 'r') {
BlinkButton(3,&retry);
Debugger();
break;
}
/* ignore */
else if (c == 'i') {
BlinkButton(3,&ignore);
break;
}
}
if (event.what == mouseDown) {
GlobalToLocal(&event.where);
if (PtInRect(event.where,&abort) && ButtonClicked(&abort))
ExitToShell();
else if (PtInRect(event.where,&retry) && ButtonClicked(&retry)) {
Debugger();
break;
}
else if (PtInRect(event.where,&ignore) && ButtonClicked(&ignore))
break;
}
}
}
DisposeWindow(window);
SetPort(oldPort);
/* ignore */
return 0;
}
#define WLMD_STR 1
#define LMGetMacJmp() (*(ProcPtr*) 0x120)
enum
{
uppGestaltDebugProcInfo = kCStackBased
| STACK_ROUTINE_PARAMETER (1, SIZE_CODE (sizeof (int)))
| STACK_ROUTINE_PARAMETER (2, SIZE_CODE (sizeof (StringPtr)))
| STACK_ROUTINE_PARAMETER (3, SIZE_CODE (sizeof (char*)))
| STACK_ROUTINE_PARAMETER (4, SIZE_CODE (sizeof (char*)))
};
static UniversalProcPtr pfnGestaltDebugger;
/***
*void _CleanStr - clean string
*
*Purpose:
* Cleans a string of characters that aren't useful. Always removes '\r'. If
* the string is going to MacsBug, replaces semicolons with periods, and
* removes trailing newlines, since MacsBug always advances to the next line
* after a _DebugStr.
*
*Entry:
* StringPtr st - the string to clean
* int fMacsBug - whether the string is going to MacsBug
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
static void __cdecl _CleanStr(StringPtr st, int fMacsBug)
{
int i;
/* change semi-colons to periods (semi-colons hose MacsBug) */
if (fMacsBug)
{
for (i = 0; i < StrLength(st); i++)
{
/* skip MB chars */
if (_ismbblead(st[i+1]))
{
i++;
continue;
}
if (st[i + 1] == ';')
st[i + 1] = '.';
}
}
for (i = StrLength(st); i >= 1; i--)
{
/* if trail byte, stop processing */
if (_ismbstrail(&st[1], &st[i]))
break;
/* remove trailing newlines */
if (st[i] == '\n')
{
if (fMacsBug)
st[0]--;
}
/* remove trailing carriage returns */
else if (st[i] == '\r')
{
st[0]--;
}
/* otherwise, stop processing */
else
{
break;
}
}
}
/***
*void _ConfirmVCDebugger
*
*Purpose:
* Determines if a 'WLMD' Gestalt selector is registered.
*
*Entry:
*
*Exit:
* Current VC++ Debug Output function or NULL.
*
*Exceptions:
*
*******************************************************************************/
static UniversalProcPtr __cdecl _ConfirmVCDebugger(void)
{
/* The VC++ Debug Ouput facilities are registered as "WLMD" */
if (Gestalt('WLMD', (long*) &pfnGestaltDebugger) != noErr)
pfnGestaltDebugger = NULL;
return pfnGestaltDebugger;
}
/***
*int _IsMSVCDebugger
*
*Purpose:
* Determines if a 'MSVC' Gestalt selector is registered, or if there
* is a low level debugger in the system
*
* Only call a macsbug-like debugger if it's going to be around to
* handle the DebugStr
*
*Entry:
*
*Exit:
* TRUE: If MSVC debugger registered
* FALSE: Otherwise
*
*Exceptions:
*
*******************************************************************************/
static int __cdecl _IsLowLevelDebugger(void)
{
#define mskBeingDebugged 1
#define mskPreviousDebugger 2
unsigned long caps;
/* See if VC++ Debugger is running */
if(Gestalt('MSVC', (long*) &caps) == noErr)
{
if((caps & mskBeingDebugged) || (caps & mskPreviousDebugger))
return 1;
else
return 0;
}
/* See if MacsBug is running */
else if (LMGetMacJmp() != NULL)
return 1;
else
return 0;
#undef mskBeingDebugged
#undef mskPreviousDebugger
}
/***
*void _CrtOutputDebugString - output Debug String
*
*Purpose:
* Does the actual output of a string to the debugger.
*
*Entry:
* char * sz -- message to output
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
static void __cdecl _CrtOutputDebugString(char * sz)
{
Str255 stDebug;
long cchTotal;
short cchCur;
const char* pchCur;
EventRecord er;
_ConfirmVCDebugger();
OSEventAvail(0, &er);
cchTotal = strlen(sz);
pchCur = sz;
/* output string in edible portions */
while (cchTotal > 0)
{
cchCur = (short) min(cchTotal, 253);
_ASSERTE(cchCur > 0);
/* put back orphaned lead byte */
if (_ismbslead(pchCur, pchCur+cchCur-1))
cchCur--;
/* convert CString to PascalString */
stDebug[0] = (unsigned char) cchCur;
BlockMoveData(pchCur, &stDebug[1], cchCur);
/* See if VC++ Debug Output facility is running */
if (pfnGestaltDebugger != NULL)
{
_CleanStr(stDebug, 0);
/* if the Control key is down, we break into MacsBug before
sending the string to the Gestalt debugger */
if ((er.modifiers & controlKey) != 0)
Debugger();
CallUniversalProc(pfnGestaltDebugger, uppGestaltDebugProcInfo, WLMD_STR, stDebug,
NULL, NULL);
}
/* See if VC++ Debugger or MacsBug is running */
else if (_IsLowLevelDebugger())
{
short cchSt;
_CleanStr(stDebug, 1);
/* _CleanStr may have changed the length of stDebug */
cchSt = StrLength(stDebug);
/* if the Control key is down, we always stop in the debugger */
if ((er.modifiers & controlKey) == 0)
{
stDebug[cchSt + 1] = ';';
stDebug[cchSt + 2] = 'g';
stDebug[0] += 2;
}
DebugStr(stDebug);
}
cchTotal -= cchCur;
pchCur += cchCur;
}
}
#endif /* defined (_M_MPPC) */
#endif /* _DEBUG */