// Copyright (c) 1996-1999 Microsoft Corporation /* * johnkn's debug logging and assert macros * */ #ifdef __cplusplus extern "C" { #endif // __cplusplus #if !defined _INC_MMDEBUG_ #define _INC_MMDEBUG_ #if defined _DEBUG && !defined DEBUG #define DEBUG #endif // // prototypes for debug functions. // #define SQUAWKNUMZ(num) #num #define SQUAWKNUM(num) SQUAWKNUMZ(num) #define SQUAWK __FILE__ "(" SQUAWKNUM(__LINE__) ") ----" #define DEBUGLINE __FILE__ "(" SQUAWKNUM(__LINE__) ") " #if defined DEBUG || defined _DEBUG || defined DEBUG_RETAIL #define STATICFN int FAR _cdecl AuxDebugEx(int, LPTSTR, ...); void FAR _cdecl AuxRip(LPTSTR, ...); VOID WINAPI AuxDebugDump (int, LPVOID, int); LPCTSTR WINAPI AuxMMErrText(DWORD mmr); int WINAPI DebugSetOutputLevel (int,int); UINT WINAPI AuxFault (DWORD dwFaultMask); #if defined DEBUG_RETAIL && !defined DEBUG && !defined _DEBUG #define INLINE_BREAK #else #if !defined _WIN32 || defined _X86_ #define INLINE_BREAK _asm {int 3} #else #define INLINE_BREAK DebugBreak() #endif #endif #define FAULT_HERE AuxFault #undef assert #define assert(exp) {\ if (!(exp)) {\ AuxDebugEx(-2, DEBUGLINE "assert failed: " #exp "\r\n"); \ INLINE_BREAK;\ }\ } #undef assert2 #define assert2(exp,sz) {\ if (!(exp)) {\ AuxDebugEx(-2, DEBUGLINE "assert failed: " sz "\r\n"); \ INLINE_BREAK;\ }\ } #undef assert3 #define assert3(exp,sz,arg) {\ if (!(exp)) {\ AuxDebugEx(-2, DEBUGLINE "assert failed: " sz "\r\n", (arg)); \ INLINE_BREAK;\ }\ } #undef assert4 #define assert4(exp,sz,arg1,arg2) {\ if (!(exp)) {\ AuxDebugEx(-2, DEBUGLINE "assert failed: " sz "\r\n", (arg1),(arg2)); \ INLINE_BREAK;\ }\ } #undef assert5 #define assert5(exp,sz,arg1,arg2,arg3) {\ if (!(exp)) {\ AuxDebugEx(-2, DEBUGLINE "assert failed: " sz "\r\n", (arg1),(arg2),(arg3)); \ INLINE_BREAK;\ }\ } #else // defined(DEBUG) || defined(_DEBUG) #define AuxDebugEx 1 ? (void)0 : #define AuxDebugDump(a,b,c) #define AuxMMErrText(m) NULL #define AuxRip 1 ? (void)0 : #define assert(a) ((void)0) #define assert2(a,b) ((void)0) #define assert3(a,b,c) ((void)0) #define assert4(a,b,c,d) ((void)0) #define assert5(a,b,c,d,e) ((void)0) #define FAULT_HERE 1 ? (void)0 : #define INLINE_BREAK #define DebugSetOutputLevel(i,j) #define STATICFN static #endif // defined(DEBUG) || defined _DEBUG || defined DEBUG_RETAIL #ifndef DPF_CATEGORY #define DPF_CATEGORY 0x0100 #endif // translate DPF's only in internal debug builds // #if defined DEBUG || defined _DEBUG #define DUMP(n,a,b) AuxDebugDump (DPF_CATEGORY | (n), a, b) #define RIP AuxDebugEx (0, DEBUGLINE), AuxRip #define AuxMMR(api,mmr) (mmr) ? AuxDebugEx(1, DEBUGLINE #api " error %d '%s'\r\n", mmr, AuxMMErrText(mmr)) : (int)0 #define DPF(n,sz) AuxDebugEx (DPF_CATEGORY | (n), DEBUGLINE sz "\r\n") #define DPF1(n,sz,a) AuxDebugEx (DPF_CATEGORY | (n), DEBUGLINE sz "\r\n",(a)) #define DPF2(n,sz,a,b) AuxDebugEx (DPF_CATEGORY | (n), DEBUGLINE sz "\r\n",(a),(b)) #define DPF3(n,sz,a,b,c) AuxDebugEx (DPF_CATEGORY | (n), DEBUGLINE sz "\r\n",(a),(b),(c)) #define DPF4(n,sz,a,b,c,d) AuxDebugEx (DPF_CATEGORY | (n), DEBUGLINE sz "\r\n",(a),(b),(c),(d)) #define DPF5(n,sz,a,b,c,d,e) AuxDebugEx (DPF_CATEGORY | (n), DEBUGLINE sz "\r\n",(a),(b),(c),(d),(e)) #define DPF6(n,sz,a,b,c,d,e,f) AuxDebugEx (DPF_CATEGORY | (n), DEBUGLINE sz "\r\n",(a),(b),(c),(d),(d),(f)) #define DPF7(n,sz,a,b,c,d,e,f,g) AuxDebugEx (DPF_CATEGORY | (n), DEBUGLINE sz "\r\n",(a),(b),(c),(d),(d),(f),(g)) #else #define DUMP(n,a,b) #define RIP AuxRip #define AuxMMR(api,mmr) #define DPF(n,sz) #define DPF1(n,sz,a) #define DPF2(n,sz,a,b) #define DPF3(n,sz,a,b,c) #define DPF4(n,sz,a,b,c,d) #define DPF5(n,sz,a,b,c,d,e) #define DPF6(n,sz,a,b,c,d,e,f) #define DPF7(n,sz,a,b,c,d,e,f,g) #endif #endif //_INC_MMDEBUG_ // ============================================================================= // // include this in only one module in a DLL or APP // #if defined DEBUG || defined _DEBUG || defined DEBUG_RETAIL #if (defined _INC_MMDEBUG_CODE_) && (_INC_MMDEBUG_CODE_ != FALSE) #undef _INC_MMDEBUG_CODE_ #define _INC_MMDEBUG_CODE_ FALSE #include #if !defined _WIN32 && !defined wvsprintfA #define wvsprintfA wvsprintf #endif static struct _mmerrors { DWORD mmr; LPCTSTR psz; } aMMErr[] = { MMSYSERR_NOERROR ,"Success", #ifdef DEBUG MMSYSERR_ERROR ,"unspecified error", MMSYSERR_BADDEVICEID ,"device ID out of range", MMSYSERR_NOTENABLED ,"driver failed enable", MMSYSERR_ALLOCATED ,"device already allocated", MMSYSERR_INVALHANDLE ,"device handle is invalid", MMSYSERR_NODRIVER ,"no device driver present", MMSYSERR_NOMEM ,"memory allocation error", MMSYSERR_NOTSUPPORTED ,"function isn't supported", MMSYSERR_BADERRNUM ,"error value out of range", MMSYSERR_INVALFLAG ,"invalid flag passed", MMSYSERR_INVALPARAM ,"invalid parameter passed", #if (WINVER >= 0x0400) MMSYSERR_HANDLEBUSY ,"handle in use by another thread", MMSYSERR_INVALIDALIAS ,"specified alias not found", MMSYSERR_BADDB ,"bad registry database", MMSYSERR_KEYNOTFOUND ,"registry key not found", MMSYSERR_READERROR ,"registry read error", MMSYSERR_WRITEERROR ,"registry write error", MMSYSERR_DELETEERROR ,"registry delete error", MMSYSERR_VALNOTFOUND ,"registry value not found", MMSYSERR_NODRIVERCB ,"Never got a 32 bit callback from driver", #endif // WINVER >= 0x400 WAVERR_BADFORMAT ,"wave:unsupported wave format", WAVERR_STILLPLAYING ,"wave:still something playing", WAVERR_UNPREPARED ,"wave:header not prepared", WAVERR_SYNC ,"wave:device is synchronous", MIDIERR_UNPREPARED ,"midi:header not prepared", MIDIERR_STILLPLAYING ,"midi:still something playing", //MIDIERR_NOMAP ,"midi:no configured instruments", MIDIERR_NOTREADY ,"midi:hardware is still busy", MIDIERR_NODEVICE ,"midi:port no longer connected", MIDIERR_INVALIDSETUP ,"midi:invalid MIF", #ifdef CHICAGO MIDIERR_BADOPENMODE ,"midi:operation unsupported w/ open mode", #endif TIMERR_NOCANDO ,"timer: request not completed", JOYERR_PARMS ,"joy:bad parameters", JOYERR_NOCANDO ,"joy:request not completed", JOYERR_UNPLUGGED ,"joystick is unplugged", MCIERR_INVALID_DEVICE_ID ,"MCIERR_INVALID_DEVICE_ID", MCIERR_UNRECOGNIZED_KEYWORD ,"MCIERR_UNRECOGNIZED_KEYWORD", MCIERR_UNRECOGNIZED_COMMAND ,"MCIERR_UNRECOGNIZED_COMMAND", MCIERR_HARDWARE ,"MCIERR_HARDWARE", MCIERR_INVALID_DEVICE_NAME ,"MCIERR_INVALID_DEVICE_NAME", MCIERR_OUT_OF_MEMORY ,"MCIERR_OUT_OF_MEMORY", MCIERR_DEVICE_OPEN ,"MCIERR_DEVICE_OPEN", MCIERR_CANNOT_LOAD_DRIVER ,"MCIERR_CANNOT_LOAD_DRIVER", MCIERR_MISSING_COMMAND_STRING ,"MCIERR_MISSING_COMMAND_STRING", MCIERR_PARAM_OVERFLOW ,"MCIERR_PARAM_OVERFLOW", MCIERR_MISSING_STRING_ARGUMENT ,"MCIERR_MISSING_STRING_ARGUMENT", MCIERR_BAD_INTEGER ,"MCIERR_BAD_INTEGER", MCIERR_PARSER_INTERNAL ,"MCIERR_PARSER_INTERNAL", MCIERR_DRIVER_INTERNAL ,"MCIERR_DRIVER_INTERNAL", MCIERR_MISSING_PARAMETER ,"MCIERR_MISSING_PARAMETER", MCIERR_UNSUPPORTED_FUNCTION ,"MCIERR_UNSUPPORTED_FUNCTION", MCIERR_FILE_NOT_FOUND ,"MCIERR_FILE_NOT_FOUND", MCIERR_DEVICE_NOT_READY ,"MCIERR_DEVICE_NOT_READY", MCIERR_INTERNAL ,"MCIERR_INTERNAL", MCIERR_DRIVER ,"MCIERR_DRIVER", MCIERR_CANNOT_USE_ALL ,"MCIERR_CANNOT_USE_ALL", MCIERR_MULTIPLE ,"MCIERR_MULTIPLE", MCIERR_EXTENSION_NOT_FOUND ,"MCIERR_EXTENSION_NOT_FOUND", MCIERR_OUTOFRANGE ,"MCIERR_OUTOFRANGE", MCIERR_FLAGS_NOT_COMPATIBLE ,"MCIERR_FLAGS_NOT_COMPATIBLE", MCIERR_FILE_NOT_SAVED ,"MCIERR_FILE_NOT_SAVED", MCIERR_DEVICE_TYPE_REQUIRED ,"MCIERR_DEVICE_TYPE_REQUIRED", MCIERR_DEVICE_LOCKED ,"MCIERR_DEVICE_LOCKED", MCIERR_DUPLICATE_ALIAS ,"MCIERR_DUPLICATE_ALIAS", MCIERR_BAD_CONSTANT ,"MCIERR_BAD_CONSTANT", MCIERR_MUST_USE_SHAREABLE ,"MCIERR_MUST_USE_SHAREABLE", MCIERR_MISSING_DEVICE_NAME ,"MCIERR_MISSING_DEVICE_NAME", MCIERR_BAD_TIME_FORMAT ,"MCIERR_BAD_TIME_FORMAT", MCIERR_NO_CLOSING_QUOTE ,"MCIERR_NO_CLOSING_QUOTE", MCIERR_DUPLICATE_FLAGS ,"MCIERR_DUPLICATE_FLAGS", MCIERR_INVALID_FILE ,"MCIERR_INVALID_FILE", MCIERR_NULL_PARAMETER_BLOCK ,"MCIERR_NULL_PARAMETER_BLOCK", MCIERR_UNNAMED_RESOURCE ,"MCIERR_UNNAMED_RESOURCE", MCIERR_NEW_REQUIRES_ALIAS ,"MCIERR_NEW_REQUIRES_ALIAS", MCIERR_NOTIFY_ON_AUTO_OPEN ,"MCIERR_NOTIFY_ON_AUTO_OPEN", MCIERR_NO_ELEMENT_ALLOWED ,"MCIERR_NO_ELEMENT_ALLOWED", MCIERR_NONAPPLICABLE_FUNCTION ,"MCIERR_NONAPPLICABLE_FUNCTION", MCIERR_ILLEGAL_FOR_AUTO_OPEN ,"MCIERR_ILLEGAL_FOR_AUTO_OPEN", MCIERR_FILENAME_REQUIRED ,"MCIERR_FILENAME_REQUIRED", MCIERR_EXTRA_CHARACTERS ,"MCIERR_EXTRA_CHARACTERS", MCIERR_DEVICE_NOT_INSTALLED ,"MCIERR_DEVICE_NOT_INSTALLED", MCIERR_GET_CD ,"MCIERR_GET_CD", MCIERR_SET_CD ,"MCIERR_SET_CD", MCIERR_SET_DRIVE ,"MCIERR_SET_DRIVE", MCIERR_DEVICE_LENGTH ,"MCIERR_DEVICE_LENGTH", MCIERR_DEVICE_ORD_LENGTH ,"MCIERR_DEVICE_ORD_LENGTH", MCIERR_NO_INTEGER ,"MCIERR_NO_INTEGER", MCIERR_WAVE_OUTPUTSINUSE ,"MCIERR_WAVE_OUTPUTSINUSE", MCIERR_WAVE_SETOUTPUTINUSE ,"MCIERR_WAVE_SETOUTPUTINUSE", MCIERR_WAVE_INPUTSINUSE ,"MCIERR_WAVE_INPUTSINUSE", MCIERR_WAVE_SETINPUTINUSE ,"MCIERR_WAVE_SETINPUTINUSE", MCIERR_WAVE_OUTPUTUNSPECIFIED ,"MCIERR_WAVE_OUTPUTUNSPECIFIED", MCIERR_WAVE_INPUTUNSPECIFIED ,"MCIERR_WAVE_INPUTUNSPECIFIED", MCIERR_WAVE_OUTPUTSUNSUITABLE ,"MCIERR_WAVE_OUTPUTSUNSUITABLE", MCIERR_WAVE_SETOUTPUTUNSUITABLE ,"MCIERR_WAVE_SETOUTPUTUNSUITABLE", MCIERR_WAVE_INPUTSUNSUITABLE ,"MCIERR_WAVE_INPUTSUNSUITABLE", MCIERR_WAVE_SETINPUTUNSUITABLE ,"MCIERR_WAVE_SETINPUTUNSUITABLE", MCIERR_SEQ_DIV_INCOMPATIBLE ,"MCIERR_SEQ_DIV_INCOMPATIBLE", MCIERR_SEQ_PORT_INUSE ,"MCIERR_SEQ_PORT_INUSE", MCIERR_SEQ_PORT_NONEXISTENT ,"MCIERR_SEQ_PORT_NONEXISTENT", MCIERR_SEQ_PORT_MAPNODEVICE ,"MCIERR_SEQ_PORT_MAPNODEVICE", MCIERR_SEQ_PORT_MISCERROR ,"MCIERR_SEQ_PORT_MISCERROR", MCIERR_SEQ_TIMER ,"MCIERR_SEQ_TIMER", MCIERR_SEQ_PORTUNSPECIFIED ,"MCIERR_SEQ_PORTUNSPECIFIED", MCIERR_SEQ_NOMIDIPRESENT ,"MCIERR_SEQ_NOMIDIPRESENT", MCIERR_NO_WINDOW ,"MCIERR_NO_WINDOW", MCIERR_CREATEWINDOW ,"MCIERR_CREATEWINDOW", MCIERR_FILE_READ ,"MCIERR_FILE_READ", MCIERR_FILE_WRITE ,"MCIERR_FILE_WRITE", #ifdef CHICAGO MCIERR_NO_IDENTITY ,"MCIERR_NO_IDENTITY", MIXERR_INVALLINE ,"Invalid Mixer Line", MIXERR_INVALCONTROL ,"Invalid Mixer Control", MIXERR_INVALVALUE ,"Invalid Mixer Value", #endif // CHICAGO #endif // DEBUG 0xFFFFFFFE , "unknown error %d" }; struct _mmdebug { int Level; int Mask; int StopOnRip; DWORD TakeFault; struct _mmerrors *paErrs; BOOL Initialized; HANDLE hOut; } mmdebug = {0, 0xFF, 0, 0xFF, aMMErr}; /*+ AuxFault * *-=================================================================*/ UINT WINAPI AuxFault ( DWORD dwFaultMask) { LPUINT pData = NULL; if (dwFaultMask & mmdebug.TakeFault) return *pData; return 0; } /*+ AuxOut - write a string to designated debug out * *-=================================================================*/ void WINAPI AuxOut ( LPTSTR psz) { #ifdef WIN32 if (mmdebug.hOut) { UINT cb = lstrlen(psz); DWORD dw; if (INVALID_HANDLE_VALUE != mmdebug.hOut) WriteFile (mmdebug.hOut, psz, cb, &dw, NULL); } else #endif { #ifdef DbgLog DbgOutString (psz); // from \quartz\sdk\classes\base\debug.cpp #else OutputDebugString (psz); #endif } } /*+ AuxDebug - create a formatted string and output to debug terminal * *-=================================================================*/ int FAR _cdecl AuxDebugEx ( int iLevel, LPTSTR lpFormat, ...) { #ifdef WIN32 char szBuf[1024]; #else static char szBuf[1024]; #endif int cb; va_list va; LPSTR psz; // mask the iLevel passed with mmdebug.Mask. if this ends up // clearing the high bits then iLevel has a shot being smaller // than mmdebug.Level. if not, then the second test will always // fail. Thus mmdebug.Mask has bits set to DISABLE that category. // // note that we always pass messages that have an iLevel < 0. // this level corresponds to Asserts & Rips so we always want to see them. // if (iLevel < 0 || mmdebug.Level >= (iLevel & mmdebug.Mask)) { va_start (va, lpFormat); cb = wvsprintfA (szBuf, lpFormat, va); va_end (va); // eat leading ..\..\ which we get from __FILE__ since // george's wierd generic makefile stuff. // psz = szBuf; while (psz[0] == '.' && psz[1] == '.' && psz[2] == '\\') psz += 3; // if we begin with a drive letter, strip off all but filename // if (psz[0] && psz[1] == ':') { UINT ii = 2; for (ii = 2; psz[ii] != 0; ++ii) if (psz[ii] == '\\') psz += ii+1, ii = 0; } // write to standard out if we have a handle. otherwise write to // the debugger // #ifdef MODULE_DEBUG_PREFIX if (psz != szBuf) AuxOut (MODULE_DEBUG_PREFIX); #endif AuxOut (psz); } return cb; } /*+ AuxRip * *-=================================================================*/ void FAR _cdecl AuxRip ( LPTSTR lpFormat, ...) { #ifdef WIN32 char szBuf[1024]; #else static char szBuf[1024]; #endif va_list va; LPSTR psz; va_start (va, lpFormat); wvsprintfA (szBuf, lpFormat, va); va_end (va); // eat leading ..\..\ which we get from __FILE__ since // george's wierd generic makefile stuff. // psz = szBuf; while (psz[0] == '.' && psz[1] == '.' && psz[2] == '\\') psz += 3; AuxOut ("RIP: "); AuxOut (psz); AuxOut ("\r\n"); if (mmdebug.StopOnRip) { #if !defined _WIN32 || defined _X86_ _asm {int 3}; #else DebugBreak(); #endif } } /*+ AuxDebugDump - * *-=================================================================*/ VOID WINAPI AuxDebugDump ( int iLevel, LPVOID lpvData, int nCount) { LPBYTE lpData = (LPBYTE)lpvData; char szBuf[128]; LPSTR psz; int cb; int ix; BYTE abRow[8]; if ((mmdebug.Level < (iLevel & mmdebug.Mask)) || nCount <= 0) return; do { cb = wsprintf (szBuf, "\t%08X: ", lpData); psz = szBuf + cb; for (ix = 0; ix < 8; ++ix) { LPBYTE lpb = lpData; abRow[ix] = '.'; if (IsBadReadPtr (lpData + ix, 1)) lstrcpy (psz, ".. "); else { wsprintf (psz, "%02X ", lpData[ix]); if (lpData[ix] >= 32 && lpData[ix] < 127) abRow[ix] = lpData[ix]; } psz += 3; } for (ix = 0; ix < 8; ++ix) *psz++ = abRow[ix]; lstrcpy (psz, "\r\n"); #ifdef MODULE_DEBUG_PREFIX AuxOut (MODULE_DEBUG_PREFIX); #endif AuxOut (szBuf); } while (lpData += 8, (nCount -= 8) > 0); return; } /*+ AuxMMErrText * *-=================================================================*/ LPCTSTR WINAPI AuxMMErrText ( DWORD mmr) { UINT uRemain = sizeof(aMMErr)/sizeof(aMMErr[0]); UINT uUpper = uRemain-1; UINT uLower = 0; static char szTemp[50]; if (mmr <= aMMErr[uUpper].mmr) { // binary search for mmr match, if match // return string pointer // while (--uRemain) { UINT ii = (uLower + uUpper) >> 1; if (aMMErr[ii].mmr < mmr) { if (uLower == ii) break; uLower = ii; } else if (aMMErr[ii].mmr > mmr) { if (uUpper == ii) break; uUpper = ii; } else { return aMMErr[ii].psz; break; } } // we can only get to here if no match was found for // the error id. // if ( ! uRemain) { int ix; INLINE_BREAK; for (ix = 0; ix < sizeof(aMMErr)/sizeof(aMMErr[0])-1; ++ix) { assert (aMMErr[ix].mmr < aMMErr[ix+1].mmr); } wsprintf (szTemp, "error %d 0x%X", mmr, mmr); return szTemp; } } wsprintf (szTemp, aMMErr[uUpper].psz, mmr); return szTemp; } /*+ DebugSetOutputLevel * *-=================================================================*/ BOOL WINAPI DebugSetOutputLevel ( int nLevel, int nMask) { int nOldLevel = mmdebug.Level; if (!mmdebug.Initialized) { #ifdef WIN32 TCHAR szFile[MAX_PATH]; mmdebug.TakeFault = GetProfileInt("Debug", "FaultMask", 1); GetProfileString("Debug", "MMDebugTo", "", szFile, sizeof(szFile)); #if 0 if (!lstrcmpi(szFile, "Console")) { mmdebug.hOut = GetStdHandle (STD_OUTPUT_HANDLE); if (!mmdebug.hOut || mmdebug.hOut == INVALID_HANDLE_VALUE) { AllocConsole (); mmdebug.hOut = GetStdHandle (STD_OUTPUT_HANDLE); if (mmdebug.hOut == INVALID_HANDLE_VALUE) mmdebug.hOut = NULL; } SetConsoleTitle (MODULE_DEBUG_PREFIX " Debug Output"); } else #endif if (szFile[0] && lstrcmpi(szFile, "Debug") && lstrcmpi(szFile, "Debugger") && lstrcmpi(szFile, "Deb")) { mmdebug.hOut = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != mmdebug.hOut) SetFilePointer (mmdebug.hOut, 0, NULL, FILE_END); } #endif mmdebug.Initialized = TRUE; } mmdebug.Level = (nLevel & 0xFF); mmdebug.Mask = (nMask | 0xFF); return nOldLevel; } #endif // _INC_MMDEBUG_CODE_ #endif // DEBUG || _DEBUG #ifdef __cplusplus } #endif // _cplusplus