703 lines
21 KiB
C++
703 lines
21 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Microsoft OLE DB RowsetViewer
|
|
// Copyright (C) 1994 - 1999 By Microsoft Corporation.
|
|
//
|
|
// @doc
|
|
//
|
|
// @module SPY.CPP
|
|
//
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Includes
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
#include "Headers.h"
|
|
#include "Spy.h"
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Defines
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Format:
|
|
// HEADSIGNITURE + BUFFERSIZE + BUFFERID + PFILENAME + LINENUMBER + BUFFER + TAILSIGNITURE
|
|
|
|
//All the header info must be ULONGs,
|
|
//so that the user buffer falls on a word boundary
|
|
//The tail must be a byte, since if it was a ULONG it would
|
|
//also require a word boundary, but the users buffer could
|
|
//be an odd number of bytes, so instead of rounding up, just use BYTE
|
|
|
|
const ULONG HEADSIZE = sizeof(ULONG); //HEADSIGNITURE
|
|
const SIZE_T LENGTHSIZE = sizeof(SIZE_T); //BUFFERSIZE
|
|
const ULONG IDSIZE = sizeof(ULONG); //BUFFERID
|
|
const ULONG FILENAMESIZE = sizeof(WCHAR*); //PFILENAME
|
|
const ULONG LINENUMBERSIZE = sizeof(ULONG); //LINENUMBER
|
|
const ULONG TAILSIZE = sizeof(BYTE); //TAILSIGNITURE
|
|
|
|
const ULONG HEADERSIZE = (ULONG)ROUNDUP(HEADSIZE + LENGTHSIZE + IDSIZE + FILENAMESIZE + LINENUMBERSIZE);
|
|
const ULONG FOOTERSIZE = TAILSIZE;
|
|
|
|
const BYTE HEADSIGN = '{';
|
|
const BYTE TAILSIGN = '}';
|
|
|
|
const BYTE ALLOCSIGN = '$';
|
|
const BYTE FREESIGN = 'Z';
|
|
|
|
#define HEAD_OFFSET(pActual) ((BYTE*)pActual)
|
|
#define TAIL_OFFSET(pActual) (USERS_OFFSET(pActual)+BUFFER_LENGTH(pActual))
|
|
|
|
#define USERS_OFFSET(pActual) (HEAD_OFFSET(pActual) + HEADERSIZE)
|
|
#define HEADER_OFFSET(pRequest) ((BYTE*)(pRequest) - HEADERSIZE)
|
|
|
|
#define LENGTH_OFFSET(pActual) (HEAD_OFFSET(pActual) + HEADSIZE)
|
|
#define BUFFER_LENGTH(pActual) (*(SIZE_T*)LENGTH_OFFSET(pActual))
|
|
|
|
#define ID_OFFSET(pActual) (LENGTH_OFFSET(pActual) + LENGTHSIZE)
|
|
#define BUFFER_ID(pActual) (*(ULONG*)ID_OFFSET(pActual))
|
|
|
|
#define FILENAME_OFFSET(pActual) (ID_OFFSET(pActual) + IDSIZE)
|
|
#define BUFFER_FILENAME(pActual) (*(WCHAR**)FILENAME_OFFSET(pActual))
|
|
|
|
#define LINENUMBER_OFFSET(pActual) (FILENAME_OFFSET(pActual) + FILENAMESIZE)
|
|
#define BUFFER_LINENUMBER(pActual) (*(ULONG*)LINENUMBER_OFFSET(pActual))
|
|
|
|
#define HEAD_SIGNITURE(pActual) (*(ULONG*)HEAD_OFFSET(pActual))
|
|
#define TAIL_SIGNITURE(pActual) (*(BYTE*)TAIL_OFFSET(pActual))
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMallocSpy::CMallocSpy()
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
CMallocSpy::CMallocSpy()
|
|
{
|
|
m_cRef = 1;
|
|
m_cbRequest = 0;
|
|
m_cAllocations = 0;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMallocSpy::~CMallocSpy()
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
CMallocSpy::~CMallocSpy()
|
|
{
|
|
//Remove all the elements of the list
|
|
ASSERT(m_cRef == 0);
|
|
CAllocList.RemoveAll();
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMallocSpy::Reset()
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CMallocSpy::Reset()
|
|
{
|
|
//Reset the number of allocations
|
|
m_cAllocations = 0;;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// HRESULT CMallocSpy::AddToList
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CMallocSpy::AddToList(void* pv)
|
|
{
|
|
ASSERT(pv);
|
|
|
|
//NOTE: We don't have to worry about access into our list in Multi-Threads as COM states:
|
|
//"The call to the pre-method through the return from the corresponding post-method
|
|
//is guaranteed to be thread-safe in multi-threaded operations."
|
|
|
|
//Add this element to the list
|
|
CAllocList.AddTail(pv);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// HRESULT CMallocSpy::RemoveFromList
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CMallocSpy::RemoveFromList(void* pv)
|
|
{
|
|
ASSERT(pv);
|
|
|
|
//NOTE: We don't have to worry about access into our list in Multi-Threads as COM states:
|
|
//"The call to the pre-method through the return from the corresponding post-method
|
|
//is guaranteed to be thread-safe in multi-threaded operations."
|
|
|
|
//Remove this element from the list
|
|
POSITION pos = CAllocList.Find(pv);
|
|
if(pos)
|
|
{
|
|
CAllocList.RemoveAt(pos);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// HRESULT CMallocSpy::Register
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CMallocSpy::Register()
|
|
{
|
|
//NOTE: This may fail, if unreigster failed to unload the previous one.
|
|
//CO_E_OBJISREG There is already a registered spy.
|
|
return CoRegisterMallocSpy(this); // Does an AddRef on Object
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// HRESULT CMallocSpy::Unregister
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CMallocSpy::Unregister()
|
|
{
|
|
//NOTE: Unregister will fail if their are outstanding leaks as the docs indicate:
|
|
|
|
//If the return code is E_ACCESSDENIED, there are still outstanding allocations that were
|
|
//made while the spy was active. In this case, the registered spy cannot be revoked at this
|
|
//time because it may have attached arbitrary headers and/or trailers to these allocations
|
|
//that only the spy knows about. Only the spy's PreFree (or PreRealloc) method knows how to
|
|
//account for these headers and trailers. Before returning E_ACCESSDENIED, CoRevokeMallocSpy
|
|
//notes internally that a revoke is pending. When the outstanding allocations have been freed,
|
|
//the revoke proceeds automatically, releasing the IMallocSpy object. Thus, it is necessary to
|
|
//call CoRevokeMallocSpy only once for each call to CoRegisterMallocSpy, even if E_ACCESSDENIED
|
|
//is returned.
|
|
return CoRevokeMallocSpy(); //Does a Release on Object
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// HRESULT CMallocSpy::DumpLeaks
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CMallocSpy::DumpLeaks()
|
|
{
|
|
ULONG cTotalLeaks = 0;
|
|
SIZE_T cTotalBytes = 0;
|
|
DWORD dwSelection = IDOK;
|
|
|
|
//Display Leaks to the Output Window
|
|
while(!CAllocList.IsEmpty())
|
|
{
|
|
//Obtain the pointer to the leaked memory
|
|
void* pRequest = CAllocList.RemoveHead();
|
|
ASSERT(pRequest);
|
|
|
|
void* pActual = HEADER_OFFSET(pRequest);
|
|
ASSERT(pActual);
|
|
|
|
//Make sure that the head/tail signitures are intact
|
|
if(HEAD_SIGNITURE(pActual) != HEADSIGN)
|
|
InternalTraceFmt(L"TRACE - IMallocSpy HeadSigniture Corrupted! - 0x%p, ID=%08lu, %Iu byte(s)\n", pRequest, BUFFER_ID(pActual), BUFFER_LENGTH(pActual));
|
|
|
|
if(TAIL_SIGNITURE(pActual) != TAILSIGN)
|
|
InternalTraceFmt(L"TRACE - IMallocSpy TailSigniture Corrupted! - 0x%p, ID=%08lu, %Iu byte(s)\n", pRequest, BUFFER_ID(pActual), BUFFER_LENGTH(pActual));
|
|
|
|
SIZE_T ulSize = BUFFER_LENGTH(pActual);
|
|
ULONG ulID = BUFFER_ID(pActual);
|
|
WCHAR* pwszFileName= BUFFER_FILENAME(pActual);
|
|
ULONG ulLine = BUFFER_LINENUMBER(pActual);
|
|
|
|
//Display a message box for all leaks (until the user is tired of it...)
|
|
if(dwSelection == IDOK)
|
|
{
|
|
dwSelection = wMessageBox(GetFocus(), MB_TASKMODAL | MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON1,
|
|
L"IMallocSpy Leak",
|
|
L"IMallocSpy Leak:\n"
|
|
L"0x%p, ID=%08lu, %Iu byte(s), File: %s, Line %d\n\n",
|
|
pRequest, ulID, ulSize, pwszFileName, ulLine);
|
|
}
|
|
|
|
//Include FileName and Line Number of the leak...
|
|
InternalTraceFmt(L"-- IMallocSpy Leak! - 0x%p,\tID=%08lu,\t%Iu byte(s),\tFile: %s,\tLine %d" wWndEOL, pRequest, ulID, ulSize, pwszFileName, ulLine);
|
|
|
|
cTotalLeaks++;
|
|
cTotalBytes += ulSize;
|
|
|
|
//Free the Leak
|
|
//You really cant free the leak since the app could be potentially still
|
|
//using it. Or the DLL may still be in use or have attached threads...
|
|
//SAFE_FREE(pActual);
|
|
}
|
|
|
|
if(cTotalLeaks)
|
|
InternalTraceFmt(L"-- IMallocSpy Total Leaks: %lu = %Iu byte(s)" wWndEOL, cTotalLeaks, cTotalBytes);
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// HRESULT CMallocSpy::QueryInterface
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CMallocSpy::QueryInterface(REFIID riid, void** ppIUnknown)
|
|
{
|
|
if(!ppIUnknown)
|
|
return E_INVALIDARG;
|
|
*ppIUnknown = NULL;
|
|
|
|
//IID_IUnknown
|
|
if(riid == IID_IUnknown)
|
|
*ppIUnknown = this;
|
|
//IDD_IMallocSpy
|
|
else if(riid == IID_IMallocSpy)
|
|
*ppIUnknown = this;
|
|
|
|
if(*ppIUnknown)
|
|
{
|
|
((IUnknown*)*ppIUnknown)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ULONG CMallocSpy::AddRef
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
ULONG CMallocSpy::AddRef()
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ULONG CMallocSpy::Release
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
ULONG CMallocSpy::Release()
|
|
{
|
|
if(--m_cRef)
|
|
return m_cRef;
|
|
|
|
TRACE(L"TRACE - Releasing IMallocSpy\n");
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMallocSpy::PreAlloc
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
SIZE_T CMallocSpy::PreAlloc(SIZE_T cbRequest)
|
|
{
|
|
//cbRequest is the orginal number of bytes requested by the user
|
|
//Store the users requested size
|
|
m_cbRequest = cbRequest;
|
|
|
|
//Return the total size requested, plus extra for header/footer
|
|
return (m_cbRequest + HEADERSIZE + FOOTERSIZE);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// void* CMallocSpy::PostAlloc
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void* CMallocSpy::PostAlloc(void* pActual)
|
|
{
|
|
//E_OUTOFMEMORY condition
|
|
if(!pActual)
|
|
return NULL;
|
|
|
|
//pActual is the pointer to the head of the buffer, including the header
|
|
//Add the users pointer to the list
|
|
AddToList(USERS_OFFSET(pActual));
|
|
|
|
//Place the HeadSigniture in the HEADER
|
|
HEAD_SIGNITURE(pActual) = HEADSIGN;
|
|
|
|
//Place the Size in the HEADER
|
|
BUFFER_LENGTH(pActual) = m_cbRequest;
|
|
|
|
//Place the ID in the HEADER
|
|
ULONG ulID = ++m_cAllocations;
|
|
BUFFER_ID(pActual) = ulID;
|
|
|
|
//Place the FILENAME in the HEADER
|
|
BUFFER_FILENAME(pActual) = NULL;
|
|
|
|
//Place the LINE NUMBER in the HEADER
|
|
BUFFER_LINENUMBER(pActual) = 0;
|
|
|
|
//Set the UsersBuffer to a known char
|
|
memset(USERS_OFFSET(pActual), ALLOCSIGN, m_cbRequest);
|
|
|
|
//Place the TailSigniture in the HEADER
|
|
TAIL_SIGNITURE(pActual) = TAILSIGN;
|
|
|
|
//Show Allocation
|
|
if(GetErrorPosting(EP_IMALLOC_ALLOCS))
|
|
InternalTraceFmt(L"TRACE - IMallocSpy Alloc - 0x%p,\tID=%08lu,\t%Iu byte(s)\n", USERS_OFFSET(pActual), ulID, m_cbRequest);
|
|
|
|
//Break at indicated Allocation
|
|
if(g_dwBreakID == ulID)
|
|
BREAKINTO();
|
|
|
|
// Return the actual users buffer
|
|
return USERS_OFFSET(pActual);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// void* CMallocSpy::PreFree
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void* CMallocSpy::PreFree(void* pRequest, BOOL fSpyed)
|
|
{
|
|
//pRequest is the users pointer to thier buffer, not the header
|
|
|
|
//E_OUTOFMEMORY condition
|
|
if(!pRequest)
|
|
return NULL;
|
|
|
|
//If this memory was alloced under IMallocSpy, need to remove it
|
|
if(fSpyed)
|
|
{
|
|
//Remove this pointer from the list
|
|
RemoveFromList(pRequest);
|
|
|
|
void* pActual = HEADER_OFFSET(pRequest);
|
|
ULONG ulID = BUFFER_ID(pActual);
|
|
|
|
//Make sure that the head/tail signitures are intact
|
|
if(HEAD_SIGNITURE(pActual) != HEADSIGN)
|
|
InternalTraceFmt(L"TRACE - IMallocSpy HeadSigniture Corrupted! - 0x%p, ID=%08lu, %Iu byte(s)\n", pRequest, ulID, BUFFER_LENGTH(pActual));
|
|
|
|
if(TAIL_SIGNITURE(pActual) != TAILSIGN)
|
|
InternalTraceFmt(L"TRACE - IMallocSpy TailSigniture Corrupted! - 0x%p, ID=%08lu, %Iu byte(s)\n", pRequest, ulID, BUFFER_LENGTH(pActual));
|
|
|
|
//Break at indicated Allocation
|
|
if(g_dwBreakID == ulID)
|
|
BREAKINTO();
|
|
|
|
//Set the UsersBuffer to a known char
|
|
memset(pRequest, FREESIGN, BUFFER_LENGTH(pActual));
|
|
|
|
//Need to return the actual header pointer to
|
|
//free the entire buffer including the heading
|
|
return pActual;
|
|
}
|
|
|
|
//else
|
|
return pRequest;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// void CMallocSpy::PostFree
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CMallocSpy::PostFree(BOOL fSpyed)
|
|
{
|
|
// Note the free or whatever
|
|
return;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMallocSpy::PreRealloc
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
SIZE_T CMallocSpy::PreRealloc(void* pRequest, SIZE_T cbRequest,
|
|
void** ppNewRequest, BOOL fSpyed)
|
|
{
|
|
ASSERT(pRequest && ppNewRequest);
|
|
|
|
//If this was alloced under IMallocSpy we need to adjust
|
|
//the size stored in the header
|
|
if(fSpyed)
|
|
{
|
|
//Remove the original pRequest pointer from the list
|
|
//Since Realloc could change the original pointer
|
|
RemoveFromList(pRequest);
|
|
|
|
//Find the start
|
|
*ppNewRequest = HEADER_OFFSET(pRequest);
|
|
|
|
//Store the new desired size
|
|
m_cbRequest = cbRequest;
|
|
|
|
//Return the total size, including extra
|
|
return (m_cbRequest + HEADERSIZE + FOOTERSIZE);
|
|
}
|
|
|
|
//else
|
|
*ppNewRequest = pRequest;
|
|
return cbRequest;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// void* CMallocSpy::PostRealloc
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void* CMallocSpy::PostRealloc(void* pActual, BOOL fSpyed)
|
|
{
|
|
//E_OUTOFMEMORY condition
|
|
if(!pActual)
|
|
return NULL;
|
|
|
|
//If this buffer was alloced under IMallocSpy
|
|
if(fSpyed)
|
|
{
|
|
//pActual is the pointer to header
|
|
//Add the new pointer to the list
|
|
AddToList(USERS_OFFSET(pActual));
|
|
|
|
//HeadSigniture should still be intact
|
|
if(HEAD_SIGNITURE(pActual) != HEADSIGN)
|
|
InternalTraceFmt(L"TRACE - IMallocSpy HeadSigniture Corrupted! - 0x%p, ID=%08lu, %Iu byte(s)\n", USERS_OFFSET(pActual), BUFFER_ID(pActual), BUFFER_LENGTH(pActual));
|
|
|
|
//ID should still be intact
|
|
|
|
//Place the new Size in the HEADER
|
|
BUFFER_LENGTH(pActual) = m_cbRequest;
|
|
|
|
//Place the new FileName in the HEADER
|
|
BUFFER_FILENAME(pActual) = NULL;
|
|
|
|
//Place the new Line Number in the HEADER
|
|
BUFFER_LINENUMBER(pActual) = 0;
|
|
|
|
//Need to place the tail signiture again,
|
|
//since it will be over written by the realloc
|
|
TAIL_SIGNITURE(pActual) = TAILSIGN;
|
|
|
|
//Show ReAllocations
|
|
if(GetErrorPosting(EP_IMALLOC_ALLOCS))
|
|
InternalTraceFmt(L"TRACE - IMallocSpy Realloc - 0x%p,\tID=%08lu,\t%Iu byte(s)\n", USERS_OFFSET(pActual), BUFFER_ID(pActual), m_cbRequest);
|
|
|
|
//Return the actual "user" buffer
|
|
return USERS_OFFSET(pActual);
|
|
}
|
|
|
|
//else
|
|
return pActual;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// void* CMallocSpy::PreGetSize
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void* CMallocSpy::PreGetSize(void* pRequest, BOOL fSpyed)
|
|
{
|
|
if (fSpyed)
|
|
return HEADER_OFFSET(pRequest);
|
|
|
|
return pRequest;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMallocSpy::PostGetSize
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
SIZE_T CMallocSpy::PostGetSize(SIZE_T cbActual, BOOL fSpyed)
|
|
{
|
|
if (fSpyed)
|
|
return cbActual - HEADERSIZE - FOOTERSIZE;
|
|
|
|
return cbActual;
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// void* CMallocSpy::PreDidAlloc
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void* CMallocSpy::PreDidAlloc(void* pRequest, BOOL fSpyed)
|
|
{
|
|
if (fSpyed)
|
|
return HEADER_OFFSET(pRequest);
|
|
|
|
return pRequest;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// BOOL CMallocSpy::PostDidAlloc
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL CMallocSpy::PostDidAlloc(void* pRequest, BOOL fSpyed, BOOL fActual)
|
|
{
|
|
return fActual;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// void CMallocSpy::PreHeapMinimize
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CMallocSpy::PreHeapMinimize()
|
|
{
|
|
// We don't do anything here
|
|
return;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// void CMallocSpy::PostHeapMinimize
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CMallocSpy::PostHeapMinimize()
|
|
{
|
|
// We don't do anything here
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CRTReportHook
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
#ifdef _DEBUG
|
|
_CRT_REPORT_HOOK g_fpPrevCRTReportHook = NULL;
|
|
int __cdecl CRTReportHook(INT nReportType, CHAR* pszMsg, INT* pReturnVal)
|
|
{
|
|
//Output
|
|
if(pReturnVal)
|
|
*pReturnVal = 0;
|
|
|
|
//If the user wants us to handle the ASSERTs...
|
|
if(TRUE)
|
|
{
|
|
//Determine what type of report this is...
|
|
switch(nReportType)
|
|
{
|
|
case _CRT_ASSERT: // - only defined for DEBUG
|
|
//Display the Assert
|
|
InternalTraceFmt(L"---------- C-Runtime Assert ----------" wWndEOL);
|
|
InternalTraceFmt(L"%S", pszMsg);
|
|
return TRUE;
|
|
|
|
case _CRT_ERROR: // - only defined for DEBUG
|
|
//Display the Error
|
|
InternalTraceFmt(L"---------- C-Runtime Error ----------" wWndEOL);
|
|
InternalTraceFmt(L"%S", pszMsg);
|
|
return TRUE;
|
|
|
|
default:
|
|
//There may be other reports or messages going to the C-runtime
|
|
//such as _CRT_WARN and _CRT_ERRCNT which we don't need to filter...
|
|
//CRT_WARN is used frequently by apps instead of OutputDebugString
|
|
break;
|
|
};
|
|
}
|
|
|
|
//If we have made it this far the ASSERT was not handled, so we should either call the previous
|
|
//installed CallBack (that we replaced if there was one) or return FALSE to the CRuntime to
|
|
//indicate we didn't handle this error, so do the normal processing for the error...
|
|
if(g_fpPrevCRTReportHook)
|
|
return g_fpPrevCRTReportHook(nReportType, pszMsg, pReturnVal);
|
|
return FALSE;
|
|
}
|
|
|
|
#endif //_DEBUG
|
|
|
|
void EnableCRTReportHook(BOOL fEnable)
|
|
{
|
|
#ifdef _DEBUG
|
|
if(fEnable)
|
|
{
|
|
if(!g_fpPrevCRTReportHook)
|
|
g_fpPrevCRTReportHook = _CrtSetReportHook(&CRTReportHook);
|
|
}
|
|
else
|
|
{
|
|
if(g_fpPrevCRTReportHook)
|
|
_CrtSetReportHook(g_fpPrevCRTReportHook);
|
|
g_fpPrevCRTReportHook = NULL;
|
|
}
|
|
#endif //_DEBUG
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CRTAllocHook
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef _DEBUG
|
|
//NOTE: The reason we have our own function pointer type is that in MSVC5.0
|
|
//the definition was "const char* filename", and in 6.0 they changed the debug definition to
|
|
//"const unsigned char* filename". So to compile with earlier versions we stick with the
|
|
//older definition and just cast away the "unsigned" ness...
|
|
typedef int (__cdecl * _CRT_ALLOC_HOOK_SIGNED)(int, void *, size_t, int, long, const char *, int);
|
|
|
|
_CRT_ALLOC_HOOK_SIGNED g_fpPrevCRTAllocHook = NULL;
|
|
int __cdecl CRTAllocHook(int allocType, void *userData, size_t size, int blockType,
|
|
long requestNumber, const /*unsigned*/ char *filename, int lineNumber)
|
|
{
|
|
//If the user wants us to handle the ASSERTs...
|
|
if(TRUE)
|
|
{
|
|
//Determine what type of Alloc this is...
|
|
switch(allocType)
|
|
{
|
|
case _HOOK_ALLOC: // - only defined for DEBUG
|
|
//Display the Alloc
|
|
InternalTraceFmt(L"TRACE - CRT Alloc - 0x%p, ID=%08lu, %Iu byte(s), File: %S, Line: %d\n", userData, requestNumber, size, filename, lineNumber);
|
|
return TRUE;
|
|
|
|
case _HOOK_REALLOC: // - only defined for DEBUG
|
|
//Display the ReAlloc
|
|
InternalTraceFmt(L"TRACE - CRT Realloc - 0x%p, ID=%08lu, %Iu byte(s), File: %S, Line: %d\n", userData, requestNumber, size, filename, lineNumber);
|
|
return TRUE;
|
|
|
|
case _HOOK_FREE: // - only defined for DEBUG
|
|
//Display the Free
|
|
InternalTraceFmt(L"TRACE - CRT Free - 0x%p, ID=%08lu, %Iu byte(s), File: %S, Line: %d\n", userData, requestNumber, size, filename, lineNumber);
|
|
return TRUE;
|
|
|
|
default:
|
|
//There may be other reports or messages going to the C-runtime
|
|
break;
|
|
};
|
|
}
|
|
|
|
//After the hook function has finished processing, it must return a Boolean value,
|
|
//which tells the main C run-time allocation process how to continue. When the hook function
|
|
//wants the main allocation process to continue as if the hook function had never been called,
|
|
//then the hook function should return TRUE.
|
|
if(g_fpPrevCRTAllocHook)
|
|
return g_fpPrevCRTAllocHook(allocType, userData, size, blockType, requestNumber, filename, lineNumber);
|
|
return TRUE;
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
void EnableCRTAllocHook(BOOL fEnable)
|
|
{
|
|
#ifdef _DEBUG
|
|
if(fEnable)
|
|
{
|
|
if(!g_fpPrevCRTAllocHook)
|
|
g_fpPrevCRTAllocHook = (_CRT_ALLOC_HOOK_SIGNED)_CrtSetAllocHook((_CRT_ALLOC_HOOK)&CRTAllocHook);
|
|
}
|
|
else
|
|
{
|
|
if(g_fpPrevCRTAllocHook)
|
|
_CrtSetAllocHook((_CRT_ALLOC_HOOK)g_fpPrevCRTAllocHook);
|
|
g_fpPrevCRTAllocHook = NULL;
|
|
}
|
|
#endif //_DEBUG
|
|
}
|
|
|
|
|