Windows2003-3790/windows/advcore/gdiplus/test/emfdcode/debug.cpp
2020-09-30 16:53:55 +02:00

311 lines
7.6 KiB
C++

/**************************************************************************\
*
* Copyright (c) 1998-1999 Microsoft Corporation
*
* Abstract:
*
* Debugging routines
*
* Revision History:
*
* 09/07/1999 agodfrey
* Created it.
*
\**************************************************************************/
#include "global.h"
// Optional callback function for reporting a debug event.
enum GpAltDebugEventLevel
{
GpAltDebugFatal,
GpAltDebugWarning
};
#define GpAltDebugEventFunction 0
//DEBUGEVENTFUNCTION GpAltDebugEventFunction = NULL;
#if DBG
// GpDebugLevel is used to control the amount/severity of debugging messages
// that are actually output.
int GpDebugLevel = DBG_TERSE;
/**************************************************************************\
*
* Function Description:
*
* Removes the path portion of a pathname
*
* Arguments:
*
* [IN] str - pathname to strip
*
* Return Value:
*
* A pointer to the filename portion of the pathname
*
* History:
*
* 09/07/1999 agodfrey
* Moved from Entry\Initialize.cpp
*
\**************************************************************************/
const char*
StripDirPrefix(
const char* str
)
{
const char* p;
p = strrchr(str, '\\');
return p ? p+1 : str;
}
const int maxInputStringSize = 1024;
/**************************************************************************\
*
* Function Description:
*
* Outputs to the debugger
*
* Arguments:
*
* [IN] format - printf-like format string and variable arguments
*
* Return Value:
*
* Zero. This is to conform to NTDLL's definition of DbgPrint.
*
* Notes:
*
* There will be no output if a debugger is not connected.
*
* History:
*
* 09/07/1999 agodfrey
* Moved from Entry\Initialize.cpp
*
\**************************************************************************/
ULONG _cdecl
DbgPrint(
char* format,
...
)
{
va_list arglist;
va_start(arglist, format);
char buf[maxInputStringSize];
_vsnprintf(buf, maxInputStringSize, format, arglist);
buf[maxInputStringSize-1]=0;
OutputDebugStringA(buf);
va_end(arglist);
return 0;
}
// If we can't allocate memory for the debug string, we'll use this buffer
// in desperation. It's not thread-safe. I *did* say 'desperation'.
static char desperationBuffer[maxInputStringSize];
/**************************************************************************\
*
* Function Description:
*
* Creates a new string, and sprintf's to it.
*
* Arguments:
*
* [IN] format - printf-like format string and variable arguments
*
* Return Value:
*
* The probably-newly-allocated string result.
*
* Notes:
*
* This function is not intended for general use. It guards against memory
* failure by using a global buffer. So, while the caller is responsible
* for freeing the memory, the caller must also check for that buffer.
* i.e. we only want DbgEmitMessage to call this.
*
* It's also only mostly thread-safe, because if we run out of memory,
* we'll use that global buffer in a non-protected way.
*
* This is the only solution I could find so that I could move most of the
* implementation details out of the header file. The root cause is that
* macros don't handle multiple arguments natively, so we have to pass
* the printf arguments as a single macro argument (in parentheses).
* Which means, the function that consumes those arguments can have no
* other arguments.
*
* History:
*
* 02/01/2000 agodfrey
* Created it. Finally, I've found a way to get debug implementation
* details out of the headers.
*
\**************************************************************************/
char * _cdecl
GpParseDebugString(
char* format,
...
)
{
va_list arglist;
va_start(arglist, format);
// Don't use GpMalloc here so that we can use ASSERT and WARNING in
// our memory allocation routines.
char *newBuf = static_cast<char *>(LocalAlloc(LMEM_FIXED, maxInputStringSize));
if (!newBuf)
{
newBuf = desperationBuffer;
}
_vsnprintf(newBuf, maxInputStringSize, format, arglist);
// Nuke the last byte, because MSDN isn't clear on what _vsnprintf does
// in that case.
newBuf[maxInputStringSize-1]=0;
va_end(arglist);
return newBuf;
}
/**************************************************************************\
*
* Function Description:
*
* Processes a debug event. Frees the message string.
*
* Arguments:
*
* level - The debug level of the event
* file - Should be __FILE__
* line - Should be __LINE__
* message - The debug message.
*
* Notes:
*
* You don't want to call this directly. That would be error-prone.
* Use ASSERT, WARNING, etc.
*
* In Office, it will raise an 'assert' dialog if necessary.
*
* Depending on the debug level, an identifying prefix will be output.
*
* If the debug level is DBG_RIP, will suspend execution (e.g. by
* hitting a breakpoint.)
*
* Note on Office interop:
*
* Under Office, we'll pass WARNINGs and ASSERTs to a reporting function
* they provide. Their function will breakpoint on ASSERTs.
* Lesser events will just be sent to the debugger.
*
* History:
*
* 02/01/2000 agodfrey
* Created it.
*
\**************************************************************************/
void _cdecl
GpLogDebugEvent(
int level,
char *file,
unsigned int line,
char *message
)
{
// We may want to add things to the passed-in message. So we need
// a temporary buffer
const int maxOutputStringSize = maxInputStringSize + 100;
char tempBuffer[maxOutputStringSize+1];
// MSDN's _vsnprintf doc isn't clear on this, so just in case:
tempBuffer[maxOutputStringSize] = 0;
int altDebugLevel = -1;
char *prefix = "";
if (GpDebugLevel <= (level))
{
switch (level)
{
case DBG_WARNING:
prefix = "WRN ";
if (GpAltDebugEventFunction)
{
altDebugLevel = GpAltDebugWarning;
}
break;
case DBG_RIP:
prefix = "RIP ";
if (GpAltDebugEventFunction)
{
altDebugLevel = GpAltDebugFatal;
}
break;
}
// The convention is that we append the trailing \n, not the caller.
// Two reasons:
// 1) Callers tend to forget it.
// 2) More importantly, it encourages the caller to think of each
// call as a separate event. This is important in some cases - e.g.
// when Office produces a popup for each event.
_snprintf(
tempBuffer,
maxOutputStringSize,
"%s%s(%d): %s\n",
prefix,
StripDirPrefix(file),
line,
message
);
if (altDebugLevel >= 0)
{
//GpAltDebugEventFunction(altDebugLevel, tempBuffer);
}
else
{
OutputDebugStringA(tempBuffer);
}
}
// Free the message buffer
if (message != desperationBuffer)
{
LocalFree(message);
}
// Force a breakpoint, if it's warranted.
if ((GpDebugLevel <= DBG_RIP) && (level == DBG_RIP) && (altDebugLevel < 0))
{
DebugBreak();
}
}
#endif // DBG