home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / trialva / ibmcppw / sdk / mapi / win16 / dev / common / mapidbg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-11  |  63.1 KB  |  2,452 lines

  1. /*
  2.  *  MAPIDBG.C
  3.  *
  4.  *  MAPI Debugging Utilities
  5.  *
  6.  *  Copyright 1993-1995 Microsoft Corporation. All Rights Reserved.
  7.  */
  8.  
  9. #ifdef DEBUG
  10.  
  11. #pragma warning(disable:4100)   /* unreferenced formal parameter */
  12. #pragma warning(disable:4127)   /* conditional expression is constant */
  13. #pragma warning(disable:4201)   /* nameless struct/union */
  14. #pragma warning(disable:4206)   /* translation unit is empty */
  15. #pragma warning(disable:4209)   /* benign typedef redefinition */
  16. #pragma warning(disable:4214)   /* bit field types other than int */
  17. #pragma warning(disable:4001)   /* single line comments */
  18. #pragma warning(disable:4050)   /* different code attributes */
  19.  
  20. #ifdef _MAC
  21. #define INC_OLE2
  22. #include <windows.h>
  23. #include <macname1.h>
  24. #include <macos\menus.h>
  25. #include <stdio.h>
  26. #include <mapiprof.h>
  27.  
  28. #define GetPrivateProfileIntA       MAPIGetPrivateProfileInt
  29.  
  30. #elif defined(WIN16) || defined(WIN32)
  31. #pragma warning(disable:4115)   /* named type definition in parentheses */
  32. #include <windows.h>
  33. #include <mapiwin.h>
  34.  
  35. #ifdef WIN32
  36. #pragma warning(disable:4001)   /* single line comments */
  37. #pragma warning(disable:4115)   /* named type definition in parentheses */
  38. #pragma warning (disable:4514)  /* unreferenced inline function */
  39. #include <objerror.h>
  40. #endif
  41.  
  42. #else
  43.  
  44. #include <stdio.h>
  45. void __far __pascal OutputDebugString(char __far *);
  46. #define wvsprintf           vsprintf
  47. #define wsprintf            sprintf
  48.  
  49. #endif      /* _MAC */
  50.  
  51. #ifdef DOS
  52. #define lstrcpyA            strcpy
  53. #define lstrlenA            strlen
  54. #define lstrcatA            strcat
  55. #define wvsprintfA          wvsprintf
  56. #define wsprintfA           wsprintf
  57. #define OutputDebugStringA  OutputDebugString
  58. #endif
  59.  
  60. #include <mapidbg.h>
  61. #include <mapidefs.h>
  62. #include <mapitags.h>
  63. #include <mapicode.h>
  64. #include <stdarg.h>
  65. #include <string.h>
  66. #include <time.h>
  67. #ifdef _MAC
  68. #include <macname2.h>
  69. #endif
  70.  
  71. #ifdef DBCS
  72. #ifdef DOS
  73. #include <gapidos.h>
  74. #else
  75. #include <mapigapi.h>
  76. #endif
  77. #endif
  78.  
  79. #if defined(DEBUG) && defined(_WINNT)
  80. #include <lmcons.h>
  81. #include <lmalert.h>
  82. #endif
  83.  
  84. /*  Patch/Hack for 16bit, optimized builds.
  85.  *
  86.  *  memcpy with a size of 0 bytes causes a
  87.  *  crash.
  88.  */
  89.  
  90. #ifndef __MEMCPY_H_
  91. #define __MEMCPY_H_
  92.  
  93. #if defined(WIN16) && !defined(DEBUG)
  94. #define MemCopy(_dst,_src,_cb)      do                                  \
  95.                                     {                                   \
  96.                                         size_t __cb = (size_t)(_cb);    \
  97.                                         if (__cb)                       \
  98.                                             memcpy(_dst,_src,__cb);     \
  99.                                     } while (FALSE)
  100. #else
  101. #define MemCopy(_dst,_src,_cb)  memcpy(_dst,_src,(size_t)(_cb))
  102. #endif
  103.  
  104. #endif
  105.  
  106. #if (defined(WIN16) || defined(DOS)) && !defined(NO_BASED_DEBUG)
  107. #define BASED_DEBUG __based(__segname("DEBUG_DATA"))
  108. #else
  109. #define BASED_DEBUG
  110. #endif
  111.  
  112. #if defined(WIN16)
  113. #define BASED_CODE          __based(__segname("_CODE"))
  114. #else
  115. #define BASED_CODE
  116. #endif
  117.  
  118.  
  119.  
  120. #if defined(WIN16) || defined(WIN32)
  121. static BOOL fTraceEnabled       = -1;
  122. static BOOL fUseEventLog        = -1;
  123. static BOOL fAssertLeaks        = -1;
  124.  
  125. static char szKeyTraceEnabled[] = "DebugTrace";
  126. static char szKeyEventLog[]     = "EventLog";
  127. static char szKeyUseVirtual[]   = "VirtualMemory";
  128. static char szKeyAssertLeaks[]  = "AssertLeaks";
  129. static char szKeyCheckOften[]   = "CheckHeapOften";
  130. static char szKeyFillRandom[]   = "MemoryFillRandom";
  131. static char szSectionDebug[]    = "General";
  132. static char szDebugIni[]        = "MAPIDBG.INI";
  133. #endif
  134.  
  135. #ifndef VTABLE_FILL
  136. #ifdef _MAC
  137. #define VTABLE_FILL     NULL,
  138. #else
  139. #define VTABLE_FILL
  140. #endif
  141. #endif
  142.  
  143. #if defined(DEBUG) && defined(_WINNT)
  144. typedef BOOL  (WINAPI   *ReportEventFN)(HANDLE, WORD, WORD, DWORD, PSID, WORD, DWORD, LPCTSTR *, LPVOID);
  145. typedef HANDLE (WINAPI  *RegisterEventSourceAFN)(LPCTSTR, LPCTSTR);
  146.  
  147. ReportEventFN pfnReportEvent = NULL;
  148. RegisterEventSourceAFN pfnRegisterEventSourceA = NULL;
  149. #endif
  150.  
  151.  
  152. #ifdef  WIN16
  153. #pragma code_seg("Debug")
  154. #endif  
  155.  
  156. #if defined( _WINNT)
  157.  
  158. /*++
  159.  
  160. Routine Description:
  161.  
  162.     This routine returns if the service specified is running interactively
  163.     (not invoked \by the service controller).
  164.  
  165. Arguments:
  166.  
  167.     None
  168.  
  169. Return Value:
  170.  
  171.     BOOL - TRUE if the service is an EXE.
  172.  
  173.  
  174. Note:
  175.  
  176. --*/
  177.  
  178. BOOL WINAPI IsDBGServiceAnExe( VOID )
  179. {
  180.     HANDLE hProcessToken = NULL;
  181.     DWORD groupLength = 50;
  182.  
  183.     PTOKEN_GROUPS groupInfo = (PTOKEN_GROUPS)LocalAlloc(0, groupLength);
  184.  
  185.     SID_IDENTIFIER_AUTHORITY siaNt = SECURITY_NT_AUTHORITY;
  186.     PSID InteractiveSid = NULL;
  187.     PSID ServiceSid = NULL;
  188.     DWORD i;
  189.  
  190.     // Start with assumption that process is an EXE, not a Service.
  191.     BOOL fExe = TRUE;
  192.  
  193.  
  194.     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
  195.         goto ret;
  196.  
  197.     if (groupInfo == NULL)
  198.         goto ret;
  199.  
  200.     if (!GetTokenInformation(hProcessToken, TokenGroups, groupInfo,
  201.         groupLength, &groupLength))
  202.     {
  203.         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  204.             goto ret;
  205.  
  206.         LocalFree(groupInfo);
  207.         groupInfo = NULL;
  208.     
  209.         groupInfo = (PTOKEN_GROUPS)LocalAlloc(0, groupLength);
  210.     
  211.         if (groupInfo == NULL)
  212.             goto ret;
  213.     
  214.         if (!GetTokenInformation(hProcessToken, TokenGroups, groupInfo,
  215.             groupLength, &groupLength))
  216.         {
  217.             goto ret;
  218.         }
  219.     }
  220.  
  221.     //
  222.     //  We now know the groups associated with this token.  We want to look to see if
  223.     //  the interactive group is active in the token, and if so, we know that
  224.     //  this is an interactive process.
  225.     //
  226.     //  We also look for the "service" SID, and if it's present, we know we're a service.
  227.     //
  228.     //  The service SID will be present iff the service is running in a
  229.     //  user account (and was invoked by the service controller).
  230.     //
  231.  
  232.  
  233.     if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_INTERACTIVE_RID, 0, 0,
  234.         0, 0, 0, 0, 0, &InteractiveSid))
  235.     {
  236.         goto ret;
  237.     }
  238.  
  239.     if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_SERVICE_RID, 0, 0, 0,
  240.         0, 0, 0, 0, &ServiceSid))
  241.     {
  242.         goto ret;
  243.     }
  244.  
  245.     for (i = 0; i < groupInfo->GroupCount ; i += 1)
  246.     {
  247.         SID_AND_ATTRIBUTES sanda = groupInfo->Groups[i];
  248.         PSID Sid = sanda.Sid;
  249.     
  250.         //
  251.         //  Check to see if the group we're looking at is one of
  252.         //  the 2 groups we're interested in.
  253.         //
  254.     
  255.         if (EqualSid(Sid, InteractiveSid))
  256.         {
  257.             //
  258.             //  This process has the Interactive SID in its
  259.             //  token.  This means that the process is running as
  260.             //  an EXE.
  261.             //
  262.             goto ret;
  263.         }
  264.         else if (EqualSid(Sid, ServiceSid))
  265.         {
  266.             //
  267.             //  This process has the Service SID in its
  268.             //  token.  This means that the process is running as
  269.             //  a service running in a user account.
  270.             //
  271.             fExe = FALSE;
  272.             goto ret;
  273.         }
  274.     }
  275.  
  276.     //
  277.     //  Neither Interactive or Service was present in the current users token,
  278.     //  This implies that the process is running as a service, most likely
  279.     //  running as LocalSystem.
  280.     //
  281.     fExe = FALSE;
  282.  
  283. ret:
  284.  
  285.     if (InteractiveSid)
  286.         FreeSid(InteractiveSid);
  287.  
  288.     if (ServiceSid)
  289.         FreeSid(ServiceSid);
  290.  
  291.     if (groupInfo)
  292.         LocalFree(groupInfo);
  293.  
  294.     if (hProcessToken)
  295.         CloseHandle(hProcessToken);
  296.  
  297.     return(fExe);
  298. }
  299.  
  300. #endif
  301.  
  302. /* LogIt */
  303.  
  304. #ifndef _MAC
  305. void    LogIt(LPSTR plpcText, BOOL  fUseAlert)
  306. {
  307. #if defined(DEBUG) && defined(_WINNT)
  308.     LPSTR           llpcStr[2];
  309.     static HANDLE   hEventSource = NULL;
  310.  
  311.     if (pfnRegisterEventSourceA == NULL)
  312.     {
  313.         /* This handle is not important as the lib will be freed on exit (and it's debug only) */
  314.         HINSTANCE       lhLib = LoadLibraryA("advapi32.dll");
  315.         
  316.         if (!lhLib)
  317.             return;
  318.         
  319.         pfnRegisterEventSourceA = (RegisterEventSourceAFN) GetProcAddress(lhLib, "RegisterEventSourceA");
  320.         pfnReportEvent = (ReportEventFN) GetProcAddress(lhLib, "ReportEventA");
  321.         
  322.         if (!pfnRegisterEventSourceA || !pfnReportEvent)
  323.             return;
  324.     }
  325.         
  326.     if (!hEventSource)                                      
  327.         hEventSource = pfnRegisterEventSourceA(NULL, "MAPIDebug");
  328.  
  329.     llpcStr[0] = "MAPI Debug Log";
  330.     llpcStr[1] = plpcText;
  331.  
  332.     pfnReportEvent(hEventSource,    /* handle of event source */
  333.         EVENTLOG_ERROR_TYPE,        /* event type             */
  334.         0,                          /* event category         */
  335.         0,                          /* event ID               */
  336.         NULL,                       /* current user's SID     */
  337.         2,                          /* strings in lpszStrings */
  338.         0,                          /* no bytes of raw data   */
  339.         llpcStr,                    /* array of error strings */
  340.         NULL);                      /* no raw data            */
  341.         
  342.     /* Now we generate an Alert! */
  343.     /* This code is adapted from PierreC's stuff, and NEEDS TO BE UNICODE!!!! */
  344.     if (fUseAlert)
  345.     {
  346. #define MAX_LINE        256
  347.  
  348. typedef NET_API_STATUS  (WINAPI *NAREFN)(TCHAR *, ADMIN_OTHER_INFO *, ULONG, TCHAR *);
  349.  
  350.         BYTE                rgb[sizeof(ADMIN_OTHER_INFO) + (sizeof(WCHAR) * MAX_LINE)];
  351.         ADMIN_OTHER_INFO *  poi     = (ADMIN_OTHER_INFO *) rgb;
  352.         WCHAR *             pch     = (WCHAR *) (rgb + sizeof(ADMIN_OTHER_INFO));
  353.         NET_API_STATUS      nas;
  354.         static   NAREFN     fnNetAlertRaiseEx = NULL;
  355.         
  356.         /* Resolve function here, never free library as it's debug only */
  357.         if (!fnNetAlertRaiseEx)
  358.         {
  359.             HINSTANCE       lhLib = LoadLibrary("NETAPI32.DLL");
  360.             if (lhLib)
  361.                 fnNetAlertRaiseEx = (NAREFN) GetProcAddress(lhLib, "NetAlertRaiseEx");
  362.         }
  363.         
  364.         if (fnNetAlertRaiseEx)
  365.         {
  366.             poi->alrtad_errcode = (DWORD) -1;
  367.             poi->alrtad_numstrings = 1;
  368.             
  369.             if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plpcText, -1, pch, MAX_LINE))
  370.             {
  371.                 nas = fnNetAlertRaiseEx(
  372.                             (TCHAR *) L"ADMIN",
  373.                             poi, 
  374.                             sizeof(ADMIN_OTHER_INFO) + ((lstrlenW(pch) + 1) * sizeof(WCHAR)),
  375.                             (TCHAR *) L"MAPI Assert");
  376.                     
  377.                         
  378.             }
  379.         }
  380.     }
  381.     
  382. #endif /* DEBUG && NT */
  383. }
  384. #endif /* !_MAC */
  385.  
  386. /* DebugOutputFn ------------------------------------------------------------ */
  387.  
  388. char BASED_CODE szCR[] = "\r";
  389.  
  390. void DebugOutputFn(char *psz)
  391. {
  392. #if defined(_MAC)
  393.  
  394.     OutputDebugString(psz);
  395.  
  396. #else
  397.  
  398. #if defined(WIN16) || defined(WIN32)
  399.     if (fTraceEnabled == -1)
  400.     {
  401.         fTraceEnabled = GetPrivateProfileIntA(szSectionDebug, szKeyTraceEnabled,
  402.             0, szDebugIni);
  403.  
  404.         fUseEventLog = GetPrivateProfileIntA(szSectionDebug, szKeyEventLog,
  405.             0, szDebugIni);     
  406.     
  407.     }
  408.  
  409.     if (!fTraceEnabled)
  410.         return;
  411.  
  412.     if (fUseEventLog)
  413. #else
  414.     if (FALSE)
  415. #endif
  416.         LogIt(psz, FALSE);
  417.  
  418. #ifdef WIN16
  419.     OutputDebugString(psz);
  420.     OutputDebugString(szCR);
  421. #else
  422.     OutputDebugStringA(psz);
  423.     OutputDebugStringA(szCR);
  424. #endif
  425.     
  426. #endif  /* _MAC */
  427. }
  428.  
  429.  
  430. /* DebugTrapFn -------------------------------------------------------------- */
  431.  
  432. #if defined(WIN32) && !defined(_MAC)
  433.  
  434. BOOL fInhibitTrapThread = FALSE;
  435.  
  436. typedef struct {
  437.     char *      sz1;
  438.     char *      sz2;
  439.     UINT        rgf;
  440.     int         iResult;
  441. } MBContext;
  442.  
  443. DWORD WINAPI MessageBoxFnThreadMain(MBContext *pmbc)
  444. {
  445.     if (fUseEventLog)
  446.     {
  447.         LogIt(pmbc->sz1, TRUE);
  448.         pmbc->iResult = IDIGNORE;
  449.     }
  450.     else
  451.         pmbc->iResult = MessageBoxA(NULL, pmbc->sz1, pmbc->sz2,
  452.             pmbc->rgf | MB_SETFOREGROUND);
  453.  
  454.     return(0);
  455. }
  456.  
  457. int MessageBoxFn(char *sz1, char *sz2, UINT rgf)
  458. {
  459.     HANDLE      hThread;
  460.     DWORD       dwThreadId;
  461.     MBContext   mbc;
  462.  
  463.     mbc.sz1     = sz1;
  464.     mbc.sz2     = sz2;
  465.     mbc.rgf     = rgf;
  466.     mbc.iResult = IDRETRY;
  467.  
  468.     if (fInhibitTrapThread)
  469.     {
  470.         MessageBoxFnThreadMain(&mbc);
  471.     }
  472.     else
  473.     {
  474.         hThread = CreateThread(NULL, 0,
  475.             (PTHREAD_START_ROUTINE)MessageBoxFnThreadMain, &mbc, 0, &dwThreadId);
  476.  
  477.         if (hThread != NULL) {
  478.             WaitForSingleObject(hThread, INFINITE);
  479.             CloseHandle(hThread);
  480.         }
  481.     }
  482.  
  483.     return(mbc.iResult);
  484. }
  485. #else
  486. #define MessageBoxFn(sz1, sz2, rgf)     MessageBoxA(NULL, sz1, sz2, rgf)
  487. #endif
  488.  
  489. int EXPORTDBG __cdecl DebugTrapFn(int fFatal, char *pszFile, int iLine, char *pszFormat, ...)
  490. {
  491.     char    sz[512];
  492.     va_list vl;
  493.  
  494.     #if defined(WIN16) || defined(WIN32)
  495.     int     id;
  496.     #endif
  497.  
  498.     lstrcpyA(sz, "++++ MAPI Debug Trap (");
  499.     _strdate(sz + lstrlenA(sz));
  500.     lstrcatA(sz, " ");
  501.     _strtime(sz + lstrlenA(sz));
  502.     lstrcatA(sz, ")\n");
  503.     DebugOutputFn(sz);
  504.  
  505.     va_start(vl, pszFormat);
  506.     wvsprintfA(sz, pszFormat, vl);
  507.     va_end(vl);
  508.  
  509.     wsprintfA(sz + lstrlenA(sz), "\n[File %s, Line %d]\n\n", pszFile, iLine);
  510.  
  511.     DebugOutputFn(sz);
  512.  
  513.     #if defined(DOS)
  514.     _asm { int 3 }
  515.     #endif
  516.  
  517. #if defined(WIN16) || defined(WIN32)
  518.     /* Hold down control key to prevent MessageBox */
  519.     if ( GetAsyncKeyState(VK_CONTROL) >= 0 )
  520.     {
  521.         UINT uiFlags = MB_ABORTRETRYIGNORE;
  522.  
  523.         if (fFatal)
  524.             uiFlags |= MB_DEFBUTTON1;
  525.         else
  526.             uiFlags |= MB_DEFBUTTON3;
  527.  
  528.         #ifdef WIN16
  529.         uiFlags |= MB_ICONEXCLAMATION | MB_SYSTEMMODAL;
  530.         #else
  531.         uiFlags |= MB_ICONSTOP | MB_TASKMODAL;
  532.         #endif
  533.  
  534.         #if defined(WIN32) && !defined(_WIN95) && !defined(_MAC)
  535.         if (!IsDBGServiceAnExe())
  536.             uiFlags |= MB_SERVICE_NOTIFICATION;
  537.         #endif
  538.  
  539.         id = MessageBoxFn(sz, "MAPI Debug Trap", uiFlags);
  540.  
  541.         if (id == IDABORT)
  542.             *((LPBYTE)NULL) = 0;
  543.         else if (id == IDRETRY)
  544.             DebugBreak();
  545.     }
  546. #endif
  547.  
  548.     return(0);
  549. }
  550.  
  551. /* DebugTraceFn ------------------------------------------------------------- */
  552.  
  553. int EXPORTDBG __cdecl DebugTraceFn(char *pszFormat, ...)
  554. {
  555.     char    sz[512];
  556.     int     fAutoLF = 0;
  557.     va_list vl;
  558.  
  559.     if (*pszFormat == '~') {
  560.         pszFormat += 1;
  561.         fAutoLF = 1;
  562.     }
  563.  
  564.     va_start(vl, pszFormat);
  565.     wvsprintfA(sz, pszFormat, vl);
  566.     va_end(vl);
  567.  
  568. #ifndef _MAC
  569.     if (fAutoLF)
  570.         lstrcatA(sz, "\n");
  571. #endif
  572.  
  573.     DebugOutputFn(sz);
  574.  
  575.     return(0);
  576. }
  577.  
  578. /* DebugTraceProblemsFn */
  579.  
  580. void EXPORTDBG __cdecl DebugTraceProblemsFn(LPSTR sz, LPVOID pv)
  581. {
  582.     LPSPropProblemArray pprobs = (LPSPropProblemArray)pv;
  583.     SPropProblem *      pprob = pprobs->aProblem;
  584.     int                 cprob = (int)pprobs->cProblem;
  585.  
  586.     DebugTraceFn("%s: SetProps problem\n", sz);
  587.     while (cprob--)
  588.     {
  589.         DebugTraceFn("Property %s (index %ld): failed with %s\n",
  590.             SzDecodeUlPropTagFn(pprob->ulPropTag),
  591.             pprob->ulIndex,
  592.             SzDecodeScodeFn(pprob->scode));
  593.     }
  594. }
  595.  
  596. /* SCODE & PropTag decoding ------------------------------------------------- */
  597.  
  598. typedef struct
  599. {
  600.     char *          psz;
  601.     unsigned long   ulPropTag;
  602. } PT;
  603.  
  604. typedef struct
  605. {
  606.     char *  psz;
  607.     SCODE   sc;
  608. } SC;
  609.  
  610. #define Pt(_ptag)   {#_ptag, _ptag}
  611. #define Sc(_sc)     {#_sc, _sc}
  612.  
  613. #if !defined(DOS)
  614. static PT BASED_DEBUG rgpt[] = {
  615.     
  616. #include "_tags.h"
  617.     
  618. /*
  619.  * Property types
  620.  */
  621.     Pt(PR_NULL),
  622.     Pt(PT_UNSPECIFIED),
  623.     Pt(PT_NULL),
  624.     Pt(PT_I2),
  625.     Pt(PT_LONG),
  626.     Pt(PT_R4),
  627.     Pt(PT_DOUBLE),
  628.     Pt(PT_CURRENCY),
  629.     Pt(PT_APPTIME),
  630.     Pt(PT_ERROR),
  631.     Pt(PT_BOOLEAN),
  632.     Pt(PT_OBJECT),
  633.     Pt(PT_I8),
  634.     Pt(PT_STRING8),
  635.     Pt(PT_UNICODE),
  636.     Pt(PT_SYSTIME),
  637.     Pt(PT_CLSID),
  638.     Pt(PT_BINARY),
  639.     Pt(PT_TSTRING),
  640.     Pt(PT_MV_I2),
  641.     Pt(PT_MV_LONG),
  642.     Pt(PT_MV_R4),
  643.     Pt(PT_MV_DOUBLE),
  644.     Pt(PT_MV_CURRENCY),
  645.     Pt(PT_MV_APPTIME),
  646.     Pt(PT_MV_SYSTIME),
  647.     Pt(PT_MV_STRING8),
  648.     Pt(PT_MV_BINARY),
  649.     Pt(PT_MV_UNICODE),
  650.     Pt(PT_MV_CLSID),
  651.     Pt(PT_MV_I8)
  652. };
  653.  
  654. #define cpt (sizeof(rgpt) / sizeof(PT))
  655.  
  656. static SC BASED_DEBUG rgsc[] = {
  657.  
  658. /* FACILITY_NULL error codes from OLE */
  659.  
  660.     Sc(S_OK),
  661.     Sc(S_FALSE),
  662.  
  663.     Sc(E_UNEXPECTED),
  664.     Sc(E_NOTIMPL),
  665.     Sc(E_OUTOFMEMORY),
  666.     Sc(E_INVALIDARG),
  667.     Sc(E_NOINTERFACE),
  668.     Sc(E_POINTER),
  669.     Sc(E_HANDLE),
  670.     Sc(E_ABORT),
  671.     Sc(E_FAIL),
  672.     Sc(E_ACCESSDENIED),
  673.  
  674. /* MAPI error codes from MAPICODE.H */
  675. #include "_scode.h"
  676.                     
  677. };
  678.  
  679. #define csc (sizeof(rgsc) / sizeof(SC))
  680. #endif
  681.  
  682. char * EXPORTDBG __cdecl
  683. SzDecodeScodeFn(SCODE sc)
  684. {
  685.     static char rgch[64];
  686.  
  687.     #if !defined(DOS)
  688.     int isc;
  689.     for (isc = 0; isc < csc; ++isc)
  690.         if (sc == rgsc[isc].sc)
  691.             return rgsc[isc].psz;
  692.     #endif
  693.  
  694.     wsprintfA (rgch, "%08lX", sc);
  695.     return rgch;
  696. }
  697.  
  698. char * EXPORTDBG __cdecl
  699. SzDecodeUlPropTypeFn(unsigned long ulPropType)
  700. {
  701.     static char rgch[8];
  702.  
  703.     switch (ulPropType)
  704.     {
  705.     case PT_UNSPECIFIED:    return("PT_UNSPECIFIED");   break;
  706.     case PT_NULL:           return("PT_NULL");          break;
  707.     case PT_I2:             return("PT_I2");            break;
  708.     case PT_LONG:           return("PT_LONG");          break;
  709.     case PT_R4:             return("PT_R4");            break;
  710.     case PT_DOUBLE:         return("PT_DOUBLE");        break;
  711.     case PT_CURRENCY:       return("PT_CURRENCY");      break;
  712.     case PT_APPTIME:        return("PT_APPTIME");       break;
  713.     case PT_ERROR:          return("PT_ERROR");         break;
  714.     case PT_BOOLEAN:        return("PT_BOOLEAN");       break;
  715.     case PT_OBJECT:         return("PT_OBJECT");        break;
  716.     case PT_I8:             return("PT_I8");            break;
  717.     case PT_STRING8:        return("PT_STRING8");       break;
  718.     case PT_UNICODE:        return("PT_UNICODE");       break;
  719.     case PT_SYSTIME:        return("PT_SYSTIME");       break;
  720.     case PT_CLSID:          return("PT_CLSID");         break;
  721.     case PT_BINARY:         return("PT_BINARY");        break;
  722.     }
  723.  
  724.     wsprintfA(rgch, "0x%04lX", ulPropType);
  725.     return rgch;
  726. }
  727.  
  728. char *  EXPORTDBG __cdecl
  729. SzDecodeUlPropTagFn(unsigned long ulPropTag)
  730. {
  731.     static char rgch[64];
  732.  
  733.     #if !defined(DOS)
  734.     int ipt;
  735.     for (ipt = 0; ipt < cpt; ++ipt)
  736.         if (ulPropTag == rgpt[ipt].ulPropTag)
  737.             return rgpt[ipt].psz;
  738.     #endif
  739.  
  740.     wsprintfA(rgch, "PROP_TAG(%s, 0x%04lX)",
  741.         SzDecodeUlPropType(PROP_TYPE(ulPropTag)),
  742.         PROP_ID(ulPropTag));
  743.     return rgch;
  744. }
  745.  
  746. SCODE  EXPORTDBG __cdecl
  747. ScodeFromSzFn(char *psz)
  748. {
  749.     #if !defined(DOS)
  750.     int isc;
  751.     for (isc = 0; isc < csc; ++isc)
  752.         {
  753.         if (lstrcmpA(psz, rgsc[isc].psz) == 0)
  754.             {
  755.             return rgsc[isc].sc;
  756.             }
  757.         }
  758.     #endif
  759.     return 0;
  760. }
  761.  
  762. unsigned long EXPORTDBG __cdecl
  763. UlPropTagFromSzFn(char *psz)
  764. {
  765.     #if !defined(DOS)
  766.     int ipt;
  767.     for (ipt = 0; ipt < cpt; ++ipt)
  768.         {
  769.         if (lstrcmpA(psz, rgpt[ipt].psz) == 0)
  770.             {
  771.             return rgpt[ipt].ulPropTag;
  772.             }
  773.         }
  774.     #endif
  775.     return 0;
  776. }
  777.  
  778. /* ScCheckScFn -------------------------------------------------------------- */
  779.  
  780. #if !defined(DOS)
  781.  
  782. SCODE EXPORTDBG __cdecl ScCheckScFn(    SCODE   sc,
  783.                     SCODE * lpscLegal,
  784.                     char *  lpszMethod,
  785.                     char *  lpszFile,
  786.                     int     iLine)
  787. {
  788.     BOOL fIsQueryInterface = (lpscLegal == IUnknown_QueryInterface_Scodes);
  789.  
  790.     if (sc == S_OK)
  791.         return(sc);
  792.  
  793.     while( *lpscLegal != S_OK && sc != *lpscLegal )
  794.     {
  795.         lpscLegal++;
  796.     }
  797.  
  798.     if ( *lpscLegal == S_OK )
  799.     {
  800.         SCODE *lpscNextCommon = Common_Scodes;
  801.  
  802.         /* see if this is a common scode */
  803.             if ( !fIsQueryInterface )
  804.                 while(  *lpscNextCommon != S_OK &&
  805.                         sc != *lpscNextCommon )
  806.                 {
  807.                     lpscNextCommon++;
  808.                 }
  809.  
  810.         /* this is an illegal error or an RPC error */
  811.            if ( (*lpscNextCommon == S_OK || fIsQueryInterface) &&
  812.                 ( SCODE_FACILITY(sc) != FACILITY_RPC) )
  813.            {
  814.                 DebugTrace( "Unrecognized scode %s from %s\n\t in file %s line %d\n",
  815.                         SzDecodeScode( sc ), lpszMethod, lpszFile, iLine);
  816.             }
  817.     }
  818.  
  819.     return(sc);
  820. }
  821. #endif
  822.  
  823. /* SCODE lists -------------------------------------------------------------- */
  824.  
  825. #if !defined(DOS)
  826.  
  827. #define STANDARD_OPENENTRY_SCODES \
  828.     E_NOINTERFACE,  \
  829.     MAPI_E_NOT_FOUND
  830.  
  831. SCODE BASED_DEBUG Common_Scodes[] =
  832. {
  833.     MAPI_E_BAD_CHARWIDTH,
  834.     MAPI_E_CALL_FAILED,
  835.     MAPI_E_INVALID_ENTRYID,
  836.     MAPI_E_INVALID_OBJECT,
  837.     MAPI_E_INVALID_PARAMETER,
  838.     MAPI_E_NO_ACCESS,
  839.     MAPI_E_NO_SUPPORT,
  840.     MAPI_E_NOT_ENOUGH_MEMORY,
  841.     MAPI_E_UNKNOWN_FLAGS,
  842.     S_OK
  843. };
  844.  
  845. SCODE BASED_DEBUG MAPILogon_Scodes[] =
  846. {
  847.     MAPI_E_NOT_INITIALIZED,
  848.     MAPI_E_LOGON_FAILED,
  849.     S_OK
  850. };
  851.  
  852. SCODE BASED_DEBUG MAPIAllocateBuffer_Scodes[] =
  853. {
  854.     MAPI_E_NOT_INITIALIZED,
  855.     S_OK
  856. };
  857.  
  858. SCODE BASED_DEBUG MAPIAllocateMore_Scodes[] =
  859. {
  860.     MAPI_E_NOT_INITIALIZED,
  861.     S_OK
  862. };
  863.  
  864. SCODE BASED_DEBUG MAPIFreeBuffer_Scodes[] =
  865. {
  866.     S_OK
  867. };
  868.  
  869. SCODE BASED_DEBUG IUnknown_QueryInterface_Scodes[] =
  870. {
  871.     E_INVALIDARG,
  872.     E_NOINTERFACE,
  873.     S_OK
  874. };
  875.  
  876. SCODE BASED_DEBUG IUnknown_GetLastError_Scodes[] =
  877. {
  878.     MAPI_E_EXTENDED_ERROR,
  879.     S_OK
  880. };
  881.  
  882. SCODE BASED_DEBUG IMAPIProp_CopyTo_Scodes[] =
  883. {
  884.     MAPI_W_ERRORS_RETURNED,
  885.     MAPI_E_INVALID_TYPE,
  886.     MAPI_E_FOLDER_CYCLE,
  887.     MAPI_E_DECLINE_COPY,
  888.     E_NOINTERFACE,
  889.     S_OK
  890. };
  891.  
  892. SCODE BASED_DEBUG IMAPIProp_CopyProps_Scodes[] =
  893. {
  894.     MAPI_W_ERRORS_RETURNED,
  895.     MAPI_W_PARTIAL_COMPLETION,
  896.     MAPI_E_INVALID_TYPE,
  897.     MAPI_E_FOLDER_CYCLE,
  898.     MAPI_E_DECLINE_COPY,
  899.     E_NOINTERFACE,
  900.     S_OK
  901. };
  902.  
  903. SCODE BASED_DEBUG IMAPIProp_DeleteProps_Scodes[] =
  904. {
  905.     MAPI_W_ERRORS_RETURNED,
  906.     MAPI_E_INVALID_TYPE,
  907.     S_OK
  908. };
  909.  
  910. SCODE BASED_DEBUG IMAPIProp_GetIDsFromNames_Scodes[] =
  911. {
  912.     MAPI_W_ERRORS_RETURNED,
  913.     MAPI_E_TABLE_TOO_BIG,
  914.     S_OK
  915. };
  916.  
  917. SCODE BASED_DEBUG IMAPIProp_GetLastError_Scodes[] =
  918. {
  919.     MAPI_E_EXTENDED_ERROR,
  920.     S_OK
  921. };
  922.  
  923. SCODE BASED_DEBUG IMAPIProp_GetNamesFromIDs_Scodes[] =
  924. {
  925.     MAPI_W_ERRORS_RETURNED,
  926.     S_OK
  927. };
  928.  
  929. SCODE BASED_DEBUG IMAPIProp_GetPropList_Scodes[] =
  930. {
  931.     MAPI_W_ERRORS_RETURNED,
  932.     S_OK
  933. };
  934.  
  935. SCODE BASED_DEBUG IMAPIProp_GetProps_Scodes[] =
  936. {
  937.     MAPI_E_NOT_FOUND,
  938.     MAPI_E_OBJECT_DELETED,
  939.     MAPI_W_ERRORS_RETURNED,
  940.     S_OK
  941. };
  942.  
  943. SCODE BASED_DEBUG IMAPIProp_OpenProperty_Scodes[] =
  944. {
  945.     MAPI_E_INTERFACE_NOT_SUPPORTED,
  946.     MAPI_E_NOT_FOUND,
  947.     MAPI_E_OBJECT_DELETED,
  948.     S_OK
  949. };
  950.  
  951. SCODE BASED_DEBUG IMAPIProp_SetProps_Scodes[] =
  952. {
  953.     MAPI_E_COMPUTED,
  954.     MAPI_E_UNEXPECTED_TYPE,
  955.     MAPI_E_INVALID_TYPE,
  956.     S_OK
  957. };
  958.  
  959. SCODE BASED_DEBUG IMAPIProp_SaveChanges_Scodes[] =
  960. {
  961.     MAPI_E_NOT_ENOUGH_DISK,
  962.     MAPI_E_OBJECT_CHANGED,
  963.     MAPI_E_OBJECT_DELETED,
  964.     S_OK
  965. };
  966.  
  967. SCODE BASED_DEBUG IStream_Read_Scodes[] = {S_OK};
  968. SCODE BASED_DEBUG IStream_Write_Scodes[] = {S_OK};
  969. SCODE BASED_DEBUG IStream_Seek_Scodes[] = {S_OK};
  970. SCODE BASED_DEBUG IStream_SetSize_Scodes[] = {S_OK};
  971. SCODE BASED_DEBUG IStream_Tell_Scodes[] = {S_OK};
  972. SCODE BASED_DEBUG IStream_LockRegion_Scodes[] = {S_OK};
  973. SCODE BASED_DEBUG IStream_UnlockRegion_Scodes[] = {S_OK};
  974. SCODE BASED_DEBUG IStream_Clone_Scodes[] = {S_OK};
  975. SCODE BASED_DEBUG IStream_CopyTo_Scodes[] = {S_OK};
  976. SCODE BASED_DEBUG IStream_Revert_Scodes[] = {S_OK};
  977. SCODE BASED_DEBUG IStream_Stat_Scodes[] = {S_OK};
  978. SCODE BASED_DEBUG IStream_Commit_Scodes[] = {S_OK};
  979.  
  980. SCODE BASED_DEBUG IMAPITable_GetLastError_Scodes[] = {S_OK};
  981. SCODE BASED_DEBUG IMAPITable_Advise_Scodes[] =
  982. {
  983.     S_OK
  984. };
  985. SCODE BASED_DEBUG IMAPITable_Unadvise_Scodes[] = {S_OK};
  986. SCODE BASED_DEBUG IMAPITable_GetStatus_Scodes[] = {S_OK};
  987. SCODE BASED_DEBUG IMAPITable_SetColumns_Scodes[] =
  988. {
  989.     MAPI_E_BUSY,
  990.     S_OK
  991. };
  992. SCODE BASED_DEBUG IMAPITable_QueryColumns_Scodes[] =
  993. {
  994.     MAPI_E_BUSY,
  995.     S_OK
  996. };
  997. SCODE BASED_DEBUG IMAPITable_GetRowCount_Scodes[] =
  998. {
  999.     MAPI_E_BUSY,
  1000.     MAPI_W_APPROX_COUNT,
  1001.     S_OK
  1002. };
  1003. SCODE BASED_DEBUG IMAPITable_SeekRow_Scodes[] =
  1004. {
  1005.     MAPI_E_INVALID_BOOKMARK,
  1006.     MAPI_E_UNABLE_TO_COMPLETE,
  1007.     MAPI_W_POSITION_CHANGED,
  1008.     S_OK
  1009. };
  1010. SCODE BASED_DEBUG IMAPITable_SeekRowApprox_Scodes[] = {S_OK};
  1011. SCODE BASED_DEBUG IMAPITable_QueryPosition_Scodes[] = {S_OK};
  1012. SCODE BASED_DEBUG IMAPITable_FindRow_Scodes[] =
  1013. {
  1014.     MAPI_E_INVALID_BOOKMARK,
  1015.     MAPI_E_NOT_FOUND,
  1016.     MAPI_W_POSITION_CHANGED,
  1017.     S_OK
  1018. };
  1019. SCODE BASED_DEBUG IMAPITable_Restrict_Scodes[] =
  1020. {
  1021.     MAPI_E_BUSY,
  1022.     S_OK
  1023. };
  1024. SCODE BASED_DEBUG IMAPITable_CreateBookmark_Scodes[] =
  1025. {
  1026.     MAPI_E_UNABLE_TO_COMPLETE,
  1027.     S_OK
  1028. };
  1029. SCODE BASED_DEBUG IMAPITable_FreeBookmark_Scodes[] = {S_OK};
  1030. SCODE BASED_DEBUG IMAPITable_SortTable_Scodes[] =
  1031. {
  1032.     MAPI_E_TOO_COMPLEX,
  1033.     S_OK
  1034. };
  1035. SCODE BASED_DEBUG IMAPITable_QuerySortOrder_Scodes[] = {S_OK};
  1036. SCODE BASED_DEBUG IMAPITable_QueryRows_Scodes[] =
  1037. {
  1038.     MAPI_E_INVALID_BOOKMARK,
  1039.     MAPI_W_POSITION_CHANGED,
  1040.     S_OK
  1041. };
  1042.  
  1043. SCODE BASED_DEBUG IMAPITable_Abort_Scodes[] =
  1044. {
  1045.     MAPI_E_UNABLE_TO_ABORT,
  1046.     S_OK
  1047. };
  1048. SCODE BASED_DEBUG IMAPITable_ExpandRow_Scodes[] = {S_OK};
  1049. SCODE BASED_DEBUG IMAPITable_CollapseRow_Scodes[] = {S_OK};
  1050. SCODE BASED_DEBUG IMAPITable_WaitForCompletion_Scodes[] =
  1051. {
  1052.     MAPI_E_TIMEOUT,
  1053.     S_OK
  1054. };
  1055. SCODE BASED_DEBUG IMAPITable_GetCollapseState_Scodes[] = {S_OK};
  1056. SCODE BASED_DEBUG IMAPITable_SetCollapseState_Scodes[] = {S_OK};
  1057.  
  1058.  
  1059. SCODE BASED_DEBUG IMAPISession_LogOff_Scodes[] = {S_OK};
  1060. SCODE BASED_DEBUG IMAPISession_Release_Scodes[] = {S_OK};
  1061. SCODE BASED_DEBUG IMAPISession_GetLastError_Scodes[] =
  1062. {
  1063.     MAPI_E_EXTENDED_ERROR,
  1064.     S_OK
  1065. };
  1066. SCODE BASED_DEBUG IMAPISession_GetMsgStoresTable_Scodes[] = {S_OK};
  1067. SCODE BASED_DEBUG IMAPISession_GetStatusTable_Scodes[] = {S_OK};
  1068. SCODE BASED_DEBUG IMAPISession_OpenMsgStore_Scodes[] = {S_OK};
  1069. SCODE BASED_DEBUG IMAPISession_OpenAddressBook_Scodes[] = {S_OK};
  1070.  
  1071. SCODE BASED_DEBUG IMAPISession_OpenEntry_Scodes[] =
  1072. {
  1073.     STANDARD_OPENENTRY_SCODES,
  1074.     S_OK
  1075. };
  1076.  
  1077. SCODE BASED_DEBUG IMAPISession_OpenProfileSection_Scodes[] = {S_OK};
  1078. SCODE BASED_DEBUG IMAPISession_Advise_Scodes[] = {S_OK};
  1079. SCODE BASED_DEBUG IMAPISession_Unadvise_Scodes[] = {S_OK};
  1080. SCODE BASED_DEBUG IMAPISession_CompareEntryIDs_Scodes[] = {S_OK};
  1081. SCODE BASED_DEBUG IMAPISession_MessageOptions_Scodes[] = {S_OK};
  1082. SCODE BASED_DEBUG IMAPISession_QueryDefaultMessageOpt_Scodes[] = {S_OK};
  1083. SCODE BASED_DEBUG IMAPISession_EnumAdrTypes_Scodes[] = {S_OK};
  1084. SCODE BASED_DEBUG IMAPISession_QueryIdentity_Scodes[] = {S_OK};
  1085.  
  1086. SCODE BASED_DEBUG IMsgStore_OpenEntry_Scodes[] =
  1087. {
  1088.     STANDARD_OPENENTRY_SCODES,
  1089.     MAPI_E_SUBMITTED,
  1090.     S_OK
  1091. };
  1092.  
  1093. SCODE BASED_DEBUG IMsgStore_SetReceiveFolder_Scodes[] =
  1094. {
  1095.     MAPI_E_BAD_CHARWIDTH,
  1096.     MAPI_E_NOT_FOUND,
  1097.     S_OK
  1098. };
  1099.  
  1100. SCODE BASED_DEBUG IMsgStore_GetReceiveFolder_Scodes[] =
  1101. {
  1102.     MAPI_E_BAD_CHARWIDTH,
  1103.     S_OK
  1104. };
  1105.  
  1106. SCODE BASED_DEBUG IMsgStore_GetReceiveFolderTable_Scodes[] = {S_OK};
  1107. SCODE BASED_DEBUG IMsgStore_StoreLogoff_Scodes[] = {S_OK};
  1108. SCODE BASED_DEBUG IMsgStore_Advise_Scodes[] = {S_OK};
  1109. SCODE BASED_DEBUG IMsgStore_Unadvise_Scodes[] = {S_OK};
  1110. SCODE BASED_DEBUG IMsgStore_CompareEntryIDs_Scodes[] = {S_OK};
  1111. SCODE BASED_DEBUG IMsgStore_GetOutgoingQueue_Scodes[] = {
  1112.     MAPI_E_NO_SUPPORT,
  1113.     S_OK};
  1114. SCODE BASED_DEBUG IMsgStore_SetLockState_Scodes[] = {
  1115.     MAPI_E_NO_SUPPORT,
  1116.     MAPI_E_NOT_FOUND,
  1117.     S_OK};
  1118. SCODE BASED_DEBUG IMsgStore_FinishedMsg_Scodes[] = {
  1119.     MAPI_E_NO_SUPPORT,
  1120.     S_OK};
  1121. SCODE BASED_DEBUG IMsgStore_AbortSubmit_Scodes[] = {
  1122.     MAPI_E_UNABLE_TO_ABORT,
  1123.     MAPI_E_NOT_IN_QUEUE,
  1124.     S_OK};
  1125. SCODE BASED_DEBUG IMsgStore_NotifyNewMail_Scodes[] = {S_OK};
  1126.  
  1127. SCODE BASED_DEBUG IMAPIFolder_GetContentsTable_Scodes[] =
  1128. {
  1129.     MAPI_E_OBJECT_DELETED,
  1130.     S_OK
  1131. };
  1132.  
  1133. SCODE BASED_DEBUG IMAPIFolder_GetHierarchyTable_Scodes[] =
  1134. {
  1135.     MAPI_E_OBJECT_DELETED,
  1136.     S_OK
  1137. };
  1138.  
  1139. SCODE BASED_DEBUG IMAPIFolder_SaveContentsSort_Scodes[] =
  1140. {
  1141.     S_OK
  1142. };
  1143.  
  1144. SCODE BASED_DEBUG IMAPIFolder_OpenEntry_Scodes[] =
  1145. {
  1146.     STANDARD_OPENENTRY_SCODES,
  1147.     MAPI_E_SUBMITTED,
  1148.     S_OK
  1149. };
  1150.  
  1151. SCODE BASED_DEBUG IMAPIFolder_CreateMessage_Scodes[] =
  1152. {
  1153.     E_NOINTERFACE,
  1154.     S_OK
  1155. };
  1156.  
  1157. SCODE BASED_DEBUG IMAPIFolder_CopyMessages_Scodes[] =
  1158. {
  1159.     E_NOINTERFACE,
  1160.     MAPI_E_SUBMITTED,
  1161.     MAPI_E_DECLINE_COPY,
  1162.     S_OK
  1163. };
  1164.  
  1165. SCODE BASED_DEBUG IMAPIFolder_DeleteMessages_Scodes[] =
  1166. {
  1167.     MAPI_E_SUBMITTED,
  1168.     S_OK
  1169. };
  1170.  
  1171. SCODE BASED_DEBUG IMAPIFolder_CreateFolder_Scodes[] =
  1172. {
  1173.     E_NOINTERFACE,
  1174.     MAPI_E_COLLISION,
  1175.     S_OK
  1176. };
  1177.  
  1178. SCODE BASED_DEBUG IMAPIFolder_CopyFolder_Scodes[] =
  1179. {
  1180.     E_NOINTERFACE,
  1181.     MAPI_E_COLLISION,
  1182.     MAPI_E_FOLDER_CYCLE,
  1183.     MAPI_E_DECLINE_COPY,
  1184.     S_OK
  1185. };
  1186.  
  1187. SCODE BASED_DEBUG IMAPIFolder_DeleteFolder_Scodes[] =
  1188. {
  1189.     MAPI_E_HAS_FOLDERS,
  1190.     MAPI_E_HAS_MESSAGES,
  1191.     MAPI_E_SUBMITTED,
  1192.     S_OK
  1193. };
  1194.  
  1195. SCODE BASED_DEBUG IMAPIFolder_SetSearchCriteria_Scodes[] =
  1196. {
  1197.     S_OK
  1198. };
  1199.  
  1200. SCODE BASED_DEBUG IMAPIFolder_GetSearchCriteria_Scodes[] =
  1201. {
  1202.     MAPI_E_NOT_INITIALIZED,
  1203.     MAPI_E_CORRUPT_STORE,
  1204.     S_OK
  1205. };
  1206.  
  1207. SCODE BASED_DEBUG IMAPIFolder_SetReadFlags_Scodes[] =
  1208. {
  1209.     S_OK
  1210. };
  1211.  
  1212. SCODE BASED_DEBUG IMAPIFolder_GetMessageStatus_Scodes[] =
  1213. {
  1214.     S_OK
  1215. };
  1216.  
  1217. SCODE BASED_DEBUG IMAPIFolder_SetMessageStatus_Scodes[] =
  1218. {
  1219.     S_OK
  1220. };
  1221.  
  1222. SCODE BASED_DEBUG IMAPIFolder_EmptyFolder_Scodes[] =
  1223. {
  1224.     MAPI_E_SUBMITTED,
  1225.     S_OK
  1226. };
  1227.  
  1228. SCODE BASED_DEBUG IMessage_GetAttachmentTable_Scodes[] =
  1229. {
  1230.     S_OK
  1231. };
  1232.  
  1233. SCODE BASED_DEBUG IMessage_OpenAttach_Scodes[] =
  1234. {
  1235.     MAPI_E_NOT_FOUND,
  1236.     E_NOINTERFACE,
  1237.     S_OK
  1238. };
  1239.  
  1240. SCODE BASED_DEBUG IMessage_CreateAttach_Scodes[] =
  1241. {
  1242.     E_NOINTERFACE,
  1243.     S_OK
  1244. };
  1245.  
  1246. SCODE BASED_DEBUG IMessage_DeleteAttach_Scodes[] =
  1247. {
  1248.     S_OK
  1249. };
  1250.  
  1251. SCODE BASED_DEBUG IMessage_GetRecipientTable_Scodes[] =
  1252. {
  1253.     S_OK
  1254. };
  1255.  
  1256. SCODE BASED_DEBUG IMessage_ModifyRecipients_Scodes[] =
  1257. {
  1258.     MAPI_E_NOT_FOUND,
  1259.     S_OK
  1260. };
  1261.  
  1262. SCODE BASED_DEBUG IMessage_SubmitMessage_Scodes[] =
  1263. {
  1264.     MAPI_E_NO_RECIPIENTS,
  1265.     MAPI_E_NON_STANDARD,
  1266.     S_OK
  1267. };
  1268.  
  1269. SCODE BASED_DEBUG IMessage_SetReadFlag_Scodes[] =
  1270. {
  1271.     S_OK
  1272. };
  1273.  
  1274. SCODE BASED_DEBUG IAttach_SaveChanges_Scodes[] =
  1275. {
  1276.     S_OK
  1277. };
  1278.  
  1279. SCODE BASED_DEBUG IAddrBook_OpenEntry_Scodes[] =
  1280. {
  1281.     STANDARD_OPENENTRY_SCODES,
  1282.     S_OK
  1283. };
  1284.  
  1285. SCODE BASED_DEBUG IAddrBook_CompareEntryIDs_Scodes[] = {S_OK};
  1286. SCODE BASED_DEBUG IAddrBook_CreateOneOff_Scodes[] = {S_OK};
  1287. SCODE BASED_DEBUG IAddrBook_ResolveName_Scodes[] = {S_OK};
  1288. SCODE BASED_DEBUG IAddrBook_Address_Scodes[] = {S_OK};
  1289. SCODE BASED_DEBUG IAddrBook_Details_Scodes[] = {S_OK};
  1290. SCODE BASED_DEBUG IAddrBook_RecipOptions_Scodes[] = {S_OK};
  1291. SCODE BASED_DEBUG IAddrBook_QueryDefaultRecipOpt_Scodes[] = {S_OK};
  1292. SCODE BASED_DEBUG IAddrBook_ButtonPress_Scodes[] = {S_OK};
  1293. SCODE BASED_DEBUG IABContainer_GetContentsTable_Scodes[] = {S_OK};
  1294. SCODE BASED_DEBUG IABContainer_GetHierarchyTable_Scodes[] = {S_OK};
  1295. SCODE BASED_DEBUG INotifObj_ChangeEvMask_Scodes[] = {S_OK};
  1296. SCODE BASED_DEBUG IMAPIStatus_ChangePassword_Scodes[] = {S_OK};
  1297. SCODE BASED_DEBUG IMAPIStatus_FlushQueues_Scodes[] = {S_OK};
  1298. SCODE BASED_DEBUG IMAPIStatus_SettingsDialog_Scodes[] = {S_OK};
  1299. SCODE BASED_DEBUG IMAPIStatus_ValidateState_Scodes[] = {S_OK};
  1300. SCODE BASED_DEBUG SMAPI_MAPILogon_Scodes[] = {
  1301.     MAPI_E_LOGON_FAILED,
  1302.     S_OK};
  1303. SCODE BASED_DEBUG SMAPI_MAPILogoff_Scodes[] = {S_OK};
  1304. SCODE BASED_DEBUG SMAPI_MAPIFreeBuffer_Scodes[] = {S_OK};
  1305. SCODE BASED_DEBUG SMAPI_MAPISendMail_Scodes[] = {S_OK};
  1306. SCODE BASED_DEBUG SMAPI_MAPISendDocuments_Scodes[] = {S_OK};
  1307. SCODE BASED_DEBUG SMAPI_MAPIFindNext_Scodes[] = {S_OK};
  1308. SCODE BASED_DEBUG SMAPI_MAPIReadMail_Scodes[] = {S_OK};
  1309. SCODE BASED_DEBUG SMAPI_MAPISaveMail_Scodes[] = {S_OK};
  1310. SCODE BASED_DEBUG SMAPI_MAPIDeleteMail_Scodes[] = {S_OK};
  1311. SCODE BASED_DEBUG SMAPI_MAPIAddress_Scodes[] = {S_OK};
  1312. SCODE BASED_DEBUG SMAPI_MAPIResolveName_Scodes[] = {S_OK};
  1313. SCODE BASED_DEBUG SMAPI_MAPIDetails_Scodes[] = {S_OK};
  1314.  
  1315. SCODE BASED_DEBUG IMSProvider_Logon_Scodes[] = {
  1316.     MAPI_E_UNCONFIGURED,
  1317.     MAPI_E_FAILONEPROVIDER,
  1318.     MAPI_E_STRING_TOO_LONG,
  1319.     MAPI_E_LOGON_FAILED,
  1320.     MAPI_E_CORRUPT_STORE,
  1321.     MAPI_E_USER_CANCEL,
  1322.     S_OK};
  1323. SCODE BASED_DEBUG IMSProvider_Deinit_Scodes[] = {
  1324.     S_OK};
  1325. SCODE BASED_DEBUG IMSProvider_Shutdown_Scodes[] = {
  1326.     S_OK};
  1327.  
  1328. SCODE BASED_DEBUG IMSProvider_Init_Scodes[] = {
  1329.     MAPI_E_VERSION,
  1330.     S_OK};
  1331. SCODE BASED_DEBUG IMSProvider_SpoolerLogon_Scodes[] = {
  1332.     MAPI_E_LOGON_FAILED,
  1333.     S_OK};
  1334.  
  1335. SCODE BASED_DEBUG IMSLogon_OpenEntry_Scodes[] =
  1336. {
  1337.     STANDARD_OPENENTRY_SCODES,
  1338.     S_OK
  1339. };
  1340.  
  1341. SCODE BASED_DEBUG IMSLogon_OpenStatusEntry_Scodes[] = {
  1342.     S_OK};
  1343.  
  1344. SCODE BASED_DEBUG IMSLogon_CompareEntryIDs_Scodes[] = {
  1345.     S_OK};
  1346.  
  1347. SCODE BASED_DEBUG IMSLogon_Advise_Scodes[] = {
  1348.     S_OK};
  1349. SCODE BASED_DEBUG IMSLogon_Unadvise_Scodes[] = {
  1350.     S_OK};
  1351. SCODE BASED_DEBUG IMSLogon_Logoff_Scodes[] = {
  1352.     S_OK};
  1353. #endif
  1354.  
  1355. /* DBGMEM ------------------------------------------------------------------- */
  1356.  
  1357. #undef  INTERFACE
  1358. #define INTERFACE struct _DBGMEM
  1359. DECLARE_INTERFACE(DBGMEM_)
  1360. {
  1361.     BEGIN_INTERFACE
  1362.     STDMETHOD(QueryInterface)       (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE; \
  1363.     STDMETHOD_(ULONG,AddRef)        (THIS) PURE; \
  1364.     STDMETHOD_(ULONG,Release)       (THIS) PURE; \
  1365.     STDMETHOD_(void FAR*, Alloc)    (THIS_ ULONG cb) PURE; \
  1366.     STDMETHOD_(void FAR*, Realloc)  (THIS_ void FAR* pv, ULONG cb) PURE; \
  1367.     STDMETHOD_(void, Free)          (THIS_ void FAR* pv) PURE; \
  1368.     STDMETHOD_(ULONG, GetSize)      (THIS_ void FAR* pv) PURE; \
  1369.     STDMETHOD_(int, DidAlloc)       (THIS_ void FAR* pv) PURE; \
  1370.     STDMETHOD_(void, HeapMinimize)  (THIS) PURE; \
  1371. };
  1372.  
  1373. extern DBGMEM_Vtbl vtblDBGMEM;
  1374.  
  1375. typedef struct _DBGMEM  DBGMEM,  FAR *PDBGMEM;
  1376. typedef struct _BLK     BLK,     *PBLK;
  1377. typedef struct _BLKTAIL BLKTAIL, *PBLKTAIL;
  1378.  
  1379. struct _DBGMEM {
  1380.     DBGMEM_Vtbl *       lpVtbl;
  1381.     ULONG               cRef;
  1382.     LPMALLOC            pmalloc;
  1383.     char                szSubsys[16];
  1384.     ULONG               ulAllocNum;
  1385.     ULONG               ulAllocAt;
  1386.     ULONG               ulFailureAt;
  1387.     BOOL                fCheckOften;
  1388.     BOOL                fUnleakable;
  1389.     ULONG               cbVirtual;
  1390.     BOOL                fFillRandom;
  1391.     int                 cbExtra;
  1392.     int                 cbTail;
  1393.     PBLK                pblkHead;
  1394. #if defined(WIN32) && defined(_X86_)
  1395.     CRITICAL_SECTION    cs;
  1396. #endif
  1397. };
  1398.  
  1399. #define NCALLERS    12
  1400.  
  1401. struct _BLK {
  1402.     PDBGMEM         pdbgmem;        /* pointer to the allocator */
  1403.     PBLK            pblkNext;       /* next link in chain of allocated blocks */
  1404.     PBLK            pblkPrev;       /* prev link in chain of allocated blocks */
  1405.     ULONG           ulAllocNum;     /* internal allocation number */
  1406.     BOOL            fUnleakable;    /* TRUE if leak code should ignore block */
  1407.     #if defined(WIN32) && defined(_X86_)
  1408.     FARPROC         pfnCallers[NCALLERS];
  1409.     #endif
  1410.     PBLKTAIL        pblktail;       /* pointer to block tail */
  1411. };
  1412.  
  1413. struct _BLKTAIL {
  1414.     PBLK            pblk;           /* pointer back to beginning of the block */
  1415. };
  1416.  
  1417. #define PblkToPv(pblk)          ((LPVOID)((PBLK)(pblk) + 1))
  1418. #define PvToPblk(pblk)          ((PBLK)(pv) - 1)
  1419. #define PblkClientSize(pblk)    ((ULONG)((char *)(pblk)->pblktail - (char *)PblkToPv(pblk)))
  1420. #define PblkAllocSize(pblk)     (PblkClientSize(pblk) + sizeof(BLK) + (pblk)->pdbgmem->cbTail)
  1421.  
  1422. #if defined(WIN32) && defined(_X86_)
  1423. #define DBGMEM_EnterCriticalSection(pdbgmem)    \
  1424.         EnterCriticalSection(&(pdbgmem)->cs)
  1425. #define DBGMEM_LeaveCriticalSection(pdbgmem)    \
  1426.         LeaveCriticalSection(&(pdbgmem)->cs)
  1427. #else
  1428. #define DBGMEM_EnterCriticalSection(pdbgmem)
  1429. #define DBGMEM_LeaveCriticalSection(pdbgmem)
  1430. #endif
  1431.  
  1432. #define INITGUID
  1433. #include <initguid.h>
  1434.  
  1435. DEFINE_OLEGUID(DBGMEM_IID_IUnknown,     0x00000000L, 0, 0);
  1436. DEFINE_OLEGUID(DBGMEM_IID_IMalloc,      0x00000002L, 0, 0);
  1437. DEFINE_OLEGUID(DBGMEM_IID_IBaseMalloc,  0x000203FFL, 0, 0);
  1438.  
  1439. /* Forward Declarations ----------------------------------------------------- */
  1440.  
  1441. BOOL DBGMEM_ValidatePblk(PDBGMEM pdbgmem, PBLK pblk, char ** pszReason);
  1442. BOOL DBGMEM_ValidatePv(PDBGMEM pdbgmem, void * pv, char * pszFunc);
  1443. STDMETHODIMP_(void) DBGMEM_Free(PDBGMEM pdbgmem, void * pv);
  1444.  
  1445. /* Call Stack (WIN32) ------------------------------------------------------- */
  1446.  
  1447. #if defined(WIN32) && defined(_X86_)
  1448.  
  1449. #ifdef _WIN95
  1450. #define dwStackLimit    0x00400000      /*  4MB for Windows 95 */
  1451. #else
  1452. #define dwStackLimit    0x00010000      /*  64KB for NT */
  1453. #endif
  1454.  
  1455. void EXPORTDBG __cdecl GetCallStack(DWORD *pdwCaller, int cSkip, int cFind)
  1456. {
  1457.     DWORD * pdwStack;
  1458.     DWORD * pdwStackPrev = (DWORD *)0;
  1459.     DWORD   dwCaller;
  1460.  
  1461.     __asm mov pdwStack, ebp
  1462.  
  1463.     memset(pdwCaller, 0, cFind * sizeof(DWORD));
  1464.  
  1465.     while (cSkip + cFind > 0)
  1466.     {
  1467.         pdwStack = (DWORD *)*pdwStack;
  1468.  
  1469.         if (    pdwStack <= (DWORD *)dwStackLimit
  1470.             ||  pdwStackPrev >= pdwStack
  1471.             ||  IsBadReadPtr(pdwStack, 2 * sizeof(DWORD)))
  1472.             break;
  1473.  
  1474.         dwCaller = *(pdwStack + 1);
  1475.  
  1476.         if (dwCaller <= dwStackLimit)
  1477.             break;
  1478.         else if (cSkip > 0)
  1479.             cSkip -= 1;
  1480.         else
  1481.         {
  1482.             *pdwCaller++ = dwCaller;
  1483.             cFind -= 1;
  1484.  
  1485.             pdwStackPrev = pdwStack;
  1486.         }
  1487.     }
  1488. }
  1489.  
  1490. #endif
  1491.  
  1492. /* Virtual Memory Support (Win32) ------------------------------------------- */
  1493.  
  1494. #if defined(WIN32) && defined(_X86_)
  1495.  
  1496. #define PAGE_SIZE       4096
  1497. #define PvToVMBase(pv)  ((void *)((ULONG)pv & 0xFFFF0000))
  1498.  
  1499. BOOL VMValidatePvEx(void *pv, ULONG cbCluster)
  1500. {
  1501.     void *  pvBase;
  1502.     BYTE *  pb;
  1503.  
  1504.     pvBase = PvToVMBase(pv);
  1505.  
  1506.     pb = (BYTE *)pvBase + sizeof(ULONG);
  1507.  
  1508.     while (pb < (BYTE *)pv) {
  1509.         if (*pb++ != 0xAD) {
  1510.             TrapSz1("VMValidatePvEx(pv=%08lX): Block leader has been overwritten", pv);
  1511.             return(FALSE);
  1512.         }
  1513.     }
  1514.  
  1515.     if (cbCluster != 1)
  1516.     {
  1517.         ULONG cb = *((ULONG *)pvBase);
  1518.         ULONG cbPad = 0;
  1519.  
  1520.         if (cb % cbCluster)
  1521.             cbPad = (cbCluster - (cb % cbCluster));
  1522.  
  1523.         if (cbPad)
  1524.         {
  1525.             BYTE *pbMac;
  1526.  
  1527.             pb = (BYTE *)pv + cb;
  1528.             pbMac = pb + cbPad;
  1529.  
  1530.             while (pb < pbMac)
  1531.             {
  1532.                 if (*pb++ != 0xBC)
  1533.                 {
  1534.                     TrapSz1("VMValidatePvEx(pv=%08lX): Block trailer has been "
  1535.                         "overwritten", pv);
  1536.                     return(FALSE);
  1537.                 }
  1538.             }
  1539.         }
  1540.     }
  1541.  
  1542.     return(TRUE);
  1543. }
  1544.  
  1545. void * EXPORTDBG __cdecl VMAlloc(ULONG cb)
  1546. {
  1547.     return VMAllocEx(cb, 1);
  1548. }
  1549.  
  1550. void * EXPORTDBG __cdecl VMAllocEx(ULONG cb, ULONG cbCluster)
  1551. {
  1552.     ULONG   cbAlloc;
  1553.     void *  pvR;
  1554.     void *  pvC;
  1555.     ULONG   cbPad   = 0;
  1556.  
  1557.     // a cluster size of 0 means don't use the virtual allocator.
  1558.  
  1559.     AssertSz(cbCluster != 0, "Cluster size is zero.");
  1560.  
  1561.     if (cb > 0x100000)
  1562.         return(0);
  1563.  
  1564.     if (cb % cbCluster)
  1565.         cbPad = (cbCluster - (cb % cbCluster));
  1566.  
  1567.     cbAlloc = sizeof(ULONG) + cb + cbPad + PAGE_SIZE - 1;
  1568.     cbAlloc -= cbAlloc % PAGE_SIZE;
  1569.     cbAlloc += PAGE_SIZE;
  1570.  
  1571.     pvR = VirtualAlloc(0, cbAlloc, MEM_RESERVE, PAGE_NOACCESS);
  1572.  
  1573.     if (pvR == 0)
  1574.         return(0);
  1575.  
  1576.     pvC = VirtualAlloc(pvR, cbAlloc - PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
  1577.  
  1578.     if (pvC != pvR)
  1579.     {
  1580.         VirtualFree(pvR, 0, MEM_RELEASE);
  1581.         return(0);
  1582.     }
  1583.  
  1584.     *(ULONG *)pvC = cb;
  1585.  
  1586.     memset((BYTE *)pvC + sizeof(ULONG), 0xAD,
  1587.         (UINT) cbAlloc - cb - cbPad - sizeof(ULONG) - PAGE_SIZE);
  1588.  
  1589.     if (cbPad)
  1590.         memset((BYTE *)pvC + cbAlloc - PAGE_SIZE - cbPad, 0xBC,
  1591.             (UINT) cbPad);
  1592.  
  1593.     return((BYTE *)pvC + (cbAlloc - cb - cbPad - PAGE_SIZE));
  1594. }
  1595.  
  1596. void EXPORTDBG __cdecl VMFree(void *pv)
  1597. {
  1598.     VMFreeEx(pv, 1);
  1599. }
  1600.  
  1601. void EXPORTDBG __cdecl VMFreeEx(void *pv, ULONG cbCluster)
  1602. {
  1603.     VMValidatePvEx(pv, cbCluster);
  1604.  
  1605.     if (!VirtualFree(PvToVMBase(pv), 0, MEM_RELEASE))
  1606.         TrapSz2("VMFreeEx(pv=%08lX): VirtualFree failed (%08lX)",
  1607.             pv, GetLastError());
  1608. }
  1609.  
  1610. void * EXPORTDBG __cdecl VMRealloc(void *pv, ULONG cb)
  1611. {
  1612.     return VMReallocEx(pv, cb, 1);
  1613. }
  1614.  
  1615. void * EXPORTDBG __cdecl VMReallocEx(void *pv, ULONG cb, ULONG cbCluster)
  1616. {
  1617.     void *  pvNew = 0;
  1618.     ULONG   cbCopy;
  1619.  
  1620.     VMValidatePvEx(pv, cbCluster);
  1621.  
  1622.     cbCopy = *(ULONG *)PvToVMBase(pv);
  1623.     if (cbCopy > cb)
  1624.         cbCopy = cb;
  1625.  
  1626.     pvNew = VMAllocEx(cb, cbCluster);
  1627.  
  1628.     if (pvNew)
  1629.     {
  1630.         MemCopy(pvNew, pv, cbCopy);
  1631.         VMFreeEx(pv, cbCluster);
  1632.     }
  1633.  
  1634.     return(pvNew);
  1635. }
  1636.  
  1637. ULONG EXPORTDBG __cdecl VMGetSize(void *pv)
  1638. {
  1639.     return VMGetSizeEx(pv, 1);
  1640. }
  1641.  
  1642. ULONG EXPORTDBG __cdecl VMGetSizeEx(void *pv, ULONG cbCluster)
  1643. {
  1644.     return(*(ULONG *)PvToVMBase(pv));
  1645. }
  1646.  
  1647. #endif
  1648.  
  1649. /* Virtual Memory Support (WIN16) ------------------------------------------- */
  1650.  
  1651. #ifdef WIN16
  1652.  
  1653. #define PvToVMBase(pv)  ((void *)((ULONG)pv & 0xFFFF0000))
  1654.  
  1655. BOOL VMValidatePvEx(void *pv, ULONG cbCluster)
  1656. {
  1657.     void *  pvBase;
  1658.     BYTE *  pb;
  1659.  
  1660.     pvBase = PvToVMBase(pv);
  1661.  
  1662.     pb = (BYTE *)pvBase + sizeof(ULONG);
  1663.  
  1664.     while (pb < (BYTE *)pv) {
  1665.         if (*pb++ != 0xAD) {
  1666.             TrapSz1("VMValidatePvEx(pv=%08lX): Block leader has been overwritten", pv);
  1667.             return(FALSE);
  1668.         }
  1669.     }
  1670.  
  1671.     if (cbCluster != 1)
  1672.     {
  1673.         ULONG cb = *((ULONG *)pvBase);
  1674.         ULONG cbPad = 0;
  1675.  
  1676.         if (cb % cbCluster)
  1677.             cbPad = (cbCluster - (cb % cbCluster));
  1678.  
  1679.         if (cbPad)
  1680.         {
  1681.             BYTE *pbMac;
  1682.  
  1683.             pb = (BYTE *)pv + cb;
  1684.             pbMac = pb + cbPad;
  1685.  
  1686.             while (pb < pbMac)
  1687.             {
  1688.                 if (*pb++ != 0xBC)
  1689.                 {
  1690.                     TrapSz1("VMValidatePvEx(pv=%08lX): Block trailer has been "
  1691.                         "overwritten", pv);
  1692.                     return(FALSE);
  1693.                 }
  1694.             }
  1695.         }
  1696.     }
  1697.  
  1698.     return(TRUE);
  1699. }
  1700.  
  1701. BOOL VMValidatePv(void *pv)
  1702. {
  1703.     return VMValidatePvEx(pv, 1);
  1704. }
  1705.  
  1706. void * EXPORTDBG __cdecl VMAlloc(ULONG cb)
  1707. {
  1708.     return VMAllocEx(cb, 1);
  1709. }
  1710.  
  1711. void * EXPORTDBG __cdecl VMAllocEx(ULONG cb, ULONG cbCluster)
  1712. {
  1713.     HGLOBAL hGlobal;
  1714.     ULONG   cbAlloc;
  1715.     ULONG   cbAllocFromSys;
  1716.     void *  pvAlloc;
  1717.     ULONG   cbPad   = 0;
  1718.  
  1719.     if (cb > 0x10000 - sizeof(ULONG))
  1720.         return(0);
  1721.  
  1722.     if (cb % cbCluster)
  1723.         cbPad = (cbCluster - (cb % cbCluster));
  1724.  
  1725.     cbAlloc = sizeof(ULONG) + cb + cbPad;
  1726.  
  1727.     if (cbAlloc > 0x10000)
  1728.         return(0);
  1729.  
  1730. #ifdef SIMPLE_MAPI
  1731.     hGlobal = GlobalAlloc(GPTR | GMEM_SHARE, cbAlloc);
  1732. #else   
  1733.     hGlobal = GlobalAlloc(GPTR, cbAlloc);
  1734. #endif  
  1735.  
  1736.     if (hGlobal == 0)
  1737.         return(0);
  1738.  
  1739.     cbAllocFromSys = GlobalSize(hGlobal);
  1740.  
  1741.     Assert(cbAllocFromSys >= cbAlloc);
  1742.  
  1743.     cbAlloc = cbAllocFromSys;
  1744.  
  1745.     pvAlloc = GlobalLock(hGlobal);
  1746.  
  1747.     if (pvAlloc == 0) {
  1748.         GlobalFree(hGlobal);
  1749.         return(0);
  1750.     }
  1751.  
  1752.     Assert(((ULONG)pvAlloc & 0x0000FFFF) == 0);
  1753.  
  1754.     *(ULONG *)pvAlloc = cb;
  1755.  
  1756.     memset((BYTE *)pvAlloc + sizeof(ULONG), 0xAD,
  1757.         (size_t)(cbAlloc - cb - cbPad - sizeof(ULONG)));
  1758.  
  1759.     if (cbPad)
  1760.         memset((BYTE *)pvAlloc + cbAlloc - cbPad, 0xBC, (size_t) cbPad);
  1761.  
  1762.     return((BYTE *)pvAlloc + (cbAlloc - cb - cbPad));
  1763. }
  1764.  
  1765. void EXPORTDBG __cdecl VMFree(void *pv)
  1766. {
  1767.     VMFreeEx(pv, 1);
  1768. }
  1769.  
  1770. void EXPORTDBG __cdecl VMFreeEx(void *pv, ULONG cbCluster)
  1771. {
  1772.     if (VMValidatePvEx(pv, cbCluster))
  1773.     {
  1774.         HGLOBAL hGlobal;
  1775.         ULONG cb = *(ULONG *)PvToVMBase(pv);
  1776.  
  1777.         memset(pv, 0xFE, (size_t)cb);
  1778.  
  1779.         hGlobal = (HGLOBAL)((ULONG)pv >> 16);
  1780.         GlobalFree(hGlobal);
  1781.     }
  1782. }
  1783.  
  1784. void * EXPORTDBG __cdecl VMRealloc(void *pv, ULONG cb)
  1785. {
  1786.     return VMReallocEx(pv, cb, 1);
  1787. }
  1788.  
  1789. void * EXPORTDBG __cdecl VMReallocEx(void *pv, ULONG cb, ULONG cbCluster)
  1790. {
  1791.     void *  pvNew = 0;
  1792.     ULONG   cbCopy;
  1793.  
  1794.     if (VMValidatePvEx(pv, cbCluster)) {
  1795.         cbCopy = *(ULONG *)PvToVMBase(pv);
  1796.         if (cbCopy > cb)
  1797.             cbCopy = cb;
  1798.  
  1799.         pvNew = VMAllocEx(cb, cbCluster);
  1800.  
  1801.         if (pvNew) {
  1802.             MemCopy(pvNew, pv, (size_t)cbCopy);
  1803.             VMFreeEx(pv, cbCluster);
  1804.         }
  1805.     }
  1806.  
  1807.     return(pvNew);
  1808. }
  1809.  
  1810. ULONG EXPORTDBG __cdecl VMGetSize(void *pv)
  1811. {
  1812.     return VMGetSizeEx(pv, 1);
  1813. }
  1814.  
  1815. ULONG EXPORTDBG __cdecl VMGetSizeEx(void *pv, ULONG ulCluster)
  1816. {
  1817.     if (VMValidatePvEx(pv, ulCluster))
  1818.         return(*(ULONG *)PvToVMBase(pv));
  1819.  
  1820.     return(0);
  1821. }
  1822.  
  1823. #endif
  1824.  
  1825. /* Virtual Memory Support (Others) ------------------------------------------ */
  1826.  
  1827. #if !defined(WIN16) && (!defined(WIN32) || !defined(_X86_))
  1828. #define VMAlloc(cb)             0
  1829. #define VMAllocEx(cb, ul)       0
  1830. #define VMRealloc(pv, cb)       0
  1831. #define VMReallocEx(pv, cb, ul) 0
  1832. #define VMFree(pv)
  1833. #define VMFreeEx(pv, ul)
  1834. #define VMGetSize(pv)           0
  1835. #define VMGetSizeEx(pv, ul)     0
  1836. #endif
  1837.  
  1838. /* PblkEnqueue / PblkDequeue ------------------------------------------------ */
  1839.  
  1840. void PblkEnqueue(PBLK pblk)
  1841. {
  1842.     pblk->pblkNext          = pblk->pdbgmem->pblkHead;
  1843.     pblk->pblkPrev          = 0;
  1844.     pblk->pdbgmem->pblkHead = pblk;
  1845.  
  1846.     if (pblk->pblkNext)
  1847.         pblk->pblkNext->pblkPrev = pblk;
  1848.  
  1849. }
  1850.  
  1851. void PblkDequeue(PBLK pblk)
  1852. {
  1853.     if (pblk->pblkNext)
  1854.         pblk->pblkNext->pblkPrev = pblk->pblkPrev;
  1855.  
  1856.     if (pblk->pblkPrev)
  1857.         pblk->pblkPrev->pblkNext = pblk->pblkNext;
  1858.     else
  1859.         pblk->pdbgmem->pblkHead  = pblk->pblkNext;
  1860. }
  1861.  
  1862. /* QueryInterface/AddRef/Release -------------------------------------------- */
  1863.  
  1864. STDMETHODIMP DBGMEM_QueryInterface(PDBGMEM pdbgmem, REFIID riid, LPVOID FAR* ppvObj)
  1865. {
  1866.     if (memcmp(riid, &DBGMEM_IID_IBaseMalloc, sizeof(IID)) == 0) {
  1867.         pdbgmem->pmalloc->lpVtbl->AddRef(pdbgmem->pmalloc);
  1868.         *ppvObj = pdbgmem->pmalloc;
  1869.         return(0);
  1870.     }
  1871.  
  1872.     if (memcmp(riid, &DBGMEM_IID_IMalloc, sizeof(IID)) == 0 ||
  1873.         memcmp(riid, &DBGMEM_IID_IUnknown, sizeof(IID)) == 0) {
  1874.         ++pdbgmem->cRef;
  1875.         *ppvObj = pdbgmem;
  1876.         return(0);
  1877.     }
  1878.  
  1879.     *ppvObj = NULL; /* OLE requires zeroing [out] parameter */
  1880.     return(ResultFromScode(E_NOINTERFACE));
  1881. }
  1882.  
  1883. STDMETHODIMP_(ULONG) DBGMEM_AddRef(PDBGMEM pdbgmem)
  1884. {
  1885.     ULONG cRef;
  1886.  
  1887.     DBGMEM_EnterCriticalSection(pdbgmem);
  1888.     cRef = ++pdbgmem->cRef;
  1889.     DBGMEM_LeaveCriticalSection(pdbgmem);
  1890.  
  1891.     return(cRef);
  1892. }
  1893.  
  1894. STDMETHODIMP_(ULONG) DBGMEM_Release(PDBGMEM pdbgmem)
  1895. {
  1896.     ULONG       cRef;
  1897.     LPMALLOC    pmalloc;
  1898.  
  1899.     DBGMEM_EnterCriticalSection(pdbgmem);
  1900.     cRef = --pdbgmem->cRef;
  1901.     DBGMEM_LeaveCriticalSection(pdbgmem);
  1902.  
  1903.     if (cRef == 0) {
  1904.         DBGMEM_CheckMemFn(pdbgmem, TRUE);
  1905.         pmalloc = pdbgmem->pmalloc;
  1906.         pdbgmem->lpVtbl = 0;
  1907.         #if defined(WIN32) && defined(_X86_)
  1908.         DeleteCriticalSection(&pdbgmem->cs);
  1909.         #endif
  1910.         pmalloc->lpVtbl->Free(pmalloc, pdbgmem);
  1911.         pmalloc->lpVtbl->Release(pmalloc);
  1912.     }
  1913.  
  1914.     return(cRef);
  1915. }
  1916.  
  1917. /* IMalloc::Alloc ----------------------------------------------------------- */
  1918.  
  1919. STDMETHODIMP_(void FAR *) DBGMEM_Alloc(PDBGMEM pdbgmem, ULONG cb)
  1920. {
  1921.     PBLK    pblk;
  1922.     ULONG   cbAlloc;
  1923.     LPVOID  pvAlloc = 0;
  1924.     BYTE    bFill   = 0xFA;
  1925.  
  1926.     DBGMEM_EnterCriticalSection(pdbgmem);
  1927.  
  1928.     if (pdbgmem->fCheckOften)
  1929.         DBGMEM_CheckMemFn(pdbgmem, FALSE);
  1930.  
  1931.     cbAlloc = sizeof(BLK) + cb + pdbgmem->cbTail;
  1932.  
  1933.     if (pdbgmem->ulFailureAt != 0)
  1934.     {
  1935.         if (pdbgmem->ulFailureAt != pdbgmem->ulAllocAt)
  1936.             ++pdbgmem->ulAllocAt;
  1937.         else
  1938.             cbAlloc = 0;
  1939.     }
  1940.  
  1941.     if (cbAlloc < cb)
  1942.         pblk = 0;
  1943.     else if (pdbgmem->cbVirtual)
  1944.         pblk = VMAllocEx(cbAlloc, pdbgmem->cbVirtual);
  1945.     else
  1946.         pblk = (PBLK)pdbgmem->pmalloc->lpVtbl->Alloc(pdbgmem->pmalloc, cbAlloc);
  1947.  
  1948.     if (pblk) {
  1949.         pblk->pdbgmem       = pdbgmem;
  1950.         pblk->ulAllocNum    = ++pdbgmem->ulAllocNum;
  1951.         pblk->fUnleakable   = FALSE;
  1952.         pblk->pblktail      = (PBLKTAIL)((char *)pblk + sizeof(BLK) + cb);
  1953.  
  1954.         if (!pdbgmem->cbVirtual)
  1955.             ((struct _BLKTAIL UNALIGNED *) pblk->pblktail)->pblk = pblk;
  1956.  
  1957.         PblkEnqueue(pblk);
  1958.  
  1959.         #if defined(WIN32) && defined(_X86_)
  1960.         GetCallStack((DWORD *)pblk->pfnCallers, 0, NCALLERS);
  1961.         #endif
  1962.  
  1963.         if (pdbgmem->fCheckOften)
  1964.             DBGMEM_CheckMemFn(pdbgmem, FALSE);
  1965.  
  1966.         pvAlloc = PblkToPv(pblk);
  1967.  
  1968.         if (pdbgmem->fFillRandom)
  1969.             bFill = (BYTE)pblk->ulAllocNum;
  1970.  
  1971.         memset(pvAlloc, bFill, (size_t)cb);
  1972.  
  1973.         if (pdbgmem->cbExtra)
  1974.             memset(pblk->pblktail + 1, 0xAE, pdbgmem->cbExtra * sizeof(ULONG));
  1975.     }
  1976.  
  1977.     DBGMEM_LeaveCriticalSection(pdbgmem);
  1978.  
  1979.     return(pvAlloc);
  1980. }
  1981.  
  1982. /* IMalloc::Realloc --------------------------------------------------------- */
  1983.  
  1984. STDMETHODIMP_(void FAR *) DBGMEM_Realloc(PDBGMEM pdbgmem, void FAR* pv, ULONG cb)
  1985. {
  1986.     ULONG   cbAlloc;
  1987.     LPVOID  pvAlloc = 0;
  1988.     BYTE    bFill = 0xFA;
  1989.  
  1990.     DBGMEM_EnterCriticalSection(pdbgmem);
  1991.  
  1992.     if (pdbgmem->fCheckOften)
  1993.         DBGMEM_CheckMemFn(pdbgmem, FALSE);
  1994.  
  1995.     if (pv == 0) {
  1996.         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);
  1997.         pvAlloc = DBGMEM_Alloc(pdbgmem, cb);
  1998.     } else if (cb == 0) {
  1999.         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);
  2000.         DBGMEM_Free(pdbgmem, pv);
  2001.         pvAlloc = 0;
  2002.     } else if (DBGMEM_ValidatePv(pdbgmem, pv, "DBGMEM_Realloc")) {
  2003.         PBLK    pblk    = PvToPblk(pv);
  2004.         ULONG   cbOld   = PblkClientSize(pblk);
  2005.         PBLK    pblkNew;
  2006.  
  2007.         PblkDequeue(pblk);
  2008.  
  2009.         cbAlloc = sizeof(BLK) + cb + pdbgmem->cbTail;
  2010.  
  2011.         if (pdbgmem->ulFailureAt != 0)
  2012.         {
  2013.             if (pdbgmem->ulFailureAt != pdbgmem->ulAllocAt)
  2014.                 ++pdbgmem->ulAllocAt;
  2015.             else
  2016.                 cbAlloc = 0;
  2017.         }
  2018.  
  2019.         if (cbAlloc < cb)
  2020.             pblkNew = 0;
  2021.         else if (pdbgmem->cbVirtual)
  2022.             pblkNew = (PBLK)VMReallocEx(pblk, cbAlloc, pdbgmem->cbVirtual);
  2023.         else
  2024.             pblkNew = (PBLK)pdbgmem->pmalloc->lpVtbl->Realloc(pdbgmem->pmalloc, pblk, cbAlloc);
  2025.  
  2026.         if (pblkNew == 0) {
  2027.             PblkEnqueue(pblk);
  2028.             pvAlloc = 0;
  2029.         } else {
  2030.             pblkNew->pblktail = (PBLKTAIL)((char *)pblkNew + sizeof(BLK) + cb);
  2031.  
  2032.             if (!pdbgmem->cbVirtual)
  2033.                 ((struct _BLKTAIL UNALIGNED *) pblkNew->pblktail)->pblk = pblkNew;
  2034.  
  2035.             PblkEnqueue(pblkNew);
  2036.  
  2037.             pvAlloc = PblkToPv(pblkNew);
  2038.  
  2039.             if (pdbgmem->fFillRandom)
  2040.                 bFill = (BYTE)pblkNew->ulAllocNum;
  2041.  
  2042.             if (cb > cbOld)
  2043.                 memset((char *)pvAlloc + cbOld, bFill, (size_t)(cb - cbOld));
  2044.  
  2045.             if (pdbgmem->cbExtra)
  2046.                 memset(pblkNew->pblktail + 1, 0xAE, pdbgmem->cbExtra * sizeof(ULONG));
  2047.         }
  2048.     }
  2049.  
  2050.     DBGMEM_LeaveCriticalSection(pdbgmem);
  2051.  
  2052.     return(pvAlloc);
  2053. }
  2054.  
  2055. /* IMalloc::Free ------------------------------------------------------------ */
  2056.  
  2057. STDMETHODIMP_(void) DBGMEM_Free(PDBGMEM pdbgmem, void FAR * pv)
  2058. {
  2059.     DBGMEM_EnterCriticalSection(pdbgmem);
  2060.  
  2061.     if (pdbgmem->fCheckOften)
  2062.         DBGMEM_CheckMemFn(pdbgmem, FALSE);
  2063.  
  2064.     if (pv && DBGMEM_ValidatePv(pdbgmem, pv, "DBGMEM_Free")) {
  2065.         PBLK pblk = PvToPblk(pv);
  2066.  
  2067.         PblkDequeue(pblk);
  2068.  
  2069.         memset(pblk, 0xDC, (size_t)PblkAllocSize(pblk));
  2070.  
  2071.         if (pdbgmem->cbVirtual)
  2072.             VMFreeEx(pblk, pdbgmem->cbVirtual);
  2073.         else
  2074.             pdbgmem->pmalloc->lpVtbl->Free(pdbgmem->pmalloc, pblk);
  2075.     }
  2076.  
  2077.     DBGMEM_LeaveCriticalSection(pdbgmem);
  2078. }
  2079.  
  2080. /* IMalloc::GetSize --------------------------------------------------------- */
  2081.  
  2082. STDMETHODIMP_(ULONG) DBGMEM_GetSize(PDBGMEM pdbgmem, void FAR * pv)
  2083. {
  2084.     ULONG ulResult = (ULONG)(-1);
  2085.  
  2086.     DBGMEM_EnterCriticalSection(pdbgmem);
  2087.  
  2088.     if (pv == 0)
  2089.         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.");
  2090.     else if (DBGMEM_ValidatePv(pdbgmem, pv, "DBGMEM_GetSize"))
  2091.         ulResult = PblkClientSize(PvToPblk(pv));
  2092.  
  2093.     DBGMEM_LeaveCriticalSection(pdbgmem);
  2094.  
  2095.     return(ulResult);
  2096. }
  2097.  
  2098. /* IMalloc::DidAlloc -------------------------------------------------------- */
  2099.  
  2100. STDMETHODIMP_(int) DBGMEM_DidAlloc(PDBGMEM pdbgmem, void FAR * pv)
  2101. {
  2102.     PBLK    pblk;
  2103.     char *  pszReason;
  2104.     int     iResult = 0;
  2105.  
  2106.     DBGMEM_EnterCriticalSection(pdbgmem);
  2107.  
  2108.     for (pblk = pdbgmem->pblkHead; pblk; pblk = pblk->pblkNext)
  2109.     {
  2110.         AssertSz2(DBGMEM_ValidatePblk(pdbgmem,pblk,&pszReason)==TRUE,
  2111.                  "Block header (pblk=%08lX) is invalid\n%s",
  2112.                  pblk, pszReason);
  2113.         if (PblkToPv(pblk) == pv) {
  2114.             iResult = 1;
  2115.             break;
  2116.         }
  2117.     }
  2118.  
  2119.     DBGMEM_LeaveCriticalSection(pdbgmem);
  2120.  
  2121.     return(iResult);
  2122. }
  2123.  
  2124. /* IMalloc::HeapMinimize ---------------------------------------------------- */
  2125.  
  2126. STDMETHODIMP_(void) DBGMEM_HeapMinimize(PDBGMEM pdbgmem)
  2127. {
  2128.     pdbgmem->pmalloc->lpVtbl->HeapMinimize(pdbgmem->pmalloc);
  2129. }
  2130.  
  2131. /* DBGMEM_ValidatePblk ------------------------------------------------------ */
  2132.  
  2133. BOOL DBGMEM_ValidatePblk(PDBGMEM pdbgmem, PBLK pblk, char ** pszReason)
  2134. {
  2135.     #if defined(WIN16) || (defined(WIN32) && defined(_X86_))
  2136.     if (IsBadWritePtr(pblk, sizeof(BLK))) {
  2137.         *pszReason = "Block header cannot be written to";
  2138.         goto err;
  2139.     }
  2140.     #endif
  2141.  
  2142.     if (pblk->pdbgmem != pdbgmem) {
  2143.         *pszReason = "Block header does not have correct pointer back to allocator";
  2144.         goto err;
  2145.     }
  2146.  
  2147.     if (pblk->pblkNext) {
  2148.         #if defined(WIN16) || (defined(WIN32) && defined(_X86_))
  2149.         if (IsBadWritePtr(pblk->pblkNext, sizeof(BLK))) {
  2150.             *pszReason = "Block header has invalid next link pointer";
  2151.             goto err;
  2152.         }
  2153.         #endif
  2154.  
  2155.         if (pblk->pblkNext->pblkPrev != pblk) {
  2156.             *pszReason = "Block header points to a next block which doesn't point back to it";
  2157.             goto err;
  2158.         }
  2159.     }
  2160.  
  2161.     if (pblk->pblkPrev) {
  2162.         #if defined(WIN16) || (defined(WIN32) && defined(_X86_))
  2163.         if (IsBadWritePtr(pblk->pblkPrev, sizeof(BLK))) {
  2164.             *pszReason = "Block header has invalid prev link pointer";
  2165.             goto err;
  2166.         }
  2167.         #endif
  2168.  
  2169.         if (pblk->pblkPrev->pblkNext != pblk) {
  2170.             *pszReason = "Block header points to a prev block which doesn't point back to it";
  2171.             goto err;
  2172.         }
  2173.     } else if (pdbgmem->pblkHead != pblk) {
  2174.         *pszReason = "Block header has a zero prev link but the allocator doesn't believe it is the first block";
  2175.         goto err;
  2176.     }
  2177.  
  2178.     if (pblk->ulAllocNum > pdbgmem->ulAllocNum) {
  2179.         *pszReason = "Block header has an invalid internal allocation number";
  2180.         goto err;
  2181.     }
  2182.  
  2183.     if (!pdbgmem->cbVirtual) {
  2184.         #if defined(WIN16) || (defined(WIN32) && defined(_X86_))
  2185.         if (IsBadWritePtr(pblk->pblktail, pdbgmem->cbTail)) {
  2186.             *pszReason = "Block header has invalid pblktail pointer";
  2187.             goto err;
  2188.         }
  2189.         #endif
  2190.  
  2191.         if (((struct _BLKTAIL UNALIGNED *) pblk->pblktail)->pblk != pblk) {
  2192.             *pszReason = "Block trailer does not point back to the block header";
  2193.             goto err;
  2194.         }
  2195.     }
  2196.  
  2197.     if (pdbgmem->cbExtra) {
  2198.         ULONG UNALIGNED * pul = (ULONG UNALIGNED *)(pblk->pblktail + 1);
  2199.         int n = pdbgmem->cbExtra;
  2200.         for (; --n >= 0; ++pul)
  2201.             if (*pul != 0xAEAEAEAE) {
  2202.                 *pszReason = "Block trailer spiddle-zone has been overwritten";
  2203.                 goto err;
  2204.             }
  2205.     }
  2206.  
  2207.     return(TRUE);
  2208.  
  2209. err:
  2210.     return(FALSE);
  2211. }
  2212.  
  2213. /* DBGMEM_ValidatePv -------------------------------------------------------- */
  2214.  
  2215. BOOL DBGMEM_ValidatePv(PDBGMEM pdbgmem, void * pv, char * pszFunc)
  2216. {
  2217.     char *  pszReason;
  2218.  
  2219.     if (DBGMEM_DidAlloc(pdbgmem, pv) == 0) {
  2220.         TrapSz3("DBGMEM_ValidatePv(subsys=%s,pv=%08lX) [via %s]\nDetected a memory block which was not allocated by this allocator",
  2221.             pdbgmem->szSubsys, pv, pszFunc);
  2222.         return(FALSE);
  2223.     }
  2224.  
  2225.     if (DBGMEM_ValidatePblk(pdbgmem,PvToPblk(pv),&pszReason))
  2226.         return(TRUE);
  2227.  
  2228.     TrapSz4("DBGMEM_ValidatePv(%s,pv=%08lX) [via %s]\n%s",
  2229.         pdbgmem->szSubsys, pv, pszFunc, pszReason);
  2230.  
  2231.     return(FALSE);
  2232. }
  2233.  
  2234. /* DBGMEM_ReportLeak -------------------------------------------------------- */
  2235.  
  2236. #if defined(WIN32) && defined(_X86_)
  2237. void EXPORTDBG __cdecl DBGMEM_LeakHook(FARPROC pfn)
  2238. {
  2239.     /* Dummy function so that you can set a breakpoint with command   */
  2240.     /* "ln ecx;g", in order to get the debugger to print out the name */
  2241.     /* of the function which allocated the leaked memory block        */
  2242. }
  2243. #endif
  2244.  
  2245. void DBGMEM_ReportLeak(PDBGMEM pdbgmem, PBLK pblk)
  2246. {
  2247.     int i = 0;
  2248.  
  2249.     DebugTrace("%s Memory Leak: @%08lX, allocation #%ld, size %ld\n",
  2250.         pdbgmem->szSubsys, PblkToPv(pblk), pblk->ulAllocNum, PblkClientSize(pblk));
  2251.  
  2252.     #if defined(WIN32) && defined(_X86_)
  2253.     for (i = 0; i < NCALLERS && pblk->pfnCallers[i] != 0; i++) {
  2254.         DebugTrace("[%d] %08lX ", i, pblk->pfnCallers[i]);
  2255.         DBGMEM_LeakHook(pblk->pfnCallers[i]);
  2256.     }
  2257.     DebugTrace("\n");
  2258.     #endif
  2259. }
  2260.  
  2261. /* DBGMEM_NoLeakDetectFn ---------------------------------------------------- */
  2262.  
  2263. void EXPORTDBG __cdecl DBGMEM_NoLeakDetectFn(void * pmalloc, void *pv)
  2264. {
  2265.     PDBGMEM pdbgmem = (PDBGMEM)pmalloc;
  2266.  
  2267.     DBGMEM_EnterCriticalSection(pdbgmem);
  2268.  
  2269.     if (pv == 0)
  2270.         pdbgmem->fUnleakable = TRUE;
  2271.     else if (DBGMEM_ValidatePv(pdbgmem, pv, "DBGMEM_NoLeakDetectFn"))
  2272.         PvToPblk(pv)->fUnleakable = TRUE;
  2273.  
  2274.     DBGMEM_LeaveCriticalSection(pdbgmem);
  2275. }
  2276.  
  2277. /* DBGMEM_SetFailureAtFn ---------------------------------------------------- */
  2278.  
  2279. void EXPORTDBG __cdecl DBGMEM_SetFailureAtFn(void * pmalloc, ULONG ulFailureAt)
  2280. {
  2281.     PDBGMEM pdbgmem = (PDBGMEM)pmalloc;
  2282.  
  2283.     DBGMEM_EnterCriticalSection(pdbgmem);
  2284.  
  2285.     pdbgmem->ulFailureAt = ulFailureAt;
  2286.  
  2287.     DBGMEM_LeaveCriticalSection(pdbgmem);
  2288. }
  2289.  
  2290. /* DBGMEM_CheckMemFn -------------------------------------------------------- */
  2291.  
  2292. void EXPORTDBG __cdecl DBGMEM_CheckMemFn(void * pmalloc, BOOL fReportOrphans)
  2293. {
  2294.     PDBGMEM pdbgmem = (PDBGMEM)pmalloc;
  2295.     PBLK    pblk;
  2296.     int     cLeaks = 0;
  2297.  
  2298.     DBGMEM_EnterCriticalSection(pdbgmem);
  2299.  
  2300.     for (pblk = pdbgmem->pblkHead; pblk; pblk = pblk->pblkNext) {
  2301.         if (!DBGMEM_ValidatePv(pdbgmem, PblkToPv(pblk), "DBGMEM_CheckMemFn"))
  2302.             break;
  2303.  
  2304.         if (fReportOrphans && !pdbgmem->fUnleakable && !pblk->fUnleakable) {
  2305.             DBGMEM_ReportLeak(pdbgmem, pblk);
  2306.             cLeaks += 1;
  2307.         }
  2308.     }
  2309.  
  2310.     #if defined(WIN16) || (defined(WIN32) && defined(_X86_))
  2311.     if (fAssertLeaks == -1)
  2312.     {
  2313.         fAssertLeaks = GetPrivateProfileIntA(szSectionDebug, szKeyAssertLeaks,
  2314.             0, szDebugIni);
  2315.     }
  2316.     #endif
  2317.  
  2318.     if (cLeaks > 0)
  2319.     {
  2320.         #if defined(WIN16) || (defined(WIN32) && defined(_X86_))
  2321.         if (fAssertLeaks)
  2322.         {
  2323.             TrapSz3("DBGMEM detected %d memory leak%s in subsystem %s",
  2324.                 cLeaks, cLeaks == 1 ? "" : "s", pdbgmem->szSubsys);
  2325.         }
  2326.         else
  2327.         {
  2328.             TraceSz3("DBGMEM detected %d memory leak%s in subsystem %s",
  2329.                 cLeaks, cLeaks == 1 ? "" : "s", pdbgmem->szSubsys);
  2330.         }
  2331.         #else
  2332.         TraceSz3("DBGMEM detected %d memory leak%s in subsystem %s",
  2333.             cLeaks, cLeaks == 1 ? "" : "s", pdbgmem->szSubsys);
  2334.         #endif
  2335.     }
  2336.  
  2337.     DBGMEM_LeaveCriticalSection(pdbgmem);
  2338. }
  2339.  
  2340. /* vtblDBGMEM --------------------------------------------------------------- */
  2341.  
  2342. DBGMEM_Vtbl BASED_DEBUG vtblDBGMEM =
  2343. {
  2344.     VTABLE_FILL
  2345.     DBGMEM_QueryInterface,
  2346.     DBGMEM_AddRef,
  2347.     DBGMEM_Release,
  2348.     DBGMEM_Alloc,
  2349.     DBGMEM_Realloc,
  2350.     DBGMEM_Free,
  2351.     DBGMEM_GetSize,
  2352.     DBGMEM_DidAlloc,
  2353.     DBGMEM_HeapMinimize
  2354. };
  2355.  
  2356. /* DBGMEM_EncapsulateFn ----------------------------------------------------- */
  2357.  
  2358. void * EXPORTDBG __cdecl DBGMEM_EncapsulateFn(void * pvmalloc, char *pszSubsys, BOOL fCheckOften)
  2359. {
  2360.     LPMALLOC    pmalloc = (LPMALLOC)pvmalloc;
  2361.     PDBGMEM     pdbgmem;
  2362.     LPMALLOC    pmallocBase;
  2363.     ULONG       cbVirtual = 0;
  2364.     BOOL        fFillRandom = FALSE;
  2365.     HRESULT     hr;
  2366.  
  2367.     hr = pmalloc->lpVtbl->QueryInterface(pmalloc, &DBGMEM_IID_IBaseMalloc, &pmallocBase);
  2368.     if (hr) {
  2369.         pmallocBase = pmalloc;
  2370.         pmallocBase->lpVtbl->AddRef(pmallocBase);
  2371.     }
  2372.  
  2373.     pdbgmem = (PDBGMEM)pmallocBase->lpVtbl->Alloc(pmallocBase, sizeof(DBGMEM));
  2374.  
  2375.     if (pdbgmem == 0) {
  2376.         TrapSz("DBGMEM: Failed trying to allocate memory for the first time!\n");
  2377.         return(pmallocBase);
  2378.     }
  2379.  
  2380.     #if defined(WIN16) || (defined(WIN32) && defined(_X86_))
  2381.     cbVirtual = GetPrivateProfileIntA(szSectionDebug, szKeyUseVirtual, 0,
  2382.         szDebugIni);
  2383.  
  2384.     if (cbVirtual != 0 && cbVirtual != 1 && cbVirtual != 4)
  2385.         cbVirtual = 1;
  2386.  
  2387.     if (cbVirtual)
  2388.         DebugTrace("DBGMEM: Subsystem '%s' using virtual memory allocator -"
  2389.             " align %d.\n", pszSubsys, cbVirtual);
  2390.  
  2391.     if (!fCheckOften)
  2392.         fCheckOften = GetPrivateProfileIntA(szSectionDebug, szKeyCheckOften, 0,
  2393.             szDebugIni);
  2394.  
  2395.     fFillRandom = GetPrivateProfileIntA(szSectionDebug, szKeyFillRandom, 0,
  2396.         szDebugIni);
  2397.  
  2398.     #endif
  2399.  
  2400.     memset(pdbgmem, 0, sizeof(DBGMEM));
  2401.  
  2402.     pdbgmem->lpVtbl         = &vtblDBGMEM;
  2403.     pdbgmem->cRef           = 1;
  2404.     pdbgmem->pmalloc        = pmallocBase;
  2405.     pdbgmem->fCheckOften    = fCheckOften;
  2406.     pdbgmem->fUnleakable    = FALSE;
  2407.     pdbgmem->cbVirtual      = cbVirtual;
  2408.     pdbgmem->fFillRandom    = fFillRandom;
  2409.     pdbgmem->cbExtra        = 0;
  2410.     pdbgmem->ulAllocAt      = 1L;
  2411.     pdbgmem->ulFailureAt    = 0L;
  2412.  
  2413.     if (pdbgmem->cbVirtual)
  2414.         pdbgmem->cbTail     = 0;
  2415.     else
  2416.         pdbgmem->cbTail     = sizeof(BLKTAIL) + pdbgmem->cbExtra * sizeof(ULONG);
  2417.  
  2418.     lstrcpyn(pdbgmem->szSubsys, pszSubsys, sizeof(pdbgmem->szSubsys));
  2419.  
  2420.     #if defined(WIN32) && defined(_X86_)
  2421.     InitializeCriticalSection(&pdbgmem->cs);
  2422.     #endif
  2423.  
  2424.     return(pdbgmem);
  2425. }
  2426.  
  2427. /* DBGMEM_ShutdownFn -------------------------------------------------------- */
  2428.  
  2429. void EXPORTDBG __cdecl DBGMEM_ShutdownFn(void *pvmalloc)
  2430. {
  2431.     LPMALLOC    pmalloc = (LPMALLOC)pvmalloc;
  2432.     PDBGMEM     pdbgmem = (PDBGMEM)pvmalloc;
  2433.     LPMALLOC    pmallocBase;
  2434.     HRESULT     hr;
  2435.  
  2436.     hr = pmalloc->lpVtbl->QueryInterface(pmalloc, &DBGMEM_IID_IBaseMalloc, &pmallocBase);
  2437.     if (hr == 0) {
  2438.         pmallocBase->lpVtbl->Release(pmallocBase);
  2439.         if (pdbgmem->cRef != 1) {
  2440.             TrapSz2("DBGMEM_Shutdown: Expected a cRef of 1; instead have %ld for %s",
  2441.                 pdbgmem->cRef, pdbgmem->szSubsys);
  2442.             pdbgmem->cRef = 1;
  2443.         }
  2444.     }
  2445.  
  2446.     pmalloc->lpVtbl->Release(pmalloc);
  2447. }
  2448.  
  2449. /* -------------------------------------------------------------------------- */
  2450.  
  2451. #endif
  2452.