Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2448 lines
57 KiB

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