MAPIDBG.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:64k
源码类别:

Windows编程

开发平台:

Visual C++

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