//+---------------------------------------------------------------------------- // // File: // cdebug.cpp // // Contents: // Ole2 internal debugging support; implementation of debugstream // and IDebug for interface/class // // Classes: // // Functions: // // History: // 24-Jan-94 alexgo first pass at converting to Cairo-style // memory allocation // 12/31/93 - ChrisWe - defined DbgWarn for use by reterr.h // 12/31/93 - ChrisWe - make compile with _DEBUG defined // 03-Jan-95 BruceMa Use olewcstombs, etc. // //----------------------------------------------------------------------------- #include //REVIEW32: RemLookupSHUnk not supported in cairo compobj #ifndef WIN32 #include //for RemLookupSHUnk #endif #pragma SEG(cdebug) #pragma SEG(cdebug) #include #ifdef _MAC #define Yield() #endif // // Redefine UNICODE functions to ANSI for Chicago support. // #if !defined(UNICODE) #define swprintf wsprintfA #undef _xstrcpy #undef _xstrlen #define _xstrcpy strcpy #define _xstrlen strlen #endif #ifdef _DEBUG FARINTERNAL_(void) DbgWarn(LPSTR psz, LPSTR pszFileName, ULONG uLineno) { static const char msg[] = "Unexpected result: "; const char *pszmsg; TCHAR buf[250]; // pick a message pszmsg = psz ? psz : msg; // write this out to the debugger #ifdef UNICODE MultiByteToWideChar(CP_ACP, 0, pszmsg, strlen(pszmsg)+1, buf, sizeof(buf)); OutputDebugString(buf); MultiByteToWideChar(CP_ACP, 0, pszFileName, strlen(pszFileName)+1, buf, sizeof(buf)); OutputDebugString(buf); wsprintf(buf, TEXT(", line %lu\n"), uLineno); #else // !UNICODE OutputDebugString(pszmsg); OutputDebugString(pszFileName); wsprintfA(buf, TEXT(", line %lu\n"), uLineno); #endif // UNICODE OutputDebugString(buf); } #endif // _DEBUG //some constants used only in this file #define DBGMARGIN 45 #define DBGTABSIZE 4 #define HEADER 1 #define NOHEADER 0 // mattp!!!! NYI for MAC #ifdef _MAC TCHAR vDebugStr[300]; #pragma SEG(DbgReplyFilter) pascal BOOL DbgReplyFilter ( long lParam, HighLevelEventMsgPtr lpmsg, TargetIDPtr lptargetid) { //#pragma unused (lptargetid) TargetID sender; unsigned long msgRefcon; unsigned long cb; long msgClass = (long)(lpmsg->theMsgEvent.message); long msgType = *(long *)&(lpmsg->theMsgEvent.where); if ((msgType != 'Sync') || (msgClass != 'Dbg2')) { // i return false; } AcceptHighLevelEvent(&sender, &msgRefcon, NULL, &cb); // here we dispose of the auto reply return true; } void OutputDebugString(const TCHAR *s) { //*vDebugStr = sprintf(vDebugStr+1, "%s", s); //DebugStr((Str255) vDebugStr); if (SendHighLevelEvent('LSpy', 'Dbg2', 'TEXT', 'Eric',(TCHAR*) s, _xstrlen(s))) { long timeout = TickCount() + 60; //timeout in 1 second OSErr err; #if 0 while (timeout > TickCount()) { EventRecord evt; if (GetSpecificHighLevelEvent( (GetSpecificFilterProcPtr) DbgReplyFilter, NULL, &err)) { // DebugStr("\pgot dbg2 return reciept"); break; } WaitNextEvent(NULL, &evt, 3, NULL); } #else SystemTask(); #endif } else ;//DebugStr("\pBad send hl"); } #endif // _MAC ASSERTDATA #define DBGLOGFILENAME TEXT("debug.log") static void GetCurDateTime(LPTSTR lpsz); #pragma SEG(DbgLogOpen) STDAPI_(HFILE) DbgLogOpen(LPCTSTR lpszFile, LPCTSTR lpszMode) { #ifdef _DEBUG #ifndef _MAC HFILE fh; LPSTR lpsz; #ifdef _UNICODE char buf[2 * MAX_PATH]; #endif AssertSz( lpszFile && lpszMode, "Invalid arguments to DbgLogOpen"); switch (lpszMode[0]) { case TEXT('w'): #ifdef _UNICODE WideCharToMultiByte (CP_ACP, WC_COMPOSITECHECK, lpszFile, -1, buf, MAX_PATH, NULL, NULL); lpsz = buf; #else lpsz = (LPSTR)lpszFile; #endif // Open for writing (overwrite if exists) fh = _lcreat(lpsz, 0); break; case TEXT('r'): // Open for reading #ifdef _UNICODE WideCharToMultiByte (CP_ACP, WC_COMPOSITECHECK, lpszFile, -1, buf, MAX_PATH, NULL, NULL); lpsz = buf; #else lpsz = (LPSTR)lpszFile; #endif fh = _lopen(lpsz, OF_READ); break; case TEXT('a'): #ifdef _UNICODE WideCharToMultiByte (CP_ACP, WC_COMPOSITECHECK, lpszFile, -1, buf, MAX_PATH, NULL, NULL); lpsz = buf; #else lpsz = (LPSTR)lpszFile; #endif // Open for appending // to append to log file seek to end before writing if ((fh = _lopen(lpsz, OF_READWRITE)) != -1) { #ifdef WIN32 _llseek(fh, 0L, FILE_END); #else _llseek(fh, 0L, SEEK_END); #endif // WIN32 } else { // file does not exist, create a new one. fh = _lcreat(lpsz, 0); } break; } return fh; #endif //_MAC #else (void) lpszFile; (void) lpszMode; return -1; #endif //_DEBUG } #pragma SEG(DbgLogClose) STDAPI_(void) DbgLogClose(HFILE fh) { #ifdef _DEBUG #ifndef _MAC if (fh != -1) _lclose(fh); #endif #else (void) fh; #endif } #pragma SEG(DbgLogWrite) STDAPI_(void) DbgLogWrite(HFILE fh, LPCTSTR lpszStr) { #ifdef _DEBUG LPSTR lpsz; #ifdef _UNICODE char buf[2 * MAX_PATH]; #endif #ifndef _MAC if (fh != -1 && lpszStr) { #ifdef _UNICODE WideCharToMultiByte (CP_ACP, WC_COMPOSITECHECK, lpszStr, -1, buf, MAX_PATH, NULL, NULL); lpsz = buf; #else lpsz = (LPSTR)lpszStr; #endif // _UNICODE _lwrite(fh, lpsz, strlen(lpsz)); // NOTE NOT UNICODE } #endif // _MAC #else (void) fh; (void) lpszStr; #endif } #pragma SEG(DbgLogTimeStamp) STDAPI_(void) DbgLogTimeStamp(HFILE fh, LPCTSTR lpsz) { #ifdef _DEBUG TCHAR buffer[80]; GetCurDateTime(buffer); DbgLogOutputDebugString(fh, TEXT("\n***************************************\n")); if (lpsz) DbgLogOutputDebugString(fh, lpsz); DbgLogOutputDebugString(fh, TEXT(": ")); DbgLogOutputDebugString(fh, buffer); DbgLogOutputDebugString(fh, TEXT("\n")); DbgLogOutputDebugString(fh, TEXT(".......................................\n\n")); #else (void) fh; (void) lpsz; #endif } #pragma SEG(DbgLogWriteBanner) STDAPI_(void) DbgLogWriteBanner(HFILE fh, LPCTSTR lpsz) { #ifdef _DEBUG DbgLogOutputDebugString(fh, TEXT("\n***************************************\n")); if (lpsz) DbgLogOutputDebugString(fh, lpsz); DbgLogOutputDebugString(fh, TEXT("\n")); DbgLogOutputDebugString(fh, TEXT(".......................................\n\n")); #else (void) fh; (void) lpsz; #endif } #pragma SEG(DbgLogOutputDebugString) STDAPI_(void) DbgLogOutputDebugString(HFILE fh, LPCTSTR lpsz) { #ifdef _DEBUG #ifndef _MAC if (fh != -1) DbgLogWrite(fh, lpsz); OutputDebugString(lpsz); #endif #else (void)fh; (void)lpsz; #endif } #ifdef _DEBUG #pragma SEG(GetCurDateTime) static void GetCurDateTime(LPTSTR lpsz) { unsigned year, month, day, dayOfweek, hours, min, sec; static const TCHAR FAR* const dayNames[7] = { TEXT("Sun"), TEXT("Mon"), TEXT("Tue"), TEXT("Wed"), TEXT("Thu"), TEXT("Fri"), TEXT("Sat") }; static const TCHAR FAR* const monthNames[12] = { TEXT("Jan"), TEXT("Feb"), TEXT("Mar"), TEXT("Apr"), TEXT("May"), TEXT("Jun"), TEXT("Jul"), TEXT("Aug"), TEXT("Sep"), TEXT("Oct"), TEXT("Nov"), TEXT("Dec") }; #ifndef _MAC #ifdef WIN32 SYSTEMTIME st; GetLocalTime(&st); year = st.wYear; month = st.wMonth - 1; dayOfweek = st.wDayOfWeek; day = st.wDay; hours = st.wHour; min = st.wMinute; sec = st.wSecond; #else _asm { // Call GetDate mov ah, 0x2a int 0x21 mov year, cx mov month, dx mov day, dx mov dayOfweek, ax // Call GetTime mov ah, 0x2c int 0x21 mov hours, cx mov min, cx mov sec, dx } month >>= 8; month -= 1; day &= 0xFF; dayOfweek &= 0xFF; hours >>= 8; min &= 0xFF; sec >>= 8; #endif //_WIN32 #else // defined(_MAC) // REVIEW MAC -- need function here to get current date & time day = 9; month = 1; year = 1960; hours = 12; min = 30; sec = 17; #endif //_MAC // Format time as: Wed Jan 02 02:03:55 1990 // Format time as: Wed 05/02/1992 02:03:55 #if defined(UNICODE) wsprintf(lpsz, TEXT("%ws %ws %02d %02d:%02d:%02d %d"), dayNames[dayOfweek],monthNames[month], day, hours, min, sec, year); #else wsprintfA(lpsz, "%s %s %02d %02d:%02d:%02d %d", dayNames[dayOfweek],monthNames[month], day, hours, min, sec, year); #endif } class FAR CDebugLog { private: HFILE m_fhLog; public: CDebugLog( ) { m_fhLog = -1; } CDebugLog( LPCTSTR lpszFileName ); ~CDebugLog() { DbgLogClose(m_fhLog); } HFILE Open(LPCTSTR lpszFileName, LPCTSTR lpszMode) { return (m_fhLog = DbgLogOpen(lpszFileName, lpszMode)); } void Close(void) { DbgLogClose(m_fhLog); m_fhLog = -1; } void OutputDebugString(LPCTSTR lpsz) { DbgLogOutputDebugString(m_fhLog, lpsz); } void TimeStamp(LPCTSTR lpsz) { DbgLogTimeStamp(m_fhLog, lpsz); } void WriteBanner(LPCTSTR lpsz) { DbgLogWriteBanner(m_fhLog, lpsz); } }; //------------------------------------------------------------------------- // Thought for the decade: // All these methods and all these functions and crud, for what? // So we can avoid calling the shared, system-provided, *printf? // Was it worth it? Is Barney a genius? He sure knows how to lead // everyone down the garden path... //------------------------------------------------------------------------- class FAR CDebugStream : public CPrivAlloc { public: STDSTATIC_(IDebugStream FAR *) Create( // no aggregation int margin, int tabsize, BOOL fHeader); private: CDebugStream( int margin, int tabsize, BOOL fHeader ); ~CDebugStream(); void OutputDebugString( LPCTSTR lpsz ) {m_DbgLog.OutputDebugString(lpsz);} implementations: implement CDSImpl : IDebugStream { public: CDSImpl( CDebugStream FAR * pDebugStream ) { m_pDebugStream = pDebugStream; } ~CDSImpl( void ) ; //{ if (m_pDebugStream->m_pendingReturn) ForceReturn(); } void PrintString( LPTSTR ); void ForceReturn( void ); void ReturnIfPending( void ); STDMETHOD(QueryInterface)(REFIID iid, LPVOID FAR* ppvObj ); STDMETHOD_(ULONG,AddRef)( void ); STDMETHOD_(ULONG,Release)( void ); STDMETHOD_(IDebugStream&, operator << ) ( IUnknown FAR * pDebug ); STDMETHOD_(IDebugStream&, operator << ) ( REFCLSID rclsid ); STDMETHOD_(IDebugStream&, operator << ) ( int n ); STDMETHOD_(IDebugStream&, operator << ) ( long l ); STDMETHOD_(IDebugStream&, operator << ) ( ULONG l ); STDMETHOD_(IDebugStream&, operator << ) ( LPCTSTR sz ); STDMETHOD_(IDebugStream&, operator << ) ( TCHAR ch ); STDMETHOD_(IDebugStream&, operator << ) ( void FAR * pv ); STDMETHOD_(IDebugStream&, operator << ) ( CBool b ); STDMETHOD_(IDebugStream&, operator << ) ( CAtom atom ); STDMETHOD_(IDebugStream&, operator << ) ( CHwnd hwnd ); STDMETHOD_(IDebugStream&, Tab) ( void ); STDMETHOD_(IDebugStream&, Indent) ( void ); STDMETHOD_(IDebugStream&, UnIndent) ( void ); STDMETHOD_(IDebugStream&, Return) ( void ); STDMETHOD_(IDebugStream&, LF) ( void ); CDebugStream FAR * m_pDebugStream; }; DECLARE_NC(CDebugStream,CDSImpl) CDSImpl m_DebugStream; shared_state: ULONG m_refs; int m_indent; int m_position; int m_margin; int m_tabsize; BOOL m_pendingReturn; CDebugLog m_DbgLog; }; #endif // _DEBUG /* * The member variable m_pendingReturn is a hack to allow * the sequence of operations Return, UnIndent put the character * at the *beginning of the unindented line* The debugwindow does * not seem to support going to the beginning of the line or * backspacing, so we do not actually do a Return until we know * that the next operation is not UnIndent. * */ /* * Implementation of per process list heads */ #ifdef NEVER // per-proces debug lists not used static IDebug FAR * GetIDHead() { if this gets enabled, the map should be in the etask } static void SetIDHead(IDebug FAR* pIDHead) { if this gets enabled, the map should be in the etask } #endif // NEVER /* * Implementation of IDebug constructor and destructor */ #ifdef NEVER __export IDebug::IDebug( void ) { SETPVTBL(IDebug); //#ifdef _DEBUG BOOL fIsShared = (SHARED == PlacementOf(this)); IDebug FAR* pIDHead = (fIsShared ? pIDHeadShared : GetIDHead()); pIDPrev = NULL; if (pIDHead) pIDHead->pIDPrev = this; pIDNext = pIDHead; if (fIsShared) pIDHeadShared = this; else SetIDHead(this); } #endif //NEVER #ifdef NEVER __export IDebug::~IDebug( void ) { //#ifdef _DEBUG BOOL fIsShared = (SHARED == PlacementOf(this)); if (pIDPrev) pIDPrev->pIDNext = pIDNext; else if (fIsShared) pIDHeadShared = pIDNext; else SetIDHead(pIDNext); if (pIDNext) pIDNext->pIDPrev = pIDPrev; } #endif //NEVER //REVIEW: maybe we should expose this later STDAPI OleGetClassID( LPUNKNOWN pUnk, LPCLSID lpclsid ) { LPRUNNABLEOBJECT lpRunnableObject = NULL; LPPERSIST lpPersist = NULL; HRESULT hresult = NOERROR; VDATEIFACE(pUnk); VDATEPTROUT(lpclsid, LPCLSID); *lpclsid = CLSID_NULL; pUnk->QueryInterface(IID_IRunnableObject, (LPLPVOID)&lpRunnableObject); if( lpRunnableObject ){ hresult = lpRunnableObject->GetRunningClass(lpclsid); lpRunnableObject->Release(); } else { pUnk->QueryInterface(IID_IPersist, (LPLPVOID)&lpPersist); if( lpPersist ){ hresult = lpPersist->GetClassID( lpclsid ); lpPersist->Release(); } } return hresult; } #ifdef _DEBUG CDebugStream::CDebugStream( int margin, int tabsize, BOOL fHeader) : m_DebugStream(this) { #ifndef _MAC static BOOL fAppendFile = FALSE; // Create the debug log file. Overwrite the existing file if it exists. m_DbgLog.Open(DBGLOGFILENAME, (fAppendFile ? TEXT("a") : TEXT("w"))); if( fHeader ) // only add creation timestamp to top of file. if (! fAppendFile) { m_DbgLog.TimeStamp(TEXT("Created")); fAppendFile = TRUE; } else { m_DbgLog.WriteBanner(NULL); } #endif m_indent = 0; m_position = m_indent; m_margin = margin; m_tabsize = tabsize; m_refs = 1; m_pendingReturn = FALSE; } CDebugStream::~CDebugStream() { m_DbgLog.Close(); } NC(CDebugStream,CDSImpl)::~CDSImpl(void) { if (m_pDebugStream->m_pendingReturn) ForceReturn(); } STDMETHODIMP NC(CDebugStream,CDSImpl)::QueryInterface(REFIID iidInterface, void FAR* FAR* ppvObj ) { VDATEPTROUT(ppvObj, LPLPVOID); if (IsEqualGUID(iidInterface, IID_IUnknown) || IsEqualGUID(iidInterface, IID_IDebugStream)) { *ppvObj = (void FAR *)this; return NOERROR; } else { *ppvObj = NULL; return ReportResult(0, E_NOINTERFACE, 0, 0); } } STDMETHODIMP_(ULONG) NC(CDebugStream,CDSImpl)::AddRef( void ) { return ++m_pDebugStream->m_refs; } STDMETHODIMP_(ULONG) NC(CDebugStream,CDSImpl)::Release( void ) { if (--m_pDebugStream->m_refs == 0) { delete m_pDebugStream; return 0; } return m_pDebugStream->m_refs; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (int n) { TCHAR buffer[12]; ReturnIfPending(); buffer[swprintf(buffer, TEXT("%d"), n)] = TEXT('\0'); PrintString(buffer); return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (long l) { TCHAR buffer[16]; ReturnIfPending(); buffer[swprintf(buffer, TEXT("%ld"), l)] = TEXT('\0'); PrintString(buffer); return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (ULONG l) { TCHAR buffer[16]; ReturnIfPending(); buffer[swprintf(buffer, TEXT("%lu"), l)] = TEXT('\0'); PrintString(buffer); return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (CAtom atom) { TCHAR buffer[128]; ReturnIfPending(); if( (ATOM)atom ){ if( !GetAtomName((ATOM)atom, buffer, sizeof(buffer)) ) buffer[swprintf(buffer, TEXT("Invalid atom"))] = TEXT('\0'); }else buffer[swprintf(buffer, TEXT("NULL atom"))] = TEXT('\0'); PrintString(buffer); return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (CHwnd hwnd) { TCHAR szBuf[128]; ReturnIfPending(); if( (HWND)hwnd ) szBuf[swprintf(szBuf, TEXT("window handle: %x"), (HWND)hwnd)] = TEXT('\0'); else szBuf[swprintf(szBuf, TEXT("NULL window handle"))] = TEXT('\0'); PrintString(szBuf); return *this; } LPTSTR FindBreak( LPTSTR sz, int currentPosition, int margin ) { LPTSTR szBreak = sz; LPTSTR szPtr = sz; if( !sz ) return NULL; while (*szPtr) { while (*(szPtr) && *(szPtr++) <= TEXT(' ')); while (*(szPtr) && *(szPtr++) > TEXT(' ')); if (currentPosition+(szPtr-sz) < margin) { szBreak = szPtr; } else return szBreak; } return szPtr; } /* * PrintString is an internal utility routine that can assume that * everything in the string (other than the null at the end) is >= * ' '. Thus it knows that when it prints a single character, the * position on the debug terminal advances a single columm. This * would not be the case if the string could contain tabs, * returns, etc. */ void NC(CDebugStream,CDSImpl)::PrintString(LPTSTR sz) { // assert sz != NULL LPTSTR szUnprinted = sz; LPTSTR szPtr = sz; TCHAR chSave; #ifdef _MAC Puts(sz); return; #endif if( !sz ) return; while (*szUnprinted) { szPtr = FindBreak( szUnprinted, m_pDebugStream->m_position, m_pDebugStream->m_margin ); if (szPtr == szUnprinted && m_pDebugStream->m_position > m_pDebugStream->m_indent) { Return(); szPtr = FindBreak( szUnprinted, m_pDebugStream->m_position, m_pDebugStream->m_margin ); if (szPtr == szUnprinted) // text won't fit even after word wrapping { m_pDebugStream->OutputDebugString(szUnprinted); m_pDebugStream->m_position += _xstrlen(szUnprinted); return; } } chSave = *szPtr; *szPtr = TEXT('\0'); if (m_pDebugStream->m_position == m_pDebugStream->m_indent) // no text on line, skip blanks { while (*szUnprinted == TEXT(' ')) szUnprinted++; } m_pDebugStream->OutputDebugString(szUnprinted); *szPtr = chSave; m_pDebugStream->m_position += (ULONG) (szPtr - szUnprinted); szUnprinted = szPtr; } } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (TCHAR ch) { TCHAR buffer[2] = TEXT("a"); if (ch==TEXT('\n')) Return(); else if (ch==TEXT('\t')) Tab(); else if (ch >= TEXT(' ')) { ReturnIfPending(); if (m_pDebugStream->m_position >= m_pDebugStream->m_margin) Return(); *buffer = ch; m_pDebugStream->OutputDebugString(buffer); m_pDebugStream->m_position++; } return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (LPCTSTR sz) { LPTSTR szCopy; TCHAR chSave; LPTSTR szPtr; LPTSTR szPtrSave; ReturnIfPending(); if (!sz) return *this; szCopy = (LPTSTR)PubMemAlloc(sizeof(TCHAR)*(2+_xstrlen(sz))); if (!szCopy) { Return(); *this << TEXT("Memory allocation error in DebugStream"); Return(); return *this; } _xstrcpy( szCopy, sz ); for (szPtr = szCopy, szPtrSave = szCopy; *szPtr; szPtr++) { if ( *szPtr < TEXT(' '))// we hit a control character or the end { chSave = *szPtr; *szPtr = TEXT('\0'); PrintString( szPtrSave ); if (chSave != TEXT('\0')) *szPtr = chSave; szPtrSave = szPtr+1; switch (chSave) { case TEXT('\t'): Tab(); break; case TEXT('\n'): Return(); break; case TEXT('\r'): m_pDebugStream->OutputDebugString(TEXT("\r")); break; default: break; } } } PrintString( szPtrSave ); PubMemFree(szCopy); return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (CBool b) { ReturnIfPending(); if (b) *this << TEXT("TRUE"); else *this << TEXT("FALSE"); return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << ( void FAR * pv ) { TCHAR buffer[12]; ReturnIfPending(); if (pv == NULL) *this << TEXT("NULL"); else { buffer[swprintf(buffer, TEXT("%lX"), pv)] = TEXT('\0'); PrintString(buffer); } return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << ( REFCLSID rclsid ) { TCHAR sz[256]; #if !defined(_CHICAGO_) if (IsEqualGUID(rclsid, CLSID_NULL)) _xstrcpy(sz, TEXT("NULL CLSID")); else if (StringFromCLSID2(rclsid, sz, sizeof(sz)) == 0) _xstrcpy(sz, TEXT("Unknown CLSID")); *this << sz; #endif return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << ( IUnknown FAR * pUnk ) { IDebug FAR * pDebug = NULL; CLSID clsid = CLSID_NULL; ReturnIfPending(); if (!pUnk) { *this << TEXT("NULL interface"); } else if( IsValidInterface(pUnk) ) { pUnk->QueryInterface(IID_IDebug, (void FAR* FAR*)&pDebug); if (pDebug) { pDebug->Dump( this ); if ( !pDebug->IsValid( 0 ) ) *this << TEXT("Object is not valid") << TEXT('\n'); /* * NB: Debug interfaces are *not* ref counted (so as not to skew the * counts of the objects they are debugging! :) */ } else { OleGetClassID(pUnk, (LPCLSID)&clsid); *this << clsid << TEXT(" @ ")<<(VOID FAR *)pUnk << TEXT(" doesn't support debug dumping"); } } else { *this << TEXT("Invalid interface @ ") << (VOID FAR *)pUnk; } return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::Tab( void ) { ReturnIfPending(); int advance = m_pDebugStream->m_tabsize * ( 1 + m_pDebugStream->m_position/m_pDebugStream->m_tabsize) - m_pDebugStream->m_position; if (m_pDebugStream->m_position + advance < m_pDebugStream->m_margin) { for (int i = 0; i < advance; i++) m_pDebugStream->OutputDebugString(TEXT(" ")); m_pDebugStream->m_position += advance; } return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::Indent( void ) { if (m_pDebugStream->m_indent + m_pDebugStream->m_tabsize < m_pDebugStream->m_margin) m_pDebugStream->m_indent += m_pDebugStream->m_tabsize; if (!m_pDebugStream->m_pendingReturn) while (m_pDebugStream->m_position < m_pDebugStream->m_indent) operator<<(TEXT(' ')); return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::UnIndent( void ) { if (m_pDebugStream->m_indent > 0) m_pDebugStream->m_indent -= m_pDebugStream->m_tabsize; return *this; } void NC(CDebugStream,CDSImpl)::ForceReturn( void ) { m_pDebugStream->OutputDebugString(TEXT("\n")); for (int i = 0; im_indent; i++) m_pDebugStream->OutputDebugString(TEXT(" ")); m_pDebugStream->m_position = m_pDebugStream->m_indent; m_pDebugStream->m_pendingReturn = FALSE; } void NC(CDebugStream,CDSImpl)::ReturnIfPending( void ) { if (m_pDebugStream->m_pendingReturn) ForceReturn(); } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::Return( void ) { ReturnIfPending(); m_pDebugStream->m_pendingReturn = TRUE; Yield(); // let dbwin get control return *this; } STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::LF( void ) { return Return(); } STDSTATICIMP_(IDebugStream FAR *) CDebugStream::Create( // no aggregation int margin, int tabsize, BOOL fHeader ) { CDebugStream FAR * pcds = new CDebugStream( margin, tabsize, fHeader ); if( !pcds ){ AssertSz( pcds, "Out of Memory"); return NULL; } return &(pcds->m_DebugStream); } #endif // _DEBUG STDAPI_(IDebugStream FAR *) MakeDebugStream( short margin, short tabsize, BOOL fHeader) { #ifdef _DEBUG return CDebugStream::Create( margin, tabsize, fHeader ); #else (void) margin; (void) tabsize; (void) fHeader; return NULL; #endif // _DEBUG } // // IDebug helpers // STDAPI_(void) DbgDumpObject( IUnknown FAR * pUnk, DWORD dwReserved ) { #ifdef _DEBUG IDebugStream FAR * pcds = MakeDebugStream( DBGMARGIN, DBGTABSIZE, NOHEADER ); (void)dwReserved; if( pcds ) { *pcds << pUnk; pcds->Return(); pcds->Release(); } #else (void) pUnk; (void) dwReserved; #endif } STDAPI_(void) DbgDumpExternalObject( IUnknown FAR * pUnk, DWORD dwReserved ) { //REVIEW32: Compobj does not support RemLookupSHUnk yet (alexgo 11/8/93) #ifdef WIN32 (void)dwReserved; (void)pUnk; #elif _DEBUG SHREG shreg; (void) dwReserved; if( IsValidInterface(pUnk) ){ if( RemLookupSHUnk(pUnk, NULL, &shreg) == NOERROR ){ DbgDumpObject(shreg.m_pSM, 0); shreg.m_pSM->Release(); } } #else (void) dwReserved; (void) pUnk; #endif } STDAPI_(BOOL) DbgIsObjectValid( IUnknown FAR * pUnk ) { #ifdef _DEBUG BOOL fReturn = TRUE; // default value for objects that don't // support IDebug IDebug FAR * pDebug = NULL; if( IsValidInterface(pUnk) ){ pUnk->QueryInterface( IID_IDebug, (void FAR* FAR*)&pDebug); if (pDebug) fReturn = pDebug->IsValid(); //IDebug is not addref'd return fReturn; } return FALSE; #else (void) pUnk; return TRUE; #endif } STDAPI_(void) DbgDumpClassName( IUnknown FAR * pUnk ) { #ifdef _DEBUG CLSID clsid; IDebugStream FAR * pcds = MakeDebugStream( DBGMARGIN, DBGTABSIZE, NOHEADER ); if( pcds ) { if( IsValidInterface(pUnk) ){ OleGetClassID( pUnk, (LPCLSID)&clsid); *pcds << clsid << TEXT(" @ ") << (void FAR* )pUnk << TEXT('\n'); }else if (!pUnk) *pcds << TEXT("NULL interface") << TEXT('\n'); else *pcds << (void FAR *)pUnk << TEXT(" is not a valid interface") << TEXT('\n'); pcds->Release(); } #else (void)pUnk; #endif } STDAPI_(void) DumpAllObjects( void ) { //#ifdef _DEBUG #ifdef NEVER IDebug FAR * pID = GetIDHead(); IDebugStream FAR * pcds = MakeDebugStream( DBGMARGIN, DBGTABSIZE, NOHEADER ); *pcds << TEXT("----TASK OBJECTS-------\n"); while (pID) { pID->Dump( pcds ); pID = pID->pIDNext; } *pcds << TEXT("----SHARED OBJECTS-------\n"); pID = pIDHeadShared; while (pID) { pID->Dump( pcds ); pID = pID->pIDNext; } pcds->Release(); #endif } STDAPI_(BOOL) ValidateAllObjects( BOOL fSuspicious ) { //#ifdef _DEBUG #ifdef NEVER IDebug FAR * pID = GetIDHead(); int pass = 0; IDebugStream FAR * pcds = MakeDebugStream( DBGMARGIN, DBGTABSIZE, NOHEADER); BOOL fReturn = TRUE; while (pID) { if (!(pID->IsValid(fSuspicious))) { fReturn = FALSE; if (pass == 0) *pcds << TEXT("\n****INVALID OBJECT*****\n"); else *pcds << TEXT("\n****INVALID SHARED MEMORY OBJECT*****\n"); pID->Dump( pcds ); pcds->Return(); } pID = pID->pIDNext; if ((pID == NULL) && (pass++ == 0)) pID = pIDHeadShared; } pcds->Release(); return fReturn; #endif //NEVER (void) fSuspicious; return TRUE; } #ifdef _DEBUG extern "C" BOOL CALLBACK __loadds DebCallBack(WORD wID, DWORD dwData) { // TCHAR rgchBuf[50]; //// BOOL fTraceStack = FALSE; //// STACKTRACEENTRY ste; //// WORD wSS, wCS, wIP, wBP; // NFYLOADSEG FAR* pNFY = (NFYLOADSEG FAR *)dwData; // // if (wID == NFY_LOADSEG) // { // if (0 == _xstrcmp(pNFY->lpstrModuleName, TEXT("OLE2"))) // { // swprintf(rgchBuf, TEXT("Load seg %02x(%#04x), module %s"), pNFY->wSegNum, // pNFY->wSelector, pNFY->lpstrModuleName); // OutputDebugString(rgchBuf); // _asm int 3 //// if (fTraceStack) //// { //// _asm mov wSS, SS //// _asm mov wCS, CS //// _asm mov wIP, IP //// _asm mov wBP, BP //// ste.dwSize = sizeof(STACKTRACEENTRY); //// if (StackTraceCSIPFirst(&ste, wSS, wCS, wIP, wBP)) //// { //// while (fTraceStack && StackTraceNext(&ste)); //// } //// //// } // } // } // else if (wID == NFY_FREESEG) // { // } (void) wID; (void) dwData; return FALSE; } BOOL InstallHooks(void) { // return NotifyRegister(NULL, (LPFNNOTIFYCALLBACK)DebCallBack, NF_NORMAL); return TRUE; } BOOL UnInstallHooks() { // return NotifyUnRegister(NULL); return TRUE; } #endif