// // // // This file cannot be compiled as a C++ file, otherwise the linker // will bail on unresolved externals (even with extern "C" wrapping // this). #include "precomp.h" // Define some things for debug.h // #define SZ_DEBUGINI "ccshell.ini" #define SZ_DEBUGSECTION "deskcpl" #define SZ_MODULE "DESKCPL" #define DECLARE_DEBUG #include "debug.h" // Include the standard helper functions to dump common ADTs //#include "..\lib\dump.c" #ifdef DEBUG // // Typedefs // typedef struct _ALLOCHEADER { LIST_ENTRY ListEntry; PTCHAR File; ULONG Line; LONG AllocNumber; ULONG Size; } ALLOCHEADER, *PALLOCHEADER; // // Globals // LIST_ENTRY AllocListHead = { &AllocListHead, &AllocListHead }; #undef LocalAlloc #undef LocalReAlloc #undef LocalFree INT g_BreakAtAlloc = -1; INT g_BreakAtFree = -1; ULONG g_AllocNumber = 0; #define TRAP() DbgBreakPoint() //***************************************************************************** // // MyAlloc() // //***************************************************************************** HLOCAL DeskAllocPrivate ( const TCHAR *File, ULONG Line, ULONG Flags, DWORD dwBytes ) { static ULONG allocNumber = 0; DWORD bytes; PALLOCHEADER header; if (dwBytes) { bytes = dwBytes + sizeof(ALLOCHEADER); header = (PALLOCHEADER)LocalAlloc(Flags, bytes); if (header != NULL) { InsertTailList(&AllocListHead, &header->ListEntry); header->File = (TCHAR*) File; header->Line = Line; header->AllocNumber = ++allocNumber; header->Size = dwBytes; if (header->AllocNumber == g_BreakAtAlloc) { // user set assert TRAP(); } return (HLOCAL)(header + 1); } } return NULL; } //***************************************************************************** // // MyReAlloc() // //***************************************************************************** HLOCAL DeskReAllocPrivate ( const TCHAR *File, ULONG Line, HLOCAL hMem, DWORD dwBytes, ULONG Flags ) { PALLOCHEADER header; PALLOCHEADER headerNew; if (hMem) { header = (PALLOCHEADER)hMem; header--; // Remove the old address from the allocation list // RemoveEntryList(&header->ListEntry); headerNew = (PALLOCHEADER) LocalReAlloc((HLOCAL)header, dwBytes, Flags); if (headerNew != NULL) { // Add the new address to the allocation list // headerNew->File = (TCHAR*) File; headerNew->Line = Line; headerNew->AllocNumber = ++g_AllocNumber; headerNew->Size = dwBytes; if (headerNew->AllocNumber == g_BreakAtAlloc) { // user set assert TRAP(); } InsertTailList(&AllocListHead, &headerNew->ListEntry); return (HLOCAL)(headerNew + 1); } else { // If GlobalReAlloc fails, the original memory is not freed, // and the original handle and pointer are still valid. // Add the old address back to the allocation list. // InsertTailList(&AllocListHead, &header->ListEntry); } } return NULL; } //***************************************************************************** // // MyFree() // //***************************************************************************** HLOCAL DeskFreePrivate ( HLOCAL hMem ) { PALLOCHEADER header; TCHAR buf[128]; if (hMem) { header = (PALLOCHEADER)hMem; header--; if (header->AllocNumber == g_BreakAtFree) { TRAP(); } wsprintf(buf, TEXT("free alloc number %d, size %d\r\n"), header->AllocNumber, header->Size); RemoveEntryList(&header->ListEntry); return LocalFree((HLOCAL)header); } return LocalFree(hMem); } HLOCAL DeskFreeDirect (HLOCAL hMem) { return(LocalFree(hMem)); } //***************************************************************************** // // MyCheckForLeaks() // //***************************************************************************** VOID DeskCheckForLeaksPrivate ( VOID ) { PALLOCHEADER header; TCHAR buf[1024+40], tmpBuf[512]; unsigned int i, size, size2, ic; DWORD *pdw; char *pch, *pch2; LPVOID mem; #if UNICODE #define DeskIsPrintable iswprint #else #define DeskIsPrintable isprint #endif while (!IsListEmpty(&AllocListHead)) { header = (PALLOCHEADER)RemoveHeadList(&AllocListHead); mem = header + 1; wsprintf(buf, TEXT("Desk.cpl mem leak in File: %s\r\n Line: %d Size: %d Allocation: %d Buffer: 0x%x\r\n"), header->File, header->Line, header->Size, header->AllocNumber, mem); OutputDebugString(buf); // // easy stuff, print out all the 4 DWORDS we can // pdw = (DWORD *) mem; pch = (char *) mem; *buf = TEXT('\0'); for (i = 0; i < header->Size/16; i++, pdw += 4) { wsprintf(tmpBuf, TEXT(" %08x %08x %08x %08x "), pdw[0], pdw[1], pdw[2], pdw[3]); lstrcat(buf, tmpBuf); for (ic = 0; ic < 16; ic++, pch++) { tmpBuf[ic] = DeskIsPrintable(*pch) ? *pch : TEXT('.'); } tmpBuf[ic] = TEXT('\0'); lstrcat(buf, tmpBuf); OutputDebugString(buf); OutputDebugString(TEXT("\n")); *buf = TEXT('\0'); } // // Is there less than a 16 byte chunk left? // size = header->Size % 16; if (size) { // // Print all the DWORDs we can // for (i = 0; i < size / 4; i++, pdw++) { wsprintf(tmpBuf, TEXT(" %08x"), *pdw); lstrcat(buf, tmpBuf); } if (size % 4) { // // Print the remaining bytes // lstrcat(buf, TEXT(" ")); pch2 = (char*) pdw; for (i = 0; i < size % 4; i++, pch2++) { wsprintf(tmpBuf, TEXT("%02x"), (DWORD) *pch2); lstrcat(buf, tmpBuf); } // // Align with 4 bytes // for ( ; i < 4; i++) { lstrcat(buf, TEXT(" ")); } } // // Print blanks for any remaining DWORDs (ie to match the 4 above) // size2 = (16 - (header->Size % 16)) / 4; for (i = 0; i < size2; i++) { lstrcat(buf, TEXT(" ")); } lstrcat(buf, TEXT(" ")); // // Print the actual remain bytes as chars // for (i = 0; i < size; i++, pch++) { tmpBuf[i] = DeskIsPrintable(*pch) ? *pch : TEXT('.'); } tmpBuf[i] = TEXT('\0'); lstrcat(buf, tmpBuf); OutputDebugString(buf); OutputDebugString(TEXT("\n")); } OutputDebugString(TEXT("\n")); ASSERT(0); } } #endif