/* * MAPIDBG.C * * MAPI Debugging Utilities * * Copyright (C) 1986-1996 Microsoft Corporation. All rights reserved. */ #ifdef DEBUG #pragma warning(disable:4100) /* unreferenced formal parameter */ #pragma warning(disable:4127) /* conditional expression is constant */ #pragma warning(disable:4201) /* nameless struct/union */ #pragma warning(disable:4206) /* translation unit is empty */ #pragma warning(disable:4209) /* benign typedef redefinition */ #pragma warning(disable:4214) /* bit field types other than int */ #pragma warning(disable:4001) /* single line comments */ #pragma warning(disable:4050) /* different code attributes */ #ifdef _MAC #define INC_OLE2 #include #include #include #include #include #define GetPrivateProfileIntA MAPIGetPrivateProfileInt #elif defined(WIN16) || defined(_WIN32) #pragma warning(disable:4115) /* named type definition in parentheses */ #include #include #ifdef _WIN32 #pragma warning(disable:4001) /* single line comments */ #pragma warning(disable:4115) /* named type definition in parentheses */ #pragma warning (disable:4514) /* unreferenced inline function */ #include #endif #else #include void __far __pascal OutputDebugString(char __far *); #define wvsprintf vsprintf #define wsprintf sprintf #endif /* _MAC */ #ifdef DOS #define lstrcpyA strcpy #define lstrlenA strlen #define lstrcatA strcat #define wvsprintfA wvsprintf #define wsprintfA wsprintf #define OutputDebugStringA OutputDebugString #endif #include #include #include #include #include #include #include #ifdef _MAC #include #endif #if defined(DBCS) && defined(DOS) #include #endif #if defined(DEBUG) && defined(_WINNT) #include #include #endif /* Patch/Hack for 16bit, optimized builds. * * memcpy with a size of 0 bytes causes a * crash. */ #ifndef __MEMCPY_H_ #define __MEMCPY_H_ #if defined(WIN16) && !defined(DEBUG) #define MemCopy(_dst,_src,_cb) do \ { \ size_t __cb = (size_t)(_cb); \ if (__cb) \ memcpy(_dst,_src,__cb); \ } while (FALSE) #else #define MemCopy(_dst,_src,_cb) memcpy(_dst,_src,(size_t)(_cb)) #endif #endif #if (defined(WIN16) || defined(DOS)) && !defined(NO_BASED_DEBUG) #define BASED_DEBUG __based(__segname("DEBUG_DATA")) #else #define BASED_DEBUG #endif #if defined(WIN16) #define BASED_CODE __based(__segname("_CODE")) #else #define BASED_CODE #endif #if defined(WIN16) || defined(_WIN32) static BOOL fTraceEnabled = -1; static BOOL fUseEventLog = -1; static BOOL fAssertLeaks = -1; #if defined(_WIN32) && !defined(_MAC) BOOL fInhibitTrapThread = 2; #endif static char szKeyTraceEnabled[] = "DebugTrace"; static char szKeyInhibitTrapThread[] = "TrapOnSameThread"; static char szKeyEventLog[] = "EventLog"; static char szKeyUseVirtual[] = "VirtualMemory"; static char szKeyAssertLeaks[] = "AssertLeaks"; static char szKeyCheckOften[] = "CheckHeapOften"; static char szKeyFillRandom[] = "MemoryFillRandom"; static char szSectionDebug[] = "General"; static char szDebugIni[] = "MAPIDBG.INI"; #endif #ifndef VTABLE_FILL #ifdef _MAC #define VTABLE_FILL NULL, #else #define VTABLE_FILL #endif #endif #if defined(DEBUG) && defined(_WINNT) typedef BOOL (WINAPI *ReportEventFN)(HANDLE, WORD, WORD, DWORD, PSID, WORD, DWORD, LPCTSTR *, LPVOID); typedef HANDLE (WINAPI *RegisterEventSourceAFN)(LPCTSTR, LPCTSTR); ReportEventFN pfnReportEvent = NULL; RegisterEventSourceAFN pfnRegisterEventSourceA = NULL; #endif #ifdef WIN16 #pragma code_seg("Debug") #endif #if defined( _WINNT) /*++ Routine Description: This routine returns if the service specified is running interactively (not invoked \by the service controller). Arguments: None Return Value: BOOL - TRUE if the service is an EXE. Note: --*/ BOOL WINAPI IsDBGServiceAnExe( VOID ) { HANDLE hProcessToken = NULL; DWORD groupLength = 50; PTOKEN_GROUPS groupInfo = (PTOKEN_GROUPS)LocalAlloc(0, groupLength); SID_IDENTIFIER_AUTHORITY siaNt = SECURITY_NT_AUTHORITY; PSID InteractiveSid = NULL; PSID ServiceSid = NULL; DWORD i; // Start with assumption that process is an EXE, not a Service. BOOL fExe = TRUE; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken)) goto ret; if (groupInfo == NULL) goto ret; if (!GetTokenInformation(hProcessToken, TokenGroups, groupInfo, groupLength, &groupLength)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) goto ret; LocalFree(groupInfo); groupInfo = NULL; groupInfo = (PTOKEN_GROUPS)LocalAlloc(0, groupLength); if (groupInfo == NULL) goto ret; if (!GetTokenInformation(hProcessToken, TokenGroups, groupInfo, groupLength, &groupLength)) { goto ret; } } // // We now know the groups associated with this token. We want to look to see if // the interactive group is active in the token, and if so, we know that // this is an interactive process. // // We also look for the "service" SID, and if it's present, we know we're a service. // // The service SID will be present iff the service is running in a // user account (and was invoked by the service controller). // if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_INTERACTIVE_RID, 0, 0, 0, 0, 0, 0, 0, &InteractiveSid)) { goto ret; } if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, &ServiceSid)) { goto ret; } for (i = 0; i < groupInfo->GroupCount ; i += 1) { SID_AND_ATTRIBUTES sanda = groupInfo->Groups[i]; PSID Sid = sanda.Sid; // // Check to see if the group we're looking at is one of // the 2 groups we're interested in. // if (EqualSid(Sid, InteractiveSid)) { // // This process has the Interactive SID in its // token. This means that the process is running as // an EXE. // goto ret; } else if (EqualSid(Sid, ServiceSid)) { // // This process has the Service SID in its // token. This means that the process is running as // a service running in a user account. // fExe = FALSE; goto ret; } } // // Neither Interactive or Service was present in the current users token, // This implies that the process is running as a service, most likely // running as LocalSystem. // fExe = FALSE; ret: if (InteractiveSid) FreeSid(InteractiveSid); if (ServiceSid) FreeSid(ServiceSid); if (groupInfo) LocalFree(groupInfo); if (hProcessToken) CloseHandle(hProcessToken); return(fExe); } #endif /* LogIt */ #ifndef _MAC void LogIt(LPSTR plpcText, BOOL fUseAlert) { #if defined(DEBUG) && defined(_WINNT) LPSTR llpcStr[2]; static HANDLE hEventSource = NULL; if (pfnRegisterEventSourceA == NULL) { /* This handle is not important as the lib will be freed on exit (and it's debug only) */ HINSTANCE lhLib = LoadLibraryA("advapi32.dll"); if (!lhLib) return; pfnRegisterEventSourceA = (RegisterEventSourceAFN) GetProcAddress(lhLib, "RegisterEventSourceA"); pfnReportEvent = (ReportEventFN) GetProcAddress(lhLib, "ReportEventA"); if (!pfnRegisterEventSourceA || !pfnReportEvent) return; } if (!hEventSource) hEventSource = pfnRegisterEventSourceA(NULL, "MAPIDebug"); llpcStr[0] = "MAPI Debug Log"; llpcStr[1] = plpcText; pfnReportEvent(hEventSource, /* handle of event source */ EVENTLOG_ERROR_TYPE, /* event type */ 0, /* event category */ 0, /* event ID */ NULL, /* current user's SID */ 2, /* strings in lpszStrings */ 0, /* no bytes of raw data */ llpcStr, /* array of error strings */ NULL); /* no raw data */ /* Now we generate an Alert! */ /* This code is adapted from PierreC's stuff, and NEEDS TO BE UNICODE!!!! */ if (fUseAlert) { #define MAX_LINE 256 typedef NET_API_STATUS (WINAPI *NAREFN)(TCHAR *, ADMIN_OTHER_INFO *, ULONG, TCHAR *); BYTE rgb[sizeof(ADMIN_OTHER_INFO) + (sizeof(WCHAR) * MAX_LINE)]; ADMIN_OTHER_INFO * poi = (ADMIN_OTHER_INFO *) rgb; WCHAR * pch = (WCHAR *) (rgb + sizeof(ADMIN_OTHER_INFO)); NET_API_STATUS nas; static NAREFN fnNetAlertRaiseEx = NULL; /* Resolve function here, never free library as it's debug only */ if (!fnNetAlertRaiseEx) { HINSTANCE lhLib = LoadLibrary("NETAPI32.DLL"); if (lhLib) fnNetAlertRaiseEx = (NAREFN) GetProcAddress(lhLib, "NetAlertRaiseEx"); } if (fnNetAlertRaiseEx) { poi->alrtad_errcode = (DWORD) -1; poi->alrtad_numstrings = 1; if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plpcText, -1, pch, MAX_LINE)) { nas = fnNetAlertRaiseEx( (TCHAR *) L"ADMIN", poi, sizeof(ADMIN_OTHER_INFO) + ((lstrlenW(pch) + 1) * sizeof(WCHAR)), (TCHAR *) L"MAPI Assert"); } } } #endif /* DEBUG && NT */ } #endif /* !_MAC */ /* DebugOutputFn ------------------------------------------------------------ */ char BASED_CODE szCR[] = "\r"; void DebugOutputFn(char *psz) { #if defined(_MAC) OutputDebugString(psz); #else #if defined(WIN16) || defined(_WIN32) if (fTraceEnabled == -1) { fTraceEnabled = GetPrivateProfileIntA(szSectionDebug, szKeyTraceEnabled, 0, szDebugIni); fUseEventLog = GetPrivateProfileIntA(szSectionDebug, szKeyEventLog, 0, szDebugIni); } if (!fTraceEnabled) return; if (fUseEventLog) #else if (FALSE) #endif LogIt(psz, FALSE); #ifdef WIN16 OutputDebugString(psz); OutputDebugString(szCR); #else OutputDebugStringA(psz); OutputDebugStringA(szCR); #endif #endif /* _MAC */ } /* DebugTrapFn -------------------------------------------------------------- */ #if defined(_WIN32) && !defined(_MAC) typedef struct { char * sz1; char * sz2; UINT rgf; int iResult; } MBContext; DWORD WINAPI MessageBoxFnThreadMain(MBContext *pmbc) { if (fUseEventLog) { LogIt(pmbc->sz1, TRUE); pmbc->iResult = IDIGNORE; } else pmbc->iResult = MessageBoxA(NULL, pmbc->sz1, pmbc->sz2, pmbc->rgf | MB_SETFOREGROUND); return(0); } int MessageBoxFn(char *sz1, char *sz2, UINT rgf) { HANDLE hThread; DWORD dwThreadId; MBContext mbc; mbc.sz1 = sz1; mbc.sz2 = sz2; mbc.rgf = rgf; mbc.iResult = IDRETRY; #if defined(_WIN32) && !defined(_MAC) if (fInhibitTrapThread == 2) fInhibitTrapThread = GetPrivateProfileIntA(szSectionDebug, szKeyInhibitTrapThread, 0, szDebugIni); #endif if (fInhibitTrapThread) { MessageBoxFnThreadMain(&mbc); } else { hThread = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)MessageBoxFnThreadMain, &mbc, 0, &dwThreadId); if (hThread != NULL) { WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); } } return(mbc.iResult); } #else #define MessageBoxFn(sz1, sz2, rgf) MessageBoxA(NULL, sz1, sz2, rgf) #endif int EXPORTDBG __cdecl DebugTrapFn(int fFatal, char *pszFile, int iLine, char *pszFormat, ...) { char sz[512]; va_list vl; #if defined(WIN16) || defined(_WIN32) int id; #endif #if defined(_WIN32) && !defined(_MAC) static int iServiceFlag = -1; #endif lstrcpyA(sz, "++++ MAPI Debug Trap ("); _strdate(sz + lstrlenA(sz)); lstrcatA(sz, " "); _strtime(sz + lstrlenA(sz)); lstrcatA(sz, ")\n"); DebugOutputFn(sz); va_start(vl, pszFormat); wvsprintfA(sz, pszFormat, vl); va_end(vl); wsprintfA(sz + lstrlenA(sz), "\n[File %s, Line %d]\n\n", pszFile, iLine); DebugOutputFn(sz); #if defined(DOS) _asm { int 3 } #endif #if defined(WIN16) || defined(_WIN32) /* Hold down control key to prevent MessageBox */ if ( GetAsyncKeyState(VK_CONTROL) >= 0 ) { UINT uiFlags = MB_ABORTRETRYIGNORE; if (fFatal) uiFlags |= MB_DEFBUTTON1; else uiFlags |= MB_DEFBUTTON3; #ifdef WIN16 uiFlags |= MB_ICONEXCLAMATION | MB_SYSTEMMODAL; #else uiFlags |= MB_ICONSTOP | MB_TASKMODAL; #endif #if defined(_WIN32) && !defined(_MAC) if (iServiceFlag == -1) { DWORD dwVersion = GetVersion(); if (dwVersion & 0x80000000) { if (LOBYTE(LOWORD(dwVersion)) < 4) { // NT 3.51 iServiceFlag = 0x00040000; } else { // NT 4.0+ iServiceFlag = 0x00200000; } } else // not NT, skip this iServiceFlag = 0; } if (!IsDBGServiceAnExe()) uiFlags |= (UINT) iServiceFlag; #endif id = MessageBoxFn(sz, "MAPI Debug Trap", uiFlags); if (id == IDABORT) *((LPBYTE)NULL) = 0; else if (id == IDRETRY) DebugBreak(); } #endif return(0); } /* DebugTraceFn ------------------------------------------------------------- */ int EXPORTDBG __cdecl DebugTraceFn(char *pszFormat, ...) { char sz[768]; int fAutoLF = 0; va_list vl; if (*pszFormat == '~') { pszFormat += 1; fAutoLF = 1; } va_start(vl, pszFormat); wvsprintfA(sz, pszFormat, vl); va_end(vl); #ifndef _MAC if (fAutoLF) lstrcatA(sz, "\n"); #endif DebugOutputFn(sz); return(0); } /* DebugTraceProblemsFn */ void EXPORTDBG __cdecl DebugTraceProblemsFn(LPSTR sz, LPVOID pv) { LPSPropProblemArray pprobs = (LPSPropProblemArray)pv; SPropProblem * pprob = pprobs->aProblem; int cprob = (int)pprobs->cProblem; DebugTraceFn("%s: SetProps problem\n", sz); while (cprob--) { DebugTraceFn("Property %s (index %ld): failed with %s\n", SzDecodeUlPropTagFn(pprob->ulPropTag), pprob->ulIndex, SzDecodeScodeFn(pprob->scode)); } } /* SCODE & PropTag decoding ------------------------------------------------- */ typedef struct { char * psz; unsigned long ulPropTag; } PT; typedef struct { char * psz; SCODE sc; } SC; #define Pt(_ptag) {#_ptag, _ptag} #define Sc(_sc) {#_sc, _sc} #if !defined(DOS) static PT BASED_DEBUG rgpt[] = { #include "_tags.h" /* * Property types */ Pt(PR_NULL), Pt(PT_UNSPECIFIED), Pt(PT_NULL), Pt(PT_I2), Pt(PT_LONG), Pt(PT_R4), Pt(PT_DOUBLE), Pt(PT_CURRENCY), Pt(PT_APPTIME), Pt(PT_ERROR), Pt(PT_BOOLEAN), Pt(PT_OBJECT), Pt(PT_I8), Pt(PT_STRING8), Pt(PT_UNICODE), Pt(PT_SYSTIME), Pt(PT_CLSID), Pt(PT_BINARY), Pt(PT_TSTRING), Pt(PT_MV_I2), Pt(PT_MV_LONG), Pt(PT_MV_R4), Pt(PT_MV_DOUBLE), Pt(PT_MV_CURRENCY), Pt(PT_MV_APPTIME), Pt(PT_MV_SYSTIME), Pt(PT_MV_STRING8), Pt(PT_MV_BINARY), Pt(PT_MV_UNICODE), Pt(PT_MV_CLSID), Pt(PT_MV_I8) }; #define cpt (sizeof(rgpt) / sizeof(PT)) static SC BASED_DEBUG rgsc[] = { /* FACILITY_NULL error codes from OLE */ Sc(S_OK), Sc(S_FALSE), Sc(E_UNEXPECTED), Sc(E_NOTIMPL), Sc(E_OUTOFMEMORY), Sc(E_INVALIDARG), Sc(E_NOINTERFACE), Sc(E_POINTER), Sc(E_HANDLE), Sc(E_ABORT), Sc(E_FAIL), Sc(E_ACCESSDENIED), /* MAPI error codes from MAPICODE.H */ #include "_scode.h" }; #define csc (sizeof(rgsc) / sizeof(SC)) #endif char * EXPORTDBG __cdecl SzDecodeScodeFn(SCODE sc) { static char rgch[64]; #if !defined(DOS) int isc; for (isc = 0; isc < csc; ++isc) if (sc == rgsc[isc].sc) return rgsc[isc].psz; #endif wsprintfA (rgch, "%08lX", sc); return rgch; } char * EXPORTDBG __cdecl SzDecodeUlPropTypeFn(unsigned long ulPropType) { static char rgch[8]; switch (ulPropType) { case PT_UNSPECIFIED: return("PT_UNSPECIFIED"); break; case PT_NULL: return("PT_NULL"); break; case PT_I2: return("PT_I2"); break; case PT_LONG: return("PT_LONG"); break; case PT_R4: return("PT_R4"); break; case PT_DOUBLE: return("PT_DOUBLE"); break; case PT_CURRENCY: return("PT_CURRENCY"); break; case PT_APPTIME: return("PT_APPTIME"); break; case PT_ERROR: return("PT_ERROR"); break; case PT_BOOLEAN: return("PT_BOOLEAN"); break; case PT_OBJECT: return("PT_OBJECT"); break; case PT_I8: return("PT_I8"); break; case PT_STRING8: return("PT_STRING8"); break; case PT_UNICODE: return("PT_UNICODE"); break; case PT_SYSTIME: return("PT_SYSTIME"); break; case PT_CLSID: return("PT_CLSID"); break; case PT_BINARY: return("PT_BINARY"); break; } wsprintfA(rgch, "0x%04lX", ulPropType); return rgch; } char * EXPORTDBG __cdecl SzDecodeUlPropTagFn(unsigned long ulPropTag) { static char rgch[64]; #if !defined(DOS) int ipt; for (ipt = 0; ipt < cpt; ++ipt) if (ulPropTag == rgpt[ipt].ulPropTag) return rgpt[ipt].psz; #endif wsprintfA(rgch, "PROP_TAG(%s, 0x%04lX)", SzDecodeUlPropType(PROP_TYPE(ulPropTag)), PROP_ID(ulPropTag)); return rgch; } SCODE EXPORTDBG __cdecl ScodeFromSzFn(char *psz) { #if !defined(DOS) int isc; for (isc = 0; isc < csc; ++isc) { if (lstrcmpA(psz, rgsc[isc].psz) == 0) { return rgsc[isc].sc; } } #endif return 0; } unsigned long EXPORTDBG __cdecl UlPropTagFromSzFn(char *psz) { #if !defined(DOS) int ipt; for (ipt = 0; ipt < cpt; ++ipt) { if (lstrcmpA(psz, rgpt[ipt].psz) == 0) { return rgpt[ipt].ulPropTag; } } #endif return 0; } /* ScCheckScFn -------------------------------------------------------------- */ #if !defined(DOS) SCODE EXPORTDBG __cdecl ScCheckScFn( SCODE sc, SCODE * lpscLegal, char * lpszMethod, char * lpszFile, int iLine) { BOOL fIsQueryInterface = (lpscLegal == IUnknown_QueryInterface_Scodes); if (sc == S_OK) return(sc); while( *lpscLegal != S_OK && sc != *lpscLegal ) { lpscLegal++; } if ( *lpscLegal == S_OK ) { SCODE *lpscNextCommon = Common_Scodes; /* see if this is a common scode */ if ( !fIsQueryInterface ) while( *lpscNextCommon != S_OK && sc != *lpscNextCommon ) { lpscNextCommon++; } /* this is an illegal error or an RPC error */ if ( (*lpscNextCommon == S_OK || fIsQueryInterface) && ( SCODE_FACILITY(sc) != FACILITY_RPC) ) { DebugTrace( "Unrecognized scode %s from %s\n\t in file %s line %d\n", SzDecodeScode( sc ), lpszMethod, lpszFile, iLine); } } return(sc); } #endif /* SCODE lists -------------------------------------------------------------- */ #if !defined(DOS) #define STANDARD_OPENENTRY_SCODES \ E_NOINTERFACE, \ MAPI_E_NOT_FOUND SCODE BASED_DEBUG Common_Scodes[] = { MAPI_E_BAD_CHARWIDTH, MAPI_E_CALL_FAILED, MAPI_E_INVALID_ENTRYID, MAPI_E_INVALID_OBJECT, MAPI_E_INVALID_PARAMETER, MAPI_E_NO_ACCESS, MAPI_E_NO_SUPPORT, MAPI_E_NOT_ENOUGH_MEMORY, MAPI_E_UNKNOWN_FLAGS, S_OK }; SCODE BASED_DEBUG MAPILogon_Scodes[] = { MAPI_E_NOT_INITIALIZED, MAPI_E_LOGON_FAILED, S_OK }; SCODE BASED_DEBUG MAPIAllocateBuffer_Scodes[] = { MAPI_E_NOT_INITIALIZED, S_OK }; SCODE BASED_DEBUG MAPIAllocateMore_Scodes[] = { MAPI_E_NOT_INITIALIZED, S_OK }; SCODE BASED_DEBUG MAPIFreeBuffer_Scodes[] = { S_OK }; SCODE BASED_DEBUG IUnknown_QueryInterface_Scodes[] = { E_INVALIDARG, E_NOINTERFACE, S_OK }; SCODE BASED_DEBUG IUnknown_GetLastError_Scodes[] = { MAPI_E_EXTENDED_ERROR, S_OK }; SCODE BASED_DEBUG IMAPIProp_CopyTo_Scodes[] = { MAPI_W_ERRORS_RETURNED, MAPI_E_INVALID_TYPE, MAPI_E_FOLDER_CYCLE, MAPI_E_DECLINE_COPY, E_NOINTERFACE, S_OK }; SCODE BASED_DEBUG IMAPIProp_CopyProps_Scodes[] = { MAPI_W_ERRORS_RETURNED, MAPI_W_PARTIAL_COMPLETION, MAPI_E_INVALID_TYPE, MAPI_E_FOLDER_CYCLE, MAPI_E_DECLINE_COPY, E_NOINTERFACE, S_OK }; SCODE BASED_DEBUG IMAPIProp_DeleteProps_Scodes[] = { MAPI_W_ERRORS_RETURNED, MAPI_E_INVALID_TYPE, S_OK }; SCODE BASED_DEBUG IMAPIProp_GetIDsFromNames_Scodes[] = { MAPI_W_ERRORS_RETURNED, MAPI_E_TABLE_TOO_BIG, S_OK }; SCODE BASED_DEBUG IMAPIProp_GetLastError_Scodes[] = { MAPI_E_EXTENDED_ERROR, S_OK }; SCODE BASED_DEBUG IMAPIProp_GetNamesFromIDs_Scodes[] = { MAPI_W_ERRORS_RETURNED, S_OK }; SCODE BASED_DEBUG IMAPIProp_GetPropList_Scodes[] = { MAPI_W_ERRORS_RETURNED, S_OK }; SCODE BASED_DEBUG IMAPIProp_GetProps_Scodes[] = { MAPI_E_NOT_FOUND, MAPI_E_OBJECT_DELETED, MAPI_W_ERRORS_RETURNED, S_OK }; SCODE BASED_DEBUG IMAPIProp_OpenProperty_Scodes[] = { MAPI_E_INTERFACE_NOT_SUPPORTED, MAPI_E_NOT_FOUND, MAPI_E_OBJECT_DELETED, S_OK }; SCODE BASED_DEBUG IMAPIProp_SetProps_Scodes[] = { MAPI_E_COMPUTED, MAPI_E_UNEXPECTED_TYPE, MAPI_E_INVALID_TYPE, S_OK }; SCODE BASED_DEBUG IMAPIProp_SaveChanges_Scodes[] = { MAPI_E_NOT_ENOUGH_DISK, MAPI_E_OBJECT_CHANGED, MAPI_E_OBJECT_DELETED, S_OK }; SCODE BASED_DEBUG IStream_Read_Scodes[] = {S_OK}; SCODE BASED_DEBUG IStream_Write_Scodes[] = {S_OK}; SCODE BASED_DEBUG IStream_Seek_Scodes[] = {S_OK}; SCODE BASED_DEBUG IStream_SetSize_Scodes[] = {S_OK}; SCODE BASED_DEBUG IStream_Tell_Scodes[] = {S_OK}; SCODE BASED_DEBUG IStream_LockRegion_Scodes[] = {S_OK}; SCODE BASED_DEBUG IStream_UnlockRegion_Scodes[] = {S_OK}; SCODE BASED_DEBUG IStream_Clone_Scodes[] = {S_OK}; SCODE BASED_DEBUG IStream_CopyTo_Scodes[] = {S_OK}; SCODE BASED_DEBUG IStream_Revert_Scodes[] = {S_OK}; SCODE BASED_DEBUG IStream_Stat_Scodes[] = {S_OK}; SCODE BASED_DEBUG IStream_Commit_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPITable_GetLastError_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPITable_Advise_Scodes[] = { S_OK }; SCODE BASED_DEBUG IMAPITable_Unadvise_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPITable_GetStatus_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPITable_SetColumns_Scodes[] = { MAPI_E_BUSY, S_OK }; SCODE BASED_DEBUG IMAPITable_QueryColumns_Scodes[] = { MAPI_E_BUSY, S_OK }; SCODE BASED_DEBUG IMAPITable_GetRowCount_Scodes[] = { MAPI_E_BUSY, MAPI_W_APPROX_COUNT, S_OK }; SCODE BASED_DEBUG IMAPITable_SeekRow_Scodes[] = { MAPI_E_INVALID_BOOKMARK, MAPI_E_UNABLE_TO_COMPLETE, MAPI_W_POSITION_CHANGED, S_OK }; SCODE BASED_DEBUG IMAPITable_SeekRowApprox_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPITable_QueryPosition_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPITable_FindRow_Scodes[] = { MAPI_E_INVALID_BOOKMARK, MAPI_E_NOT_FOUND, MAPI_W_POSITION_CHANGED, S_OK }; SCODE BASED_DEBUG IMAPITable_Restrict_Scodes[] = { MAPI_E_BUSY, S_OK }; SCODE BASED_DEBUG IMAPITable_CreateBookmark_Scodes[] = { MAPI_E_UNABLE_TO_COMPLETE, S_OK }; SCODE BASED_DEBUG IMAPITable_FreeBookmark_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPITable_SortTable_Scodes[] = { MAPI_E_TOO_COMPLEX, S_OK }; SCODE BASED_DEBUG IMAPITable_QuerySortOrder_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPITable_QueryRows_Scodes[] = { MAPI_E_INVALID_BOOKMARK, MAPI_W_POSITION_CHANGED, S_OK }; SCODE BASED_DEBUG IMAPITable_Abort_Scodes[] = { MAPI_E_UNABLE_TO_ABORT, S_OK }; SCODE BASED_DEBUG IMAPITable_ExpandRow_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPITable_CollapseRow_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPITable_WaitForCompletion_Scodes[] = { MAPI_E_TIMEOUT, S_OK }; SCODE BASED_DEBUG IMAPITable_GetCollapseState_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPITable_SetCollapseState_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_LogOff_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_Release_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_GetLastError_Scodes[] = { MAPI_E_EXTENDED_ERROR, S_OK }; SCODE BASED_DEBUG IMAPISession_GetMsgStoresTable_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_GetStatusTable_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_OpenMsgStore_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_OpenAddressBook_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_OpenEntry_Scodes[] = { STANDARD_OPENENTRY_SCODES, S_OK }; SCODE BASED_DEBUG IMAPISession_OpenProfileSection_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_Advise_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_Unadvise_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_CompareEntryIDs_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_MessageOptions_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_QueryDefaultMessageOpt_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_EnumAdrTypes_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPISession_QueryIdentity_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMsgStore_OpenEntry_Scodes[] = { STANDARD_OPENENTRY_SCODES, MAPI_E_SUBMITTED, S_OK }; SCODE BASED_DEBUG IMsgStore_SetReceiveFolder_Scodes[] = { MAPI_E_BAD_CHARWIDTH, MAPI_E_NOT_FOUND, S_OK }; SCODE BASED_DEBUG IMsgStore_GetReceiveFolder_Scodes[] = { MAPI_E_BAD_CHARWIDTH, S_OK }; SCODE BASED_DEBUG IMsgStore_GetReceiveFolderTable_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMsgStore_StoreLogoff_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMsgStore_Advise_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMsgStore_Unadvise_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMsgStore_CompareEntryIDs_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMsgStore_GetOutgoingQueue_Scodes[] = { MAPI_E_NO_SUPPORT, S_OK}; SCODE BASED_DEBUG IMsgStore_SetLockState_Scodes[] = { MAPI_E_NO_SUPPORT, MAPI_E_NOT_FOUND, S_OK}; SCODE BASED_DEBUG IMsgStore_FinishedMsg_Scodes[] = { MAPI_E_NO_SUPPORT, S_OK}; SCODE BASED_DEBUG IMsgStore_AbortSubmit_Scodes[] = { MAPI_E_UNABLE_TO_ABORT, MAPI_E_NOT_IN_QUEUE, S_OK}; SCODE BASED_DEBUG IMsgStore_NotifyNewMail_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPIFolder_GetContentsTable_Scodes[] = { MAPI_E_OBJECT_DELETED, S_OK }; SCODE BASED_DEBUG IMAPIFolder_GetHierarchyTable_Scodes[] = { MAPI_E_OBJECT_DELETED, S_OK }; SCODE BASED_DEBUG IMAPIFolder_SaveContentsSort_Scodes[] = { S_OK }; SCODE BASED_DEBUG IMAPIFolder_OpenEntry_Scodes[] = { STANDARD_OPENENTRY_SCODES, MAPI_E_SUBMITTED, S_OK }; SCODE BASED_DEBUG IMAPIFolder_CreateMessage_Scodes[] = { E_NOINTERFACE, S_OK }; SCODE BASED_DEBUG IMAPIFolder_CopyMessages_Scodes[] = { E_NOINTERFACE, MAPI_E_SUBMITTED, MAPI_E_DECLINE_COPY, S_OK }; SCODE BASED_DEBUG IMAPIFolder_DeleteMessages_Scodes[] = { MAPI_E_SUBMITTED, S_OK }; SCODE BASED_DEBUG IMAPIFolder_CreateFolder_Scodes[] = { E_NOINTERFACE, MAPI_E_COLLISION, S_OK }; SCODE BASED_DEBUG IMAPIFolder_CopyFolder_Scodes[] = { E_NOINTERFACE, MAPI_E_COLLISION, MAPI_E_FOLDER_CYCLE, MAPI_E_DECLINE_COPY, S_OK }; SCODE BASED_DEBUG IMAPIFolder_DeleteFolder_Scodes[] = { MAPI_E_HAS_FOLDERS, MAPI_E_HAS_MESSAGES, MAPI_E_SUBMITTED, S_OK }; SCODE BASED_DEBUG IMAPIFolder_SetSearchCriteria_Scodes[] = { S_OK }; SCODE BASED_DEBUG IMAPIFolder_GetSearchCriteria_Scodes[] = { MAPI_E_NOT_INITIALIZED, MAPI_E_CORRUPT_STORE, S_OK }; SCODE BASED_DEBUG IMAPIFolder_SetReadFlags_Scodes[] = { S_OK }; SCODE BASED_DEBUG IMAPIFolder_GetMessageStatus_Scodes[] = { S_OK }; SCODE BASED_DEBUG IMAPIFolder_SetMessageStatus_Scodes[] = { S_OK }; SCODE BASED_DEBUG IMAPIFolder_EmptyFolder_Scodes[] = { MAPI_E_SUBMITTED, S_OK }; SCODE BASED_DEBUG IMessage_GetAttachmentTable_Scodes[] = { S_OK }; SCODE BASED_DEBUG IMessage_OpenAttach_Scodes[] = { MAPI_E_NOT_FOUND, E_NOINTERFACE, S_OK }; SCODE BASED_DEBUG IMessage_CreateAttach_Scodes[] = { E_NOINTERFACE, S_OK }; SCODE BASED_DEBUG IMessage_DeleteAttach_Scodes[] = { S_OK }; SCODE BASED_DEBUG IMessage_GetRecipientTable_Scodes[] = { S_OK }; SCODE BASED_DEBUG IMessage_ModifyRecipients_Scodes[] = { MAPI_E_NOT_FOUND, S_OK }; SCODE BASED_DEBUG IMessage_SubmitMessage_Scodes[] = { MAPI_E_NO_RECIPIENTS, MAPI_E_NON_STANDARD, S_OK }; SCODE BASED_DEBUG IMessage_SetReadFlag_Scodes[] = { S_OK }; SCODE BASED_DEBUG IAttach_SaveChanges_Scodes[] = { S_OK }; SCODE BASED_DEBUG IAddrBook_OpenEntry_Scodes[] = { STANDARD_OPENENTRY_SCODES, S_OK }; SCODE BASED_DEBUG IAddrBook_CompareEntryIDs_Scodes[] = {S_OK}; SCODE BASED_DEBUG IAddrBook_CreateOneOff_Scodes[] = {S_OK}; SCODE BASED_DEBUG IAddrBook_ResolveName_Scodes[] = {S_OK}; SCODE BASED_DEBUG IAddrBook_Address_Scodes[] = {S_OK}; SCODE BASED_DEBUG IAddrBook_Details_Scodes[] = {S_OK}; SCODE BASED_DEBUG IAddrBook_RecipOptions_Scodes[] = {S_OK}; SCODE BASED_DEBUG IAddrBook_QueryDefaultRecipOpt_Scodes[] = {S_OK}; SCODE BASED_DEBUG IAddrBook_ButtonPress_Scodes[] = {S_OK}; SCODE BASED_DEBUG IABContainer_GetContentsTable_Scodes[] = {S_OK}; SCODE BASED_DEBUG IABContainer_GetHierarchyTable_Scodes[] = {S_OK}; SCODE BASED_DEBUG INotifObj_ChangeEvMask_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPIStatus_ChangePassword_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPIStatus_FlushQueues_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPIStatus_SettingsDialog_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMAPIStatus_ValidateState_Scodes[] = {S_OK}; SCODE BASED_DEBUG SMAPI_MAPILogon_Scodes[] = { MAPI_E_LOGON_FAILED, S_OK}; SCODE BASED_DEBUG SMAPI_MAPILogoff_Scodes[] = {S_OK}; SCODE BASED_DEBUG SMAPI_MAPIFreeBuffer_Scodes[] = {S_OK}; SCODE BASED_DEBUG SMAPI_MAPISendMail_Scodes[] = {S_OK}; SCODE BASED_DEBUG SMAPI_MAPISendDocuments_Scodes[] = {S_OK}; SCODE BASED_DEBUG SMAPI_MAPIFindNext_Scodes[] = {S_OK}; SCODE BASED_DEBUG SMAPI_MAPIReadMail_Scodes[] = {S_OK}; SCODE BASED_DEBUG SMAPI_MAPISaveMail_Scodes[] = {S_OK}; SCODE BASED_DEBUG SMAPI_MAPIDeleteMail_Scodes[] = {S_OK}; SCODE BASED_DEBUG SMAPI_MAPIAddress_Scodes[] = {S_OK}; SCODE BASED_DEBUG SMAPI_MAPIResolveName_Scodes[] = {S_OK}; SCODE BASED_DEBUG SMAPI_MAPIDetails_Scodes[] = {S_OK}; SCODE BASED_DEBUG IMSProvider_Logon_Scodes[] = { MAPI_E_UNCONFIGURED, MAPI_E_FAILONEPROVIDER, MAPI_E_STRING_TOO_LONG, MAPI_E_LOGON_FAILED, MAPI_E_CORRUPT_STORE, MAPI_E_USER_CANCEL, S_OK}; SCODE BASED_DEBUG IMSProvider_Deinit_Scodes[] = { S_OK}; SCODE BASED_DEBUG IMSProvider_Shutdown_Scodes[] = { S_OK}; SCODE BASED_DEBUG IMSProvider_Init_Scodes[] = { MAPI_E_VERSION, S_OK}; SCODE BASED_DEBUG IMSProvider_SpoolerLogon_Scodes[] = { MAPI_E_LOGON_FAILED, S_OK}; SCODE BASED_DEBUG IMSLogon_OpenEntry_Scodes[] = { STANDARD_OPENENTRY_SCODES, S_OK }; SCODE BASED_DEBUG IMSLogon_OpenStatusEntry_Scodes[] = { S_OK}; SCODE BASED_DEBUG IMSLogon_CompareEntryIDs_Scodes[] = { S_OK}; SCODE BASED_DEBUG IMSLogon_Advise_Scodes[] = { S_OK}; SCODE BASED_DEBUG IMSLogon_Unadvise_Scodes[] = { S_OK}; SCODE BASED_DEBUG IMSLogon_Logoff_Scodes[] = { S_OK}; #endif /* DBGMEM ------------------------------------------------------------------- */ #undef INTERFACE #define INTERFACE struct _DBGMEM DECLARE_INTERFACE(DBGMEM_) { BEGIN_INTERFACE STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE; \ STDMETHOD_(ULONG,AddRef) (THIS) PURE; \ STDMETHOD_(ULONG,Release) (THIS) PURE; \ STDMETHOD_(void FAR*, Alloc) (THIS_ ULONG cb) PURE; \ STDMETHOD_(void FAR*, Realloc) (THIS_ void FAR* pv, ULONG cb) PURE; \ STDMETHOD_(void, Free) (THIS_ void FAR* pv) PURE; \ STDMETHOD_(ULONG, GetSize) (THIS_ void FAR* pv) PURE; \ STDMETHOD_(int, DidAlloc) (THIS_ void FAR* pv) PURE; \ STDMETHOD_(void, HeapMinimize) (THIS) PURE; \ }; extern DBGMEM_Vtbl vtblDBGMEM; typedef struct _DBGMEM DBGMEM, FAR *PDBGMEM; typedef struct _BLK BLK, *PBLK; typedef struct _BLK UNALIGNED * PUABLK; typedef struct _BLKTAIL BLKTAIL, *PBLKTAIL; struct _DBGMEM { DBGMEM_Vtbl * lpVtbl; ULONG cRef; LPMALLOC pmalloc; char szSubsys[16]; ULONG ulAllocNum; ULONG ulAllocAt; ULONG ulFailureAt; BOOL fCheckOften; BOOL fUnleakable; ULONG cbVirtual; BOOL fFillRandom; int cbExtra; int cbTail; PBLK pblkHead; #if defined(_WIN32) && defined(_X86_) CRITICAL_SECTION cs; #endif }; #define NCALLERS 12 struct _BLK { PDBGMEM pdbgmem; /* pointer to the allocator */ PBLK pblkNext; /* next link in chain of allocated blocks */ PBLK pblkPrev; /* prev link in chain of allocated blocks */ ULONG ulAllocNum; /* internal allocation number */ BOOL fUnleakable; /* TRUE if leak code should ignore block */ #if defined(_WIN32) && defined(_X86_) FARPROC pfnCallers[NCALLERS]; #endif PBLKTAIL pblktail; /* pointer to block tail */ }; struct _BLKTAIL { PBLK pblk; /* pointer back to beginning of the block */ }; #define PblkToPv(pblk) ((LPVOID)((PBLK)(pblk) + 1)) #define PvToPblk(pblk) ((PBLK)(pv) - 1) #define PblkClientSize(pblk) ((ULONG)((char *)(pblk)->pblktail - (char *)PblkToPv(pblk))) #define PblkAllocSize(pblk) (PblkClientSize(pblk) + sizeof(BLK) + (pblk)->pdbgmem->cbTail) #if defined(_WIN32) && defined(_X86_) #define DBGMEM_EnterCriticalSection(pdbgmem) \ EnterCriticalSection(&(pdbgmem)->cs) #define DBGMEM_LeaveCriticalSection(pdbgmem) \ LeaveCriticalSection(&(pdbgmem)->cs) #else #define DBGMEM_EnterCriticalSection(pdbgmem) #define DBGMEM_LeaveCriticalSection(pdbgmem) #endif #define INITGUID #include DEFINE_OLEGUID(DBGMEM_IID_IUnknown, 0x00000000L, 0, 0); DEFINE_OLEGUID(DBGMEM_IID_IMalloc, 0x00000002L, 0, 0); DEFINE_OLEGUID(DBGMEM_IID_IBaseMalloc, 0x000203FFL, 0, 0); /* Forward Declarations ----------------------------------------------------- */ BOOL DBGMEM_ValidatePblk(PDBGMEM pdbgmem, PBLK pblk, char ** pszReason); BOOL DBGMEM_ValidatePv(PDBGMEM pdbgmem, void * pv, char * pszFunc); STDMETHODIMP_(void) DBGMEM_Free(PDBGMEM pdbgmem, void * pv); /* Call Stack (_WIN32) ------------------------------------------------------- */ #if defined(_WIN32) && defined(_X86_) #ifdef _WIN95 #define dwStackLimit 0x00400000 /* 4MB for Windows 95 */ #else #define dwStackLimit 0x00010000 /* 64KB for NT */ #endif void EXPORTDBG __cdecl GetCallStack(DWORD *pdwCaller, int cSkip, int cFind) { DWORD * pdwStack; DWORD * pdwStackPrev = (DWORD *)0; DWORD dwCaller; __asm mov pdwStack, ebp memset(pdwCaller, 0, cFind * sizeof(DWORD)); while (cSkip + cFind > 0) { pdwStack = (DWORD *)*pdwStack; if ( pdwStack <= (DWORD *)dwStackLimit || pdwStackPrev >= pdwStack || IsBadReadPtr(pdwStack, 2 * sizeof(DWORD))) break; dwCaller = *(pdwStack + 1); if (dwCaller <= dwStackLimit) break; else if (cSkip > 0) cSkip -= 1; else { *pdwCaller++ = dwCaller; cFind -= 1; pdwStackPrev = pdwStack; } } } #endif /* Virtual Memory Support (_WIN32) ------------------------------------------- */ #if defined(_WIN32) && (defined(_X86_) || defined(_PPC_) || defined(_MIPS_)) #define PAGE_SIZE 4096 #define PvToVMBase(pv) ((void *)((ULONG)pv & 0xFFFF0000)) BOOL VMValidatePvEx(void *pv, ULONG cbCluster) { void * pvBase; BYTE * pb; pvBase = PvToVMBase(pv); pb = (BYTE *)pvBase + sizeof(ULONG); while (pb < (BYTE *)pv) { if (*pb++ != 0xAD) { TrapSz1("VMValidatePvEx(pv=%08lX): Block leader has been overwritten", pv); return(FALSE); } } if (cbCluster != 1) { ULONG cb = *((ULONG *)pvBase); ULONG cbPad = 0; if (cb % cbCluster) cbPad = (cbCluster - (cb % cbCluster)); if (cbPad) { BYTE *pbMac; pb = (BYTE *)pv + cb; pbMac = pb + cbPad; while (pb < pbMac) { if (*pb++ != 0xBC) { TrapSz1("VMValidatePvEx(pv=%08lX): Block trailer has been " "overwritten", pv); return(FALSE); } } } } return(TRUE); } void * EXPORTDBG __cdecl VMAlloc(ULONG cb) { return VMAllocEx(cb, 1); } void * EXPORTDBG __cdecl VMAllocEx(ULONG cb, ULONG cbCluster) { ULONG cbAlloc; void * pvR; void * pvC; ULONG cbPad = 0; // a cluster size of 0 means don't use the virtual allocator. AssertSz(cbCluster != 0, "Cluster size is zero."); if (cb > 0x100000) return(0); if (cb % cbCluster) cbPad = (cbCluster - (cb % cbCluster)); cbAlloc = sizeof(ULONG) + cb + cbPad + PAGE_SIZE - 1; cbAlloc -= cbAlloc % PAGE_SIZE; cbAlloc += PAGE_SIZE; pvR = VirtualAlloc(0, cbAlloc, MEM_RESERVE, PAGE_NOACCESS); if (pvR == 0) return(0); pvC = VirtualAlloc(pvR, cbAlloc - PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE); if (pvC != pvR) { VirtualFree(pvR, 0, MEM_RELEASE); return(0); } *(ULONG *)pvC = cb; memset((BYTE *)pvC + sizeof(ULONG), 0xAD, (UINT) cbAlloc - cb - cbPad - sizeof(ULONG) - PAGE_SIZE); if (cbPad) memset((BYTE *)pvC + cbAlloc - PAGE_SIZE - cbPad, 0xBC, (UINT) cbPad); return((BYTE *)pvC + (cbAlloc - cb - cbPad - PAGE_SIZE)); } void EXPORTDBG __cdecl VMFree(void *pv) { VMFreeEx(pv, 1); } void EXPORTDBG __cdecl VMFreeEx(void *pv, ULONG cbCluster) { VMValidatePvEx(pv, cbCluster); if (!VirtualFree(PvToVMBase(pv), 0, MEM_RELEASE)) TrapSz2("VMFreeEx(pv=%08lX): VirtualFree failed (%08lX)", pv, GetLastError()); } void * EXPORTDBG __cdecl VMRealloc(void *pv, ULONG cb) { return VMReallocEx(pv, cb, 1); } void * EXPORTDBG __cdecl VMReallocEx(void *pv, ULONG cb, ULONG cbCluster) { void * pvNew = 0; ULONG cbCopy; VMValidatePvEx(pv, cbCluster); cbCopy = *(ULONG *)PvToVMBase(pv); if (cbCopy > cb) cbCopy = cb; pvNew = VMAllocEx(cb, cbCluster); if (pvNew) { MemCopy(pvNew, pv, cbCopy); VMFreeEx(pv, cbCluster); } return(pvNew); } ULONG EXPORTDBG __cdecl VMGetSize(void *pv) { return VMGetSizeEx(pv, 1); } ULONG EXPORTDBG __cdecl VMGetSizeEx(void *pv, ULONG cbCluster) { return(*(ULONG *)PvToVMBase(pv)); } #endif /* Virtual Memory Support (WIN16) ------------------------------------------- */ #ifdef WIN16 #define PvToVMBase(pv) ((void *)((ULONG)pv & 0xFFFF0000)) BOOL VMValidatePvEx(void *pv, ULONG cbCluster) { void * pvBase; BYTE * pb; pvBase = PvToVMBase(pv); pb = (BYTE *)pvBase + sizeof(ULONG); while (pb < (BYTE *)pv) { if (*pb++ != 0xAD) { TrapSz1("VMValidatePvEx(pv=%08lX): Block leader has been overwritten", pv); return(FALSE); } } if (cbCluster != 1) { ULONG cb = *((ULONG *)pvBase); ULONG cbPad = 0; if (cb % cbCluster) cbPad = (cbCluster - (cb % cbCluster)); if (cbPad) { BYTE *pbMac; pb = (BYTE *)pv + cb; pbMac = pb + cbPad; while (pb < pbMac) { if (*pb++ != 0xBC) { TrapSz1("VMValidatePvEx(pv=%08lX): Block trailer has been " "overwritten", pv); return(FALSE); } } } } return(TRUE); } BOOL VMValidatePv(void *pv) { return VMValidatePvEx(pv, 1); } void * EXPORTDBG __cdecl VMAlloc(ULONG cb) { return VMAllocEx(cb, 1); } void * EXPORTDBG __cdecl VMAllocEx(ULONG cb, ULONG cbCluster) { HGLOBAL hGlobal; ULONG cbAlloc; ULONG cbAllocFromSys; void * pvAlloc; ULONG cbPad = 0; if (cb > 0x10000 - sizeof(ULONG)) return(0); if (cb % cbCluster) cbPad = (cbCluster - (cb % cbCluster)); cbAlloc = sizeof(ULONG) + cb + cbPad; if (cbAlloc > 0x10000) return(0); #ifdef SIMPLE_MAPI hGlobal = GlobalAlloc(GPTR | GMEM_SHARE, cbAlloc); #else hGlobal = GlobalAlloc(GPTR, cbAlloc); #endif if (hGlobal == 0) return(0); cbAllocFromSys = GlobalSize(hGlobal); Assert(cbAllocFromSys >= cbAlloc); cbAlloc = cbAllocFromSys; pvAlloc = GlobalLock(hGlobal); if (pvAlloc == 0) { GlobalFree(hGlobal); return(0); } Assert(((ULONG)pvAlloc & 0x0000FFFF) == 0); *(ULONG *)pvAlloc = cb; memset((BYTE *)pvAlloc + sizeof(ULONG), 0xAD, (size_t)(cbAlloc - cb - cbPad - sizeof(ULONG))); if (cbPad) memset((BYTE *)pvAlloc + cbAlloc - cbPad, 0xBC, (size_t) cbPad); return((BYTE *)pvAlloc + (cbAlloc - cb - cbPad)); } void EXPORTDBG __cdecl VMFree(void *pv) { VMFreeEx(pv, 1); } void EXPORTDBG __cdecl VMFreeEx(void *pv, ULONG cbCluster) { if (VMValidatePvEx(pv, cbCluster)) { HGLOBAL hGlobal; ULONG cb = *(ULONG *)PvToVMBase(pv); memset(pv, 0xFE, (size_t)cb); hGlobal = (HGLOBAL)((ULONG)pv >> 16); GlobalFree(hGlobal); } } void * EXPORTDBG __cdecl VMRealloc(void *pv, ULONG cb) { return VMReallocEx(pv, cb, 1); } void * EXPORTDBG __cdecl VMReallocEx(void *pv, ULONG cb, ULONG cbCluster) { void * pvNew = 0; ULONG cbCopy; if (VMValidatePvEx(pv, cbCluster)) { cbCopy = *(ULONG *)PvToVMBase(pv); if (cbCopy > cb) cbCopy = cb; pvNew = VMAllocEx(cb, cbCluster); if (pvNew) { MemCopy(pvNew, pv, (size_t)cbCopy); VMFreeEx(pv, cbCluster); } } return(pvNew); } ULONG EXPORTDBG __cdecl VMGetSize(void *pv) { return VMGetSizeEx(pv, 1); } ULONG EXPORTDBG __cdecl VMGetSizeEx(void *pv, ULONG ulCluster) { if (VMValidatePvEx(pv, ulCluster)) return(*(ULONG *)PvToVMBase(pv)); return(0); } #endif /* Virtual Memory Support (Others) ------------------------------------------ */ /* * The VM Allocators do not currently work on: * ALPHA * MAC */ #if defined(MAC) || defined(_ALPHA_) #define VMAlloc(cb) 0 #define VMAllocEx(cb, ul) 0 #define VMRealloc(pv, cb) 0 #define VMReallocEx(pv, cb, ul) 0 #define VMFree(pv) #define VMFreeEx(pv, ul) #define VMGetSize(pv) 0 #define VMGetSizeEx(pv, ul) 0 #endif /* PblkEnqueue / PblkDequeue ------------------------------------------------ */ void PblkEnqueue(PBLK pblk) { pblk->pblkNext = pblk->pdbgmem->pblkHead; pblk->pblkPrev = 0; pblk->pdbgmem->pblkHead = pblk; if (pblk->pblkNext) pblk->pblkNext->pblkPrev = pblk; } void PblkDequeue(PBLK pblk) { if (pblk->pblkNext) pblk->pblkNext->pblkPrev = pblk->pblkPrev; if (pblk->pblkPrev) pblk->pblkPrev->pblkNext = pblk->pblkNext; else pblk->pdbgmem->pblkHead = pblk->pblkNext; } /* QueryInterface/AddRef/Release -------------------------------------------- */ STDMETHODIMP DBGMEM_QueryInterface(PDBGMEM pdbgmem, REFIID riid, LPVOID FAR* ppvObj) { if (memcmp(riid, &DBGMEM_IID_IBaseMalloc, sizeof(IID)) == 0) { pdbgmem->pmalloc->lpVtbl->AddRef(pdbgmem->pmalloc); *ppvObj = pdbgmem->pmalloc; return(0); } if (memcmp(riid, &DBGMEM_IID_IMalloc, sizeof(IID)) == 0 || memcmp(riid, &DBGMEM_IID_IUnknown, sizeof(IID)) == 0) { ++pdbgmem->cRef; *ppvObj = pdbgmem; return(0); } *ppvObj = NULL; /* OLE requires zeroing [out] parameter */ return(ResultFromScode(E_NOINTERFACE)); } STDMETHODIMP_(ULONG) DBGMEM_AddRef(PDBGMEM pdbgmem) { ULONG cRef; DBGMEM_EnterCriticalSection(pdbgmem); cRef = ++pdbgmem->cRef; DBGMEM_LeaveCriticalSection(pdbgmem); return(cRef); } STDMETHODIMP_(ULONG) DBGMEM_Release(PDBGMEM pdbgmem) { ULONG cRef; LPMALLOC pmalloc; DBGMEM_EnterCriticalSection(pdbgmem); cRef = --pdbgmem->cRef; DBGMEM_LeaveCriticalSection(pdbgmem); if (cRef == 0) { DBGMEM_CheckMemFn(pdbgmem, TRUE); pmalloc = pdbgmem->pmalloc; pdbgmem->lpVtbl = 0; #if defined(_WIN32) && defined(_X86_) DeleteCriticalSection(&pdbgmem->cs); #endif pmalloc->lpVtbl->Free(pmalloc, pdbgmem); pmalloc->lpVtbl->Release(pmalloc); } return(cRef); } /* IMalloc::Alloc ----------------------------------------------------------- */ STDMETHODIMP_(void FAR *) DBGMEM_Alloc(PDBGMEM pdbgmem, ULONG cb) { PBLK pblk; ULONG cbAlloc; LPVOID pvAlloc = 0; BYTE bFill = 0xFA; DBGMEM_EnterCriticalSection(pdbgmem); if (pdbgmem->fCheckOften) DBGMEM_CheckMemFn(pdbgmem, FALSE); cbAlloc = sizeof(BLK) + cb + pdbgmem->cbTail; if (pdbgmem->ulFailureAt != 0) { if (pdbgmem->ulFailureAt != pdbgmem->ulAllocAt) ++pdbgmem->ulAllocAt; else cbAlloc = 0; } if (cbAlloc < cb) pblk = 0; else if (pdbgmem->cbVirtual) pblk = VMAllocEx(cbAlloc, pdbgmem->cbVirtual); else pblk = (PBLK)pdbgmem->pmalloc->lpVtbl->Alloc(pdbgmem->pmalloc, cbAlloc); if (pblk) { pblk->pdbgmem = pdbgmem; pblk->ulAllocNum = ++pdbgmem->ulAllocNum; pblk->fUnleakable = FALSE; pblk->pblktail = (PBLKTAIL)((char *)pblk + sizeof(BLK) + cb); if (!pdbgmem->cbVirtual) *((PUABLK UNALIGNED * ) &((struct _BLKTAIL UNALIGNED *) pblk->pblktail)->pblk) = pblk; PblkEnqueue(pblk); #if defined(_WIN32) && defined(_X86_) GetCallStack((DWORD *)pblk->pfnCallers, 0, NCALLERS); #endif if (pdbgmem->fCheckOften) DBGMEM_CheckMemFn(pdbgmem, FALSE); pvAlloc = PblkToPv(pblk); if (pdbgmem->fFillRandom) bFill = (BYTE)pblk->ulAllocNum; memset(pvAlloc, bFill, (size_t)cb); if (pdbgmem->cbExtra) memset(pblk->pblktail + 1, 0xAE, pdbgmem->cbExtra * sizeof(ULONG)); } DBGMEM_LeaveCriticalSection(pdbgmem); return(pvAlloc); } /* IMalloc::Realloc --------------------------------------------------------- */ STDMETHODIMP_(void FAR *) DBGMEM_Realloc(PDBGMEM pdbgmem, void FAR* pv, ULONG cb) { ULONG cbAlloc; LPVOID pvAlloc = 0; BYTE bFill = 0xFA; DBGMEM_EnterCriticalSection(pdbgmem); if (pdbgmem->fCheckOften) DBGMEM_CheckMemFn(pdbgmem, FALSE); if (pv == 0) { TrapSz1("DBGMEM_Realloc(pv=NULL,cb=%ld): IMalloc::Realloc is being used allocate a new memory block. Explicit use of IMalloc::Alloc is preferred.", cb); pvAlloc = DBGMEM_Alloc(pdbgmem, cb); } else if (cb == 0) { TrapSz1("DBGMEM_Realloc(pv=%08lX,cb=0): IMalloc::Realloc is being used to free a memory block. Explicit use of IMalloc::Free is preferred.", pv); DBGMEM_Free(pdbgmem, pv); pvAlloc = 0; } else if (DBGMEM_ValidatePv(pdbgmem, pv, "DBGMEM_Realloc")) { PBLK pblk = PvToPblk(pv); ULONG cbOld = PblkClientSize(pblk); PBLK pblkNew; PblkDequeue(pblk); cbAlloc = sizeof(BLK) + cb + pdbgmem->cbTail; if (pdbgmem->ulFailureAt != 0) { if (pdbgmem->ulFailureAt != pdbgmem->ulAllocAt) ++pdbgmem->ulAllocAt; else cbAlloc = 0; } if (cbAlloc < cb) pblkNew = 0; else if (pdbgmem->cbVirtual) pblkNew = (PBLK)VMReallocEx(pblk, cbAlloc, pdbgmem->cbVirtual); else pblkNew = (PBLK)pdbgmem->pmalloc->lpVtbl->Realloc(pdbgmem->pmalloc, pblk, cbAlloc); if (pblkNew == 0) { PblkEnqueue(pblk); pvAlloc = 0; } else { pblkNew->pblktail = (PBLKTAIL)((char *)pblkNew + sizeof(BLK) + cb); if (!pdbgmem->cbVirtual) *((PUABLK UNALIGNED * ) &((struct _BLKTAIL UNALIGNED *) pblkNew->pblktail)->pblk) = pblkNew; PblkEnqueue(pblkNew); pvAlloc = PblkToPv(pblkNew); if (pdbgmem->fFillRandom) bFill = (BYTE)pblkNew->ulAllocNum; if (cb > cbOld) memset((char *)pvAlloc + cbOld, bFill, (size_t)(cb - cbOld)); if (pdbgmem->cbExtra) memset(pblkNew->pblktail + 1, 0xAE, pdbgmem->cbExtra * sizeof(ULONG)); } } DBGMEM_LeaveCriticalSection(pdbgmem); return(pvAlloc); } /* IMalloc::Free ------------------------------------------------------------ */ STDMETHODIMP_(void) DBGMEM_Free(PDBGMEM pdbgmem, void FAR * pv) { DBGMEM_EnterCriticalSection(pdbgmem); if (pdbgmem->fCheckOften) DBGMEM_CheckMemFn(pdbgmem, FALSE); if (pv && DBGMEM_ValidatePv(pdbgmem, pv, "DBGMEM_Free")) { PBLK pblk = PvToPblk(pv); PblkDequeue(pblk); memset(pblk, 0xDC, (size_t)PblkAllocSize(pblk)); if (pdbgmem->cbVirtual) VMFreeEx(pblk, pdbgmem->cbVirtual); else pdbgmem->pmalloc->lpVtbl->Free(pdbgmem->pmalloc, pblk); } DBGMEM_LeaveCriticalSection(pdbgmem); } /* IMalloc::GetSize --------------------------------------------------------- */ STDMETHODIMP_(ULONG) DBGMEM_GetSize(PDBGMEM pdbgmem, void FAR * pv) { ULONG ulResult = (ULONG)(-1); DBGMEM_EnterCriticalSection(pdbgmem); if (pv == 0) TrapSz("Although technically not an error, I bet you didn't really want to pass a NULL pointer to IMalloc::GetSize, did you? I hope you can deal with a size of -1, because that's the offical answer. Good luck."); else if (DBGMEM_ValidatePv(pdbgmem, pv, "DBGMEM_GetSize")) ulResult = PblkClientSize(PvToPblk(pv)); DBGMEM_LeaveCriticalSection(pdbgmem); return(ulResult); } /* IMalloc::DidAlloc -------------------------------------------------------- */ STDMETHODIMP_(int) DBGMEM_DidAlloc(PDBGMEM pdbgmem, void FAR * pv) { PBLK pblk; char * pszReason; int iResult = 0; DBGMEM_EnterCriticalSection(pdbgmem); for (pblk = pdbgmem->pblkHead; pblk; pblk = pblk->pblkNext) { AssertSz2(DBGMEM_ValidatePblk(pdbgmem,pblk,&pszReason)==TRUE, "Block header (pblk=%08lX) is invalid\n%s", pblk, pszReason); if (PblkToPv(pblk) == pv) { iResult = 1; break; } } DBGMEM_LeaveCriticalSection(pdbgmem); return(iResult); } /* IMalloc::HeapMinimize ---------------------------------------------------- */ STDMETHODIMP_(void) DBGMEM_HeapMinimize(PDBGMEM pdbgmem) { pdbgmem->pmalloc->lpVtbl->HeapMinimize(pdbgmem->pmalloc); } /* DBGMEM_ValidatePblk ------------------------------------------------------ */ BOOL DBGMEM_ValidatePblk(PDBGMEM pdbgmem, PBLK pblk, char ** pszReason) { #if defined(WIN16) || (defined(_WIN32) && defined(_X86_)) if (IsBadWritePtr(pblk, sizeof(BLK))) { *pszReason = "Block header cannot be written to"; goto err; } #endif if (pblk->pdbgmem != pdbgmem) { *pszReason = "Block header does not have correct pointer back to allocator"; goto err; } if (pblk->pblkNext) { #if defined(WIN16) || (defined(_WIN32) && defined(_X86_)) if (IsBadWritePtr(pblk->pblkNext, sizeof(BLK))) { *pszReason = "Block header has invalid next link pointer"; goto err; } #endif if (pblk->pblkNext->pblkPrev != pblk) { *pszReason = "Block header points to a next block which doesn't point back to it"; goto err; } } if (pblk->pblkPrev) { #if defined(WIN16) || (defined(_WIN32) && defined(_X86_)) if (IsBadWritePtr(pblk->pblkPrev, sizeof(BLK))) { *pszReason = "Block header has invalid prev link pointer"; goto err; } #endif if (pblk->pblkPrev->pblkNext != pblk) { *pszReason = "Block header points to a prev block which doesn't point back to it"; goto err; } } else if (pdbgmem->pblkHead != pblk) { *pszReason = "Block header has a zero prev link but the allocator doesn't believe it is the first block"; goto err; } if (pblk->ulAllocNum > pdbgmem->ulAllocNum) { *pszReason = "Block header has an invalid internal allocation number"; goto err; } if (!pdbgmem->cbVirtual) { #if defined(WIN16) || (defined(_WIN32) && defined(_X86_)) if (IsBadWritePtr(pblk->pblktail, pdbgmem->cbTail)) { *pszReason = "Block header has invalid pblktail pointer"; goto err; } #endif if (*((PUABLK UNALIGNED * ) &((struct _BLKTAIL UNALIGNED *) pblk->pblktail)->pblk) != pblk) { *pszReason = "Block trailer does not point back to the block header"; goto err; } } if (pdbgmem->cbExtra) { ULONG UNALIGNED * pul = (ULONG UNALIGNED *)(pblk->pblktail + 1); int n = pdbgmem->cbExtra; for (; --n >= 0; ++pul) if (*pul != 0xAEAEAEAE) { *pszReason = "Block trailer spiddle-zone has been overwritten"; goto err; } } return(TRUE); err: return(FALSE); } /* DBGMEM_ValidatePv -------------------------------------------------------- */ BOOL DBGMEM_ValidatePv(PDBGMEM pdbgmem, void * pv, char * pszFunc) { char * pszReason; if (DBGMEM_DidAlloc(pdbgmem, pv) == 0) { TrapSz3("DBGMEM_ValidatePv(subsys=%s,pv=%08lX) [via %s]\nDetected a memory block which was not allocated by this allocator", pdbgmem->szSubsys, pv, pszFunc); return(FALSE); } if (DBGMEM_ValidatePblk(pdbgmem,PvToPblk(pv),&pszReason)) return(TRUE); TrapSz4("DBGMEM_ValidatePv(%s,pv=%08lX) [via %s]\n%s", pdbgmem->szSubsys, pv, pszFunc, pszReason); return(FALSE); } /* DBGMEM_ReportLeak -------------------------------------------------------- */ #if defined(_WIN32) && defined(_X86_) void EXPORTDBG __cdecl DBGMEM_LeakHook(FARPROC pfn) { /* Dummy function so that you can set a breakpoint with command */ /* "ln ecx;g", in order to get the debugger to print out the name */ /* of the function which allocated the leaked memory block */ } #endif void DBGMEM_ReportLeak(PDBGMEM pdbgmem, PBLK pblk) { int i = 0; DebugTrace("%s Memory Leak: @%08lX, allocation #%ld, size %ld\n", pdbgmem->szSubsys, PblkToPv(pblk), pblk->ulAllocNum, PblkClientSize(pblk)); #if defined(_WIN32) && defined(_X86_) for (i = 0; i < NCALLERS && pblk->pfnCallers[i] != 0; i++) { DebugTrace("[%d] %08lX ", i, pblk->pfnCallers[i]); DBGMEM_LeakHook(pblk->pfnCallers[i]); } DebugTrace("\n"); #endif } /* DBGMEM_NoLeakDetectFn ---------------------------------------------------- */ void EXPORTDBG __cdecl DBGMEM_NoLeakDetectFn(void * pmalloc, void *pv) { PDBGMEM pdbgmem = (PDBGMEM)pmalloc; DBGMEM_EnterCriticalSection(pdbgmem); if (pv == 0) pdbgmem->fUnleakable = TRUE; else if (DBGMEM_ValidatePv(pdbgmem, pv, "DBGMEM_NoLeakDetectFn")) PvToPblk(pv)->fUnleakable = TRUE; DBGMEM_LeaveCriticalSection(pdbgmem); } /* DBGMEM_SetFailureAtFn ---------------------------------------------------- */ void EXPORTDBG __cdecl DBGMEM_SetFailureAtFn(void * pmalloc, ULONG ulFailureAt) { PDBGMEM pdbgmem = (PDBGMEM)pmalloc; DBGMEM_EnterCriticalSection(pdbgmem); pdbgmem->ulFailureAt = ulFailureAt; DBGMEM_LeaveCriticalSection(pdbgmem); } /* DBGMEM_CheckMemFn -------------------------------------------------------- */ void EXPORTDBG __cdecl DBGMEM_CheckMemFn(void * pmalloc, BOOL fReportOrphans) { PDBGMEM pdbgmem = (PDBGMEM)pmalloc; PBLK pblk; int cLeaks = 0; DBGMEM_EnterCriticalSection(pdbgmem); for (pblk = pdbgmem->pblkHead; pblk; pblk = pblk->pblkNext) { if (!DBGMEM_ValidatePv(pdbgmem, PblkToPv(pblk), "DBGMEM_CheckMemFn")) break; if (fReportOrphans && !pdbgmem->fUnleakable && !pblk->fUnleakable) { DBGMEM_ReportLeak(pdbgmem, pblk); cLeaks += 1; } } #if defined(WIN16) || (defined(_WIN32) && defined(_X86_)) if (fAssertLeaks == -1) { fAssertLeaks = GetPrivateProfileIntA(szSectionDebug, szKeyAssertLeaks, 0, szDebugIni); } #endif if (cLeaks > 0) { #if defined(WIN16) || (defined(_WIN32) && defined(_X86_)) if (fAssertLeaks) { TrapSz3("DBGMEM detected %d memory leak%s in subsystem %s", cLeaks, cLeaks == 1 ? "" : "s", pdbgmem->szSubsys); } else { TraceSz3("DBGMEM detected %d memory leak%s in subsystem %s", cLeaks, cLeaks == 1 ? "" : "s", pdbgmem->szSubsys); } #else TraceSz3("DBGMEM detected %d memory leak%s in subsystem %s", cLeaks, cLeaks == 1 ? "" : "s", pdbgmem->szSubsys); #endif } DBGMEM_LeaveCriticalSection(pdbgmem); } /* vtblDBGMEM --------------------------------------------------------------- */ DBGMEM_Vtbl BASED_DEBUG vtblDBGMEM = { VTABLE_FILL DBGMEM_QueryInterface, DBGMEM_AddRef, DBGMEM_Release, DBGMEM_Alloc, DBGMEM_Realloc, DBGMEM_Free, DBGMEM_GetSize, DBGMEM_DidAlloc, DBGMEM_HeapMinimize }; /* DBGMEM_EncapsulateFn ----------------------------------------------------- */ void * EXPORTDBG __cdecl DBGMEM_EncapsulateFn(void * pvmalloc, char *pszSubsys, BOOL fCheckOften) { LPMALLOC pmalloc = (LPMALLOC)pvmalloc; PDBGMEM pdbgmem; LPMALLOC pmallocBase; ULONG cbVirtual = 0; BOOL fFillRandom = FALSE; HRESULT hr; hr = pmalloc->lpVtbl->QueryInterface(pmalloc, &DBGMEM_IID_IBaseMalloc, &pmallocBase); if (hr) { pmallocBase = pmalloc; pmallocBase->lpVtbl->AddRef(pmallocBase); } pdbgmem = (PDBGMEM)pmallocBase->lpVtbl->Alloc(pmallocBase, sizeof(DBGMEM)); if (pdbgmem == 0) { TrapSz("DBGMEM: Failed trying to allocate memory for the first time!\n"); return(pmallocBase); } #if defined(WIN16) || (defined(_WIN32) && defined(_X86_)) cbVirtual = GetPrivateProfileIntA(szSectionDebug, szKeyUseVirtual, 0, szDebugIni); if (cbVirtual != 0 && cbVirtual != 1 && cbVirtual != 4) cbVirtual = 1; if (cbVirtual) DebugTrace("DBGMEM: Subsystem '%s' using virtual memory allocator -" " align %d.\n", pszSubsys, cbVirtual); if (!fCheckOften) fCheckOften = GetPrivateProfileIntA(szSectionDebug, szKeyCheckOften, 0, szDebugIni); fFillRandom = GetPrivateProfileIntA(szSectionDebug, szKeyFillRandom, 0, szDebugIni); #endif memset(pdbgmem, 0, sizeof(DBGMEM)); pdbgmem->lpVtbl = &vtblDBGMEM; pdbgmem->cRef = 1; pdbgmem->pmalloc = pmallocBase; pdbgmem->fCheckOften = fCheckOften; pdbgmem->fUnleakable = FALSE; pdbgmem->cbVirtual = cbVirtual; pdbgmem->fFillRandom = fFillRandom; pdbgmem->cbExtra = 0; pdbgmem->ulAllocAt = 1L; pdbgmem->ulFailureAt = 0L; if (pdbgmem->cbVirtual) pdbgmem->cbTail = 0; else pdbgmem->cbTail = sizeof(BLKTAIL) + pdbgmem->cbExtra * sizeof(ULONG); lstrcpyn(pdbgmem->szSubsys, pszSubsys, sizeof(pdbgmem->szSubsys)); #if defined(_WIN32) && defined(_X86_) InitializeCriticalSection(&pdbgmem->cs); #endif return(pdbgmem); } /* DBGMEM_ShutdownFn -------------------------------------------------------- */ void EXPORTDBG __cdecl DBGMEM_ShutdownFn(void *pvmalloc) { LPMALLOC pmalloc = (LPMALLOC)pvmalloc; PDBGMEM pdbgmem = (PDBGMEM)pvmalloc; LPMALLOC pmallocBase; HRESULT hr; hr = pmalloc->lpVtbl->QueryInterface(pmalloc, &DBGMEM_IID_IBaseMalloc, &pmallocBase); if (hr == 0) { pmallocBase->lpVtbl->Release(pmallocBase); if (pdbgmem->cRef != 1) { TrapSz2("DBGMEM_Shutdown: Expected a cRef of 1; instead have %ld for %s", pdbgmem->cRef, pdbgmem->szSubsys); pdbgmem->cRef = 1; } } pmalloc->lpVtbl->Release(pmalloc); } /* -------------------------------------------------------------------------- */ #endif