/******************************************************************************* * * (C) COPYRIGHT MICROSOFT CORPORATION, 1998 * * TITLE: WIADBG.CPP * * VERSION: 1.0 * * AUTHOR: ShaunIv * * DATE: 9/6/1999 * * DESCRIPTION: Implementation of debug code * *******************************************************************************/ // // need to define this so we don't get any recursion on our calls to "new" // #define WIA_DONT_DO_LEAK_CHECKS 1 #include #include #include #include #include "wianew.h" #include "wiadebug.h" #include "simstr.h" #include "miscutil.h" #include #include #include #include #include #define STACK_TRACE_DB_NAME TEXT("ntdll!RtlpStackTraceDataBase") #define SYMBOL_BUFFER_LEN 256 #define READVM(Addr, Buf, Sz) ReadVa(__FILE__, __LINE__, (Globals.Target), (Addr), (Buf), (Sz)) #ifdef UNICODE #define PrintDebugMessage PrintDebugMessageW #else #define PrintDebugMessage PrintDebugMessageA #endif /****************************************************************************** * * Class definitions * ******************************************************************************/ static CGlobalDebugState g_GlobalDebugState; class CWiaDebugWindowThreadState { private: int m_nIndentLevel; DWORD m_nDebugMask; private: // Not implemented CWiaDebugWindowThreadState( const CWiaDebugWindowThreadState & ); CWiaDebugWindowThreadState &operator=( const CWiaDebugWindowThreadState & ); public: CWiaDebugWindowThreadState(void); DWORD DebugMask(void) const; DWORD DebugMask( DWORD nDebugMask ); int IndentLevel(void) const; int IncrementIndentLevel(void); int DecrementIndentLevel(void); }; class CProcessGlobalDebugData { private: DWORD m_dwTlsIndex; BOOL m_bSymLookupInitialized; PVOID m_pDatabase; HANDLE m_hProcess; CSimpleCriticalSection m_CriticalSection; typedef struct _STACK_NODE { LPVOID pKeyAddress; size_t Size; PVOID aStack[32]; ULONG ulNumTraces; _STACK_NODE * pNext; } STACK_NODE, *PSTACK_NODE; PSTACK_NODE m_pStackList; PSTACK_NODE m_pStackListEnd; LONG m_Leaks; private: static CProcessGlobalDebugData *m_pTheProcessGlobalDebugData; private: // Not implemented CProcessGlobalDebugData( const CProcessGlobalDebugData & ); CProcessGlobalDebugData &operator=( const CProcessGlobalDebugData & ); private: // Sole implemented constructor CProcessGlobalDebugData(void); // resolve symbols address into symbols names... LPTSTR GetSymbolicNameForAddress( ULONG_PTR Address ); BOOL IsSymbolLookupInitialized(); public: ~CProcessGlobalDebugData(void); DWORD TlsIndex(void) const; bool IsValid(void) const; void DoRecordAllocation( LPVOID pv, size_t Size ); void DoRecordFree( LPVOID pv ); void GenerateLeakReport( LPTSTR pszModuleName ); HANDLE ProcessHandle( ) { return m_hProcess; } static CProcessGlobalDebugData *Allocate(void); static CProcessGlobalDebugData *ProcessData(void); static void Free(void); }; /****************************************************************************** * * Symbol functions * ******************************************************************************/ BOOL EnumerateModules( IN LPSTR ModuleName, IN ULONG_PTR BaseOfDll, IN PVOID UserContext ) /* * EnumerateModules * * Module enumeration 'proc' for imagehlp. Call SymLoadModule on the * specified module and if that succeeds cache the module name. * * ModuleName is an LPSTR indicating the name of the module imagehlp is * enumerating for us; * BaseOfDll is the load address of the DLL, which we don't care about, but * SymLoadModule does; * UserContext is a pointer to the relevant SYMINFO, which identifies * our connection. */ { DWORD64 Result; CProcessGlobalDebugData *pProcessData = CProcessGlobalDebugData::ProcessData(); if (pProcessData && pProcessData->IsValid()) { Result = SymLoadModule(pProcessData->ProcessHandle(), NULL, // hFile not used NULL, // use symbol search path ModuleName, // ModuleName from Enum BaseOfDll, // LoadAddress from Enum 0); // Let ImageHlp figure out DLL size // SilviuC: need to understand exactly what does this function return if (Result) { return FALSE; } return TRUE; } return FALSE; } /****************************************************************************** * * CWiaDebugWindowThreadState * ******************************************************************************/ CWiaDebugWindowThreadState::CWiaDebugWindowThreadState(void) : m_nIndentLevel(0), m_nDebugMask(0xFFFFFFFF) { } DWORD CWiaDebugWindowThreadState::DebugMask(void) const { return m_nDebugMask; } DWORD CWiaDebugWindowThreadState::DebugMask( DWORD nDebugMask ) { DWORD nOldDebugMask = m_nDebugMask; m_nDebugMask = nDebugMask; return nOldDebugMask; } int CWiaDebugWindowThreadState::IndentLevel(void) const { return m_nIndentLevel; } int CWiaDebugWindowThreadState::IncrementIndentLevel(void) { return (++m_nIndentLevel); } int CWiaDebugWindowThreadState::DecrementIndentLevel(void) { --m_nIndentLevel; if (m_nIndentLevel < 0) m_nIndentLevel = 0; return m_nIndentLevel; } /****************************************************************************** * * CProcessGlobalDebugData * ******************************************************************************/ // Sole implemented constructor CProcessGlobalDebugData::CProcessGlobalDebugData(void) : m_dwTlsIndex(TLS_OUT_OF_INDEXES), m_hProcess(NULL), m_pDatabase(NULL), m_bSymLookupInitialized(FALSE), m_pStackList(NULL), m_pStackListEnd(NULL), m_Leaks(0) { m_dwTlsIndex = TlsAlloc(); } CProcessGlobalDebugData::~CProcessGlobalDebugData(void) { if (m_dwTlsIndex != TLS_OUT_OF_INDEXES) TlsFree(m_dwTlsIndex); m_dwTlsIndex = TLS_OUT_OF_INDEXES; if (m_hProcess) { CloseHandle(m_hProcess); m_hProcess = NULL; } m_bSymLookupInitialized = FALSE; CAutoCriticalSection cs(m_CriticalSection); if (m_pStackList) { PSTACK_NODE pNextNode = NULL; for (PSTACK_NODE pNode = m_pStackList; pNode; ) { if (pNode) { pNextNode = pNode->pNext; LocalFree( pNode ); } pNode = pNextNode; pNextNode = NULL; } } } DWORD CProcessGlobalDebugData::TlsIndex(void) const { return m_dwTlsIndex; } bool CProcessGlobalDebugData::IsValid(void) const { return (m_dwTlsIndex != TLS_OUT_OF_INDEXES); } // // Caller must free returned string via LocalFree // LPTSTR CProcessGlobalDebugData::GetSymbolicNameForAddress( ULONG_PTR Address ) { IMAGEHLP_MODULE ModuleInfo; TCHAR SymbolBuffer[512]; PIMAGEHLP_SYMBOL Symbol; ULONG_PTR Offset; LPTSTR pName; BOOL bResult; if (!IsSymbolLookupInitialized()) { return NULL; } if (Address == (ULONG_PTR)-1) { *SymbolBuffer = 0; lstrcpy( SymbolBuffer, TEXT("<< FUZZY STACK TRACE >>") ); pName = (LPTSTR)LocalAlloc( LPTR, (lstrlen( SymbolBuffer ) + 1) * sizeof(TCHAR) ); if (pName) { lstrcpy( pName, SymbolBuffer ); } return pName; } ModuleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE); if (!SymGetModuleInfo( m_hProcess, Address, &ModuleInfo )) { // // can't get the module info, so give back an error message... // *SymbolBuffer = 0; wsprintf( SymbolBuffer, TEXT("<< cannot identify module for address %p >>"), Address ); pName = (LPTSTR)LocalAlloc( LPTR, (lstrlen( SymbolBuffer ) + 1) * sizeof(TCHAR) ); if (pName) { lstrcpy( pName, SymbolBuffer ); } return pName; } Symbol = (PIMAGEHLP_SYMBOL)SymbolBuffer; Symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL) - 1; if (SymGetSymFromAddr( m_hProcess, Address, &Offset, Symbol )) { IMAGEHLP_LINE LineInfo; DWORD Displacement; BOOL bLineInfoPresent; CHAR szString[ 1024 ]; bLineInfoPresent = SymGetLineFromAddr (m_hProcess, Address, &Displacement, &LineInfo); if (bLineInfoPresent) { // // construct string w/filename & linenumber... // wsprintfA( szString, "%s!%s (%s, line %u)", ModuleInfo.ModuleName, Symbol->Name, LineInfo.FileName, LineInfo.LineNumber ); } else { // // no line numbers, so just show symbol + offset // wsprintfA( szString, "%s!%s+%08X", ModuleInfo.ModuleName, Symbol->Name, Offset ); } INT iLen = (lstrlenA(szString)+1); pName = (LPTSTR) LocalAlloc( LPTR, (iLen * sizeof(TCHAR)) ); if (pName == NULL) { return NULL; } #ifdef UNICODE MultiByteToWideChar( CP_ACP, 0, szString, -1, pName, iLen ); #else lstrcpy( pName, szString); #endif return pName; } else { // // can't get the address info, so give back an error message... // *SymbolBuffer = 0; #ifdef UNICODE TCHAR szModW[ MAX_PATH ]; MultiByteToWideChar( CP_ACP, 0, ModuleInfo.ModuleName, -1, szModW, MAX_PATH ); wsprintf( SymbolBuffer, TEXT("<< incorrect symbols for module %s (address %p)"), szModW, Address ); #else wsprintf( SymbolBuffer, TEXT("<< incorrect symbols for module %s (address %p)"), ModuleInfo.ModuleName, Address ); #endif pName = (LPTSTR)LocalAlloc( LPTR, (lstrlen( SymbolBuffer ) + 1) * sizeof(TCHAR) ); if (pName) { lstrcpy( pName, SymbolBuffer ); } return pName; } return NULL; } void CProcessGlobalDebugData::DoRecordAllocation( LPVOID pv, size_t Size ) { if (!pv) { return; } PVOID StackTrace[32]; ULONG Count; ULONG Index; ULONG Hash; // // Capture stack trace up to 32 items deep, but skip last three items // (because they'll always be the same) // Count = RtlCaptureStackBackTrace( 4, 32, StackTrace, NULL ); if (Count) { CAutoCriticalSection cs(m_CriticalSection); // // Add this stack trace to list // PSTACK_NODE pNewNode = (PSTACK_NODE)LocalAlloc( LPTR, sizeof(STACK_NODE) ); if (pNewNode) { pNewNode->pKeyAddress = pv; pNewNode->Size = Size; pNewNode->ulNumTraces = Count; memcpy( pNewNode->aStack, StackTrace, sizeof(pNewNode->aStack) ); } if (!m_pStackList) { m_pStackList = pNewNode; m_pStackListEnd = pNewNode; } else { m_pStackListEnd->pNext = pNewNode; m_pStackListEnd = pNewNode; } m_Leaks++; } } void CProcessGlobalDebugData::DoRecordFree( LPVOID pv ) { if (!pv) { return; } CAutoCriticalSection cs(m_CriticalSection); // // Find item in allocation list... // PSTACK_NODE pNode = NULL; PSTACK_NODE pTrail = NULL; for ( pNode = m_pStackList; pNode && (pNode->pKeyAddress!=pv); pTrail = pNode, pNode = pNode->pNext ) { ; } if (pNode) { // // Remove this node from the list... // if (!pTrail) { // // It's the first item in list // m_pStackList = pNode->pNext; if (m_pStackListEnd == pNode) { m_pStackListEnd = NULL; } LocalFree( (HLOCAL) pNode ); m_Leaks--; } else { // // We're somewhere in the middle of the list... // pTrail->pNext = pNode->pNext; if (m_pStackListEnd == pNode) { m_pStackListEnd = pTrail; } LocalFree( (HLOCAL) pNode ); m_Leaks--; } } } void CProcessGlobalDebugData::GenerateLeakReport(LPTSTR pszModuleName) { CAutoCriticalSection cs(m_CriticalSection); // // Report the numer of leaks... // TCHAR sz[ 512 ]; TCHAR szNewLine[ 3 ]; COLORREF crFore = static_cast(0xFFFFFFFF), crBack = static_cast(0xFFFFFFFF); if (m_Leaks > 0) { crFore = RGB(0x00,0x00,0x00); crBack = RGB(0xFF,0x7F,0x7F); } lstrcpy( szNewLine, TEXT("\n") ); PrintDebugMessage( 2, 0xFFFFFFFF, crFore, crBack, pszModuleName, szNewLine ); wsprintf( sz, TEXT("**** Reporting leaks -- %d leaks found ****"), m_Leaks ); PrintDebugMessage( 2, 0xFFFFFFFF, crFore, crBack, pszModuleName, sz ); // // Loop through the list... // LPTSTR pSymbol = NULL; PSTACK_NODE pNode = m_pStackList; INT i = 1; while (pNode) { PrintDebugMessage( 2, 0xFFFFFFFF, crFore, crBack, pszModuleName, szNewLine ); wsprintf( sz, TEXT("Leak %d - %d bytes allocated by:"), i++, pNode->Size ); PrintDebugMessage( 2, 0xFFFFFFFF, crFore, crBack, pszModuleName, sz ); for (INT j=0; (j < (INT)pNode->ulNumTraces) && (pNode->aStack[j]); j++) { pSymbol = GetSymbolicNameForAddress( (ULONG_PTR)pNode->aStack[j] ); if (pSymbol) { PrintDebugMessage( 2, 0xFFFFFFFF, crFore, crBack, pszModuleName, pSymbol ); LocalFree( (HLOCAL)pSymbol ); } else { wsprintf( sz, TEXT("< could not resolve symbols for address %p >"),pNode->aStack[j] ); PrintDebugMessage( 2, 0xFFFFFFFF, crFore, crBack, pszModuleName, sz ); } } pNode = pNode->pNext; } PrintDebugMessage( 2, 0xFFFFFFFF, crFore, crBack, pszModuleName, szNewLine ); PrintDebugMessage( 2, 0xFFFFFFFF, crFore, crBack, pszModuleName, TEXT("**** End Leak Report ****") ); PrintDebugMessage( 2, 0xFFFFFFFF, crFore, crBack, pszModuleName, szNewLine ); } BOOL CProcessGlobalDebugData::IsSymbolLookupInitialized() { CAutoCriticalSection cs(m_CriticalSection); if (!m_bSymLookupInitialized) { if (m_hProcess) { CloseHandle( m_hProcess ); m_hProcess = NULL; } m_hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId() ); if (m_hProcess) { if (SymInitialize( m_hProcess, NULL, TRUE )) { SymSetOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); if (SymEnumerateModules( m_hProcess, EnumerateModules, m_hProcess)) { m_bSymLookupInitialized = TRUE; } } } } return m_bSymLookupInitialized; } CProcessGlobalDebugData *CProcessGlobalDebugData::Allocate(void) { if (!m_pTheProcessGlobalDebugData) m_pTheProcessGlobalDebugData = new CProcessGlobalDebugData; return (m_pTheProcessGlobalDebugData); } CProcessGlobalDebugData *CProcessGlobalDebugData::ProcessData(void) { return Allocate(); } void CProcessGlobalDebugData::Free(void) { if (m_pTheProcessGlobalDebugData) { delete m_pTheProcessGlobalDebugData; m_pTheProcessGlobalDebugData = NULL; } } CProcessGlobalDebugData *CProcessGlobalDebugData::m_pTheProcessGlobalDebugData = NULL; /****************************************************************************** * * DllMain * ******************************************************************************/ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID ) { BOOL bResult = FALSE; switch (dwReason) { case DLL_PROCESS_ATTACH: { bResult = (CProcessGlobalDebugData::Allocate() != NULL); } break; case DLL_PROCESS_DETACH: { CProcessGlobalDebugData::Free(); bResult = TRUE; } break; case DLL_THREAD_ATTACH: { CProcessGlobalDebugData *pProcessData = CProcessGlobalDebugData::ProcessData(); if (pProcessData && pProcessData->IsValid()) { CWiaDebugWindowThreadState *pThreadData = new CWiaDebugWindowThreadState; TlsSetValue( pProcessData->TlsIndex(), pThreadData ); bResult = (pThreadData != NULL); } } break; case DLL_THREAD_DETACH: { CProcessGlobalDebugData *pProcessData = CProcessGlobalDebugData::ProcessData(); if (pProcessData && pProcessData->IsValid()) { CWiaDebugWindowThreadState *pThreadData = reinterpret_cast(TlsGetValue( pProcessData->TlsIndex())); if (pThreadData) { delete pThreadData; TlsSetValue( pProcessData->TlsIndex(), NULL ); } } bResult = TRUE; } break; } return bResult; } /****************************************************************************** * * Global Helper Functions * ******************************************************************************/ static bool IsProcessDebugFlagSet( DWORD dwModuleMask ) { bool bResult = false; CProcessGlobalDebugData *pProcessData = CProcessGlobalDebugData::ProcessData(); if (pProcessData && pProcessData->IsValid()) { CWiaDebugWindowThreadState *pThreadData = reinterpret_cast(TlsGetValue(pProcessData->TlsIndex())); if (pThreadData) { bResult = ((pThreadData->DebugMask() & dwModuleMask) != 0); } } return (bResult); } static CWiaDebugWindowThreadState *ThreadData(void) { CWiaDebugWindowThreadState *pThreadData = NULL; CProcessGlobalDebugData *pProcessData = CProcessGlobalDebugData::ProcessData(); if (pProcessData && pProcessData->IsValid()) { pThreadData = reinterpret_cast(TlsGetValue(pProcessData->TlsIndex())); if (!pThreadData) { pThreadData = new CWiaDebugWindowThreadState; TlsSetValue( pProcessData->TlsIndex(), pThreadData ); } } return (pThreadData); } template static BOOL ContainsNonWhitespace( T *lpszMsg ) { for (T *lpszPtr = lpszMsg;*lpszPtr;lpszPtr++) if (*lpszPtr != ' ' && *lpszPtr != '\n' && *lpszPtr != '\r' && *lpszPtr != '\t') return TRUE; return FALSE; } static void InsertStackLevelIndent( LPSTR lpszMsg, int nStackLevel ) { const LPSTR lpszIndent = " "; CHAR szTmp[1024], *pstrTmp, *pstrPtr; pstrTmp=szTmp; pstrPtr=lpszMsg; while (pstrPtr && *pstrPtr) { // if the current character is a newline and it isn't the // last character, append the indent string if (*pstrPtr=='\n' && ContainsNonWhitespace(pstrPtr)) { *pstrTmp++ = *pstrPtr++; for (int i=0;iIsValid()) { CWiaDebugWindowThreadState *pThreadData = reinterpret_cast(TlsGetValue(pProcessData->TlsIndex())); if (pThreadData) { return pThreadData->IncrementIndentLevel(); } } return 0; } int WINAPI DecrementDebugIndentLevel(void) { CProcessGlobalDebugData *pProcessData = CProcessGlobalDebugData::ProcessData(); if (pProcessData && pProcessData->IsValid()) { CWiaDebugWindowThreadState *pThreadData = reinterpret_cast(TlsGetValue(pProcessData->TlsIndex())); if (pThreadData) { return pThreadData->DecrementIndentLevel(); } } return 0; } DWORD WINAPI GetDebugMask(void) { CProcessGlobalDebugData *pProcessData = CProcessGlobalDebugData::ProcessData(); if (pProcessData && pProcessData->IsValid()) { CWiaDebugWindowThreadState *pThreadData = reinterpret_cast(TlsGetValue(pProcessData->TlsIndex())); if (pThreadData) { return pThreadData->DebugMask(); } } return 0; } DWORD WINAPI SetDebugMask( DWORD dwNewMask ) { CProcessGlobalDebugData *pProcessData = CProcessGlobalDebugData::ProcessData(); if (pProcessData && pProcessData->IsValid()) { CWiaDebugWindowThreadState *pThreadData = reinterpret_cast(TlsGetValue(pProcessData->TlsIndex())); if (pThreadData) { return pThreadData->DebugMask(dwNewMask); } } return 0; } BOOL WINAPI PrintDebugMessageW( DWORD dwSeverity, DWORD dwModuleMask, COLORREF crForeground, COLORREF crBackground, LPCWSTR pszModuleName, LPCWSTR pszMsg ) { BOOL bResult = FALSE; #ifdef UNICODE CWiaDebugWindowThreadState *pThreadData = ThreadData(); if (pThreadData && (dwSeverity || IsProcessDebugFlagSet(dwModuleMask))) { WCHAR szMsg[1024]=L""; // Print thread id wsprintfW( szMsg, L"[%ws-%08X] %ws", pszModuleName, GetCurrentThreadId(), pszMsg ); InsertStackLevelIndent( szMsg, pThreadData->IndentLevel() ); lstrcatW( szMsg, L"\n" ); OutputDebugStringW( szMsg ); // Make sure it is a valid window if (g_GlobalDebugState.DebugWindow()) { CDebugStringMessageData DebugStringMessageData; DebugStringMessageData.crBackground = crBackground; DebugStringMessageData.crForeground = crForeground; DebugStringMessageData.bUnicode = TRUE; lstrcpyW( reinterpret_cast(DebugStringMessageData.szString), szMsg ); COPYDATASTRUCT CopyDataStruct; CopyDataStruct.dwData = COPYDATA_DEBUG_MESSAGE_ID; CopyDataStruct.cbData = sizeof(DebugStringMessageData); CopyDataStruct.lpData = &DebugStringMessageData; g_GlobalDebugState.SendDebugWindowMessage( WM_COPYDATA, 0, reinterpret_cast(&CopyDataStruct) ); } bResult = TRUE; } #else SetLastError(ERROR_CALL_NOT_IMPLEMENTED); #endif return bResult; } BOOL WINAPI PrintDebugMessageA( DWORD dwSeverity, DWORD dwModuleMask, COLORREF crForeground, COLORREF crBackground, LPCSTR pszModuleName, LPCSTR pszMsg ) { BOOL bResult = FALSE; CWiaDebugWindowThreadState *pThreadData = ThreadData(); if (pThreadData && (dwSeverity || IsProcessDebugFlagSet(dwModuleMask))) { CHAR szMsg[1024]=""; // Print thread id wsprintfA( szMsg, "[%hs-%08X] %hs", pszModuleName, GetCurrentThreadId(), pszMsg ); InsertStackLevelIndent( szMsg, pThreadData->IndentLevel() ); lstrcatA( szMsg, "\n" ); OutputDebugStringA( szMsg ); // Make sure it is a valid window if (g_GlobalDebugState.DebugWindow()) { CDebugStringMessageData DebugStringMessageData; DebugStringMessageData.crBackground = crBackground; DebugStringMessageData.crForeground = crForeground; DebugStringMessageData.bUnicode = FALSE; lstrcpyA( static_cast(DebugStringMessageData.szString), szMsg ); COPYDATASTRUCT CopyDataStruct; CopyDataStruct.dwData = COPYDATA_DEBUG_MESSAGE_ID; CopyDataStruct.cbData = sizeof(DebugStringMessageData); CopyDataStruct.lpData = &DebugStringMessageData; g_GlobalDebugState.SendDebugWindowMessage( WM_COPYDATA, 0, reinterpret_cast(&CopyDataStruct) ); } bResult = TRUE; } return bResult; } COLORREF WINAPI AllocateDebugColor(void) { DWORD dwIndex = g_GlobalDebugState.AllocateNextColorIndex(); return g_GlobalDebugState.GetColorFromIndex( dwIndex ); } #define GUID_DEBUG_ENTRY(guid) { &guid, ""#guid } static const struct { const GUID *pGuid; LPCSTR pszName; } s_GuidDebugStrings[] = { GUID_DEBUG_ENTRY(IID_IClassFactory), GUID_DEBUG_ENTRY(IID_ICommDlgBrowser), GUID_DEBUG_ENTRY(IID_IContextMenu), GUID_DEBUG_ENTRY(IID_IContextMenu2), GUID_DEBUG_ENTRY(IID_IDataObject), GUID_DEBUG_ENTRY(IID_IDropTarget), GUID_DEBUG_ENTRY(IID_IEnumIDList), GUID_DEBUG_ENTRY(IID_IExtractIconA), GUID_DEBUG_ENTRY(IID_IExtractIconW), GUID_DEBUG_ENTRY(IID_IFileViewerA), GUID_DEBUG_ENTRY(IID_IFileViewerSite), GUID_DEBUG_ENTRY(IID_IFileViewerW), GUID_DEBUG_ENTRY(IID_IMoniker), GUID_DEBUG_ENTRY(IID_INewShortcutHookA), GUID_DEBUG_ENTRY(IID_INewShortcutHookW), GUID_DEBUG_ENTRY(IID_IOleWindow), GUID_DEBUG_ENTRY(IID_IPersist), GUID_DEBUG_ENTRY(IID_IPersistFile), GUID_DEBUG_ENTRY(IID_IPersistFolder), GUID_DEBUG_ENTRY(IID_IPersistFolder2), GUID_DEBUG_ENTRY(IID_IPropSheetPage), GUID_DEBUG_ENTRY(IID_IQueryInfo), GUID_DEBUG_ENTRY(IID_ISequentialStream), GUID_DEBUG_ENTRY(IID_IShellBrowser), GUID_DEBUG_ENTRY(IID_IShellCopyHookA), GUID_DEBUG_ENTRY(IID_IShellCopyHookW), GUID_DEBUG_ENTRY(IID_IShellDetails), GUID_DEBUG_ENTRY(IID_IShellExecuteHookA), GUID_DEBUG_ENTRY(IID_IShellExecuteHookW), GUID_DEBUG_ENTRY(IID_IShellExtInit), GUID_DEBUG_ENTRY(IID_IShellExtInit), GUID_DEBUG_ENTRY(IID_IShellFolder), GUID_DEBUG_ENTRY(IID_IShellIcon), GUID_DEBUG_ENTRY(IID_IShellIconOverlay), GUID_DEBUG_ENTRY(IID_IShellIconOverlay), GUID_DEBUG_ENTRY(IID_IShellLinkA), GUID_DEBUG_ENTRY(IID_IShellLinkW), GUID_DEBUG_ENTRY(IID_IShellPropSheetExt), GUID_DEBUG_ENTRY(IID_IShellPropSheetExt), GUID_DEBUG_ENTRY(IID_IShellView), GUID_DEBUG_ENTRY(IID_IShellView2), GUID_DEBUG_ENTRY(IID_IShellView2), GUID_DEBUG_ENTRY(IID_IStream), GUID_DEBUG_ENTRY(IID_IUniformResourceLocator), GUID_DEBUG_ENTRY(IID_IUnknown), GUID_DEBUG_ENTRY(WiaImgFmt_UNDEFINED), GUID_DEBUG_ENTRY(WiaImgFmt_MEMORYBMP), GUID_DEBUG_ENTRY(WiaImgFmt_BMP), GUID_DEBUG_ENTRY(WiaImgFmt_EMF), GUID_DEBUG_ENTRY(WiaImgFmt_WMF), GUID_DEBUG_ENTRY(WiaImgFmt_JPEG), GUID_DEBUG_ENTRY(WiaImgFmt_PNG), GUID_DEBUG_ENTRY(WiaImgFmt_GIF), GUID_DEBUG_ENTRY(WiaImgFmt_TIFF), GUID_DEBUG_ENTRY(WiaImgFmt_EXIF), GUID_DEBUG_ENTRY(WiaImgFmt_PHOTOCD), GUID_DEBUG_ENTRY(WiaImgFmt_FLASHPIX), GUID_DEBUG_ENTRY(WiaImgFmt_ICO), GUID_DEBUG_ENTRY(WiaImgFmt_CIFF), GUID_DEBUG_ENTRY(WiaImgFmt_PICT), GUID_DEBUG_ENTRY(WiaImgFmt_JPEG2K), GUID_DEBUG_ENTRY(WiaImgFmt_JPEG2KX), GUID_DEBUG_ENTRY(WiaImgFmt_RTF), GUID_DEBUG_ENTRY(WiaImgFmt_XML), GUID_DEBUG_ENTRY(WiaImgFmt_HTML), GUID_DEBUG_ENTRY(WiaImgFmt_TXT), GUID_DEBUG_ENTRY(WiaImgFmt_MPG), GUID_DEBUG_ENTRY(WiaImgFmt_AVI), GUID_DEBUG_ENTRY(WiaImgFmt_ASF), GUID_DEBUG_ENTRY(WiaImgFmt_SCRIPT), GUID_DEBUG_ENTRY(WiaImgFmt_EXEC), GUID_DEBUG_ENTRY(WiaImgFmt_UNICODE16), GUID_DEBUG_ENTRY(WiaImgFmt_DPOF), GUID_DEBUG_ENTRY(WiaAudFmt_WAV), GUID_DEBUG_ENTRY(WiaAudFmt_MP3), GUID_DEBUG_ENTRY(WiaAudFmt_AIFF), GUID_DEBUG_ENTRY(WiaAudFmt_WMA), GUID_DEBUG_ENTRY(WIA_EVENT_DEVICE_DISCONNECTED), GUID_DEBUG_ENTRY(WIA_EVENT_DEVICE_CONNECTED), GUID_DEBUG_ENTRY(WIA_EVENT_ITEM_DELETED), GUID_DEBUG_ENTRY(WIA_EVENT_ITEM_CREATED), GUID_DEBUG_ENTRY(WIA_EVENT_TREE_UPDATED), GUID_DEBUG_ENTRY(WIA_EVENT_VOLUME_INSERT), GUID_DEBUG_ENTRY(WIA_EVENT_SCAN_IMAGE), GUID_DEBUG_ENTRY(WIA_EVENT_SCAN_PRINT_IMAGE), GUID_DEBUG_ENTRY(WIA_EVENT_SCAN_FAX_IMAGE), GUID_DEBUG_ENTRY(WIA_EVENT_STORAGE_CREATED), GUID_DEBUG_ENTRY(WIA_EVENT_STORAGE_DELETED), GUID_DEBUG_ENTRY(WIA_EVENT_STI_PROXY), GUID_DEBUG_ENTRY(WIA_EVENT_HANDLER_NO_ACTION), GUID_DEBUG_ENTRY(WIA_EVENT_HANDLER_PROMPT), GUID_DEBUG_ENTRY(WIA_CMD_SYNCHRONIZE), GUID_DEBUG_ENTRY(WIA_CMD_TAKE_PICTURE), GUID_DEBUG_ENTRY(WIA_CMD_DELETE_ALL_ITEMS), GUID_DEBUG_ENTRY(WIA_CMD_CHANGE_DOCUMENT), GUID_DEBUG_ENTRY(WIA_CMD_UNLOAD_DOCUMENT), GUID_DEBUG_ENTRY(WIA_CMD_DIAGNOSTIC), GUID_DEBUG_ENTRY(WIA_CMD_DELETE_DEVICE_TREE), GUID_DEBUG_ENTRY(WIA_CMD_BUILD_DEVICE_TREE), GUID_DEBUG_ENTRY(IID_IWiaDevMgr), GUID_DEBUG_ENTRY(IID_IEnumWIA_DEV_INFO), GUID_DEBUG_ENTRY(IID_IWiaEventCallback), GUID_DEBUG_ENTRY(IID_IWiaDataCallback), GUID_DEBUG_ENTRY(IID_IWiaDataTransfer), GUID_DEBUG_ENTRY(IID_IWiaItem), GUID_DEBUG_ENTRY(IID_IWiaPropertyStorage), GUID_DEBUG_ENTRY(IID_IEnumWiaItem), GUID_DEBUG_ENTRY(IID_IEnumWIA_DEV_CAPS), GUID_DEBUG_ENTRY(IID_IEnumWIA_FORMAT_INFO), GUID_DEBUG_ENTRY(IID_IWiaLog), GUID_DEBUG_ENTRY(IID_IWiaLogEx), GUID_DEBUG_ENTRY(IID_IWiaNotifyDevMgr), GUID_DEBUG_ENTRY(LIBID_WiaDevMgr), GUID_DEBUG_ENTRY(CLSID_WiaDevMgr), GUID_DEBUG_ENTRY(CLSID_WiaLog), GUID_DEBUG_ENTRY(IID_IExtractImage2), GUID_DEBUG_ENTRY(IID_IExtractImage), GUID_DEBUG_ENTRY(IID_IShellDetails3), GUID_DEBUG_ENTRY(IID_IShellFolder2) }; #define GUID_DEBUG_MAP_SIZE (sizeof(s_GuidDebugStrings)/sizeof(s_GuidDebugStrings[0])) BOOL WINAPI GetStringFromGuidA( const IID *pGuid, LPSTR pszString, int nMaxLen ) { if (!pGuid || !pszString || !nMaxLen) return FALSE; for (int i=0;iIsValid()) { pProcessData->DoRecordAllocation( pv, Size ); } } } VOID WINAPI DoRecordFree( LPVOID pv ) { if (pv) { CProcessGlobalDebugData *pProcessData = CProcessGlobalDebugData::ProcessData(); if (pProcessData && pProcessData->IsValid()) { pProcessData->DoRecordFree( pv ); } } } VOID WINAPI DoReportLeaks( LPTSTR pszModuleName ) { if (pszModuleName) { CProcessGlobalDebugData *pProcessData = CProcessGlobalDebugData::ProcessData(); if (pProcessData && pProcessData->IsValid()) { pProcessData->GenerateLeakReport( pszModuleName ); } } }