home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / mapi / docfile.ms / mspobj.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  7.8 KB  |  328 lines

  1. /*
  2.  * M S P O B J . C
  3.  *
  4.  * Common code for implementation of objects in the sample message store
  5.  * provider.
  6.  *
  7.  * Copyright (C) 1992-1995 Microsoft Corporation. All Rights Reserved.
  8.  */
  9.  
  10. #include "msp.h"
  11.  
  12. /* Object Type to Neuter Function Map -------------------------------------- */
  13.  
  14. LPFNNEUTER rgfnNeuter[] =
  15. {
  16.     (LPFNNEUTER) 0,             /* IMSProvider */
  17.     (LPFNNEUTER) 0,             /* IMSLogon */
  18.     (LPFNNEUTER) IMS_Neuter,    /* IMsgStore */
  19.     (LPFNNEUTER) IFLD_Neuter,   /* IMAPIFolder */
  20.     (LPFNNEUTER) IMSG_Neuter,   /* IMessage */
  21.     (LPFNNEUTER) IATCH_Neuter,  /* IAttach */
  22.     (LPFNNEUTER) 0,             /* IStream */
  23.     (LPFNNEUTER) 0,             /* IMAPITable */
  24. };
  25.  
  26. /* Object Type to Interfaces Supported Map --------------------------------- */
  27.  
  28. REFIID MSP_IIDs[] =
  29. {
  30.     &IID_IMSProvider,
  31.     &IID_IUnknown
  32. };
  33.  
  34. REFIID MSL_IIDs[] =
  35. {
  36.     &IID_IMSLogon,
  37.     &IID_IUnknown
  38. };
  39.  
  40. REFIID MS_IIDs[] =
  41. {
  42.     &IID_IMsgStore,
  43.     &IID_IMAPIProp,
  44.     &IID_IUnknown
  45. };
  46.  
  47. REFIID FLD_IIDs[] =
  48. {
  49.     &IID_IMAPIFolder,
  50.     &IID_IMAPIContainer,
  51.     &IID_IMAPIProp,
  52.     &IID_IUnknown
  53. };
  54.  
  55. REFIID MSG_IIDs[] =
  56. {
  57.     &IID_IMessage,
  58.     &IID_IMAPIProp,
  59.     &IID_IUnknown
  60. };
  61.  
  62. REFIID ATCH_IIDs[] =
  63. {
  64.     &IID_IAttachment,
  65.     &IID_IMAPIProp,
  66.     &IID_IUnknown
  67. };
  68.  
  69. REFIID STM_IIDs[] =
  70. {
  71.     &IID_IStream,
  72.     &IID_IUnknown
  73. };
  74.  
  75. REFIID TBL_IIDs[] =
  76. {
  77.     &IID_IMAPITable,
  78.     &IID_IUnknown
  79. };
  80.  
  81. REFIID *rgpriid[] =
  82. {
  83.     MSP_IIDs,
  84.     MSL_IIDs,
  85.     MS_IIDs,
  86.     FLD_IIDs,
  87.     MSG_IIDs,
  88.     ATCH_IIDs,
  89.     STM_IIDs,
  90.     TBL_IIDs
  91. };
  92.  
  93. #define OBJ_IsInvalid(pobj, f)                                  \
  94.     (IsBadWritePtr(pobj, sizeof(OBJ))                           \
  95.     || IsBadReadPtr((pobj)->lpVtbl, sizeof(OBJ_Vtbl))           \
  96.     || (pobj)->lpVtbl->f != OBJ_##f                             \
  97.     || (pobj)->wType >= OT_MAX)
  98.  
  99. /* OBJ_QueryInterface ------------------------------------------------------ */
  100.  
  101. BOOL 
  102. FQueryInterface(int wType, REFIID riid)
  103. {
  104.     REFIID *priid = rgpriid[wType];
  105.  
  106.     while (1)
  107.     {
  108.         if (IsEqualGUID(riid, *priid))
  109.             return (TRUE);
  110.  
  111.         if (*priid == &IID_IUnknown)
  112.             break;
  113.  
  114.         priid += 1;
  115.     }
  116.  
  117.     return (FALSE);
  118. }
  119.  
  120. STDMETHODIMP 
  121. OBJ_QueryInterface(POBJ pobj, REFIID riid, LPVOID * ppvObj)
  122. {
  123.     if (    OBJ_IsInvalid(pobj, QueryInterface)
  124.         ||  IsBadReadPtr(riid, sizeof(IID))
  125.         ||  IsBadWritePtr(ppvObj, sizeof(LPVOID)))
  126.         return ResultFromScode(E_INVALIDARG);
  127.  
  128.     /* Even if an error is returned, must zero *ppvObj */
  129.     *ppvObj = 0;
  130.  
  131.     if (FQueryInterface(pobj->wType, riid))
  132.     {
  133.         UlAddRef(pobj);
  134.         *ppvObj = pobj;
  135.         return (0);
  136.     }
  137.  
  138.     return (ResultFromScode(E_NOINTERFACE));
  139. }
  140.  
  141. /* OBJ_AddRef -------------------------------------------------------------- */
  142.  
  143. STDMETHODIMP_(ULONG) OBJ_AddRef(POBJ pobj)
  144. {
  145.     LONG cRef;
  146.  
  147.     if (OBJ_IsInvalid(pobj, AddRef))
  148.     {
  149.         TraceSz1("Sample MS: OBJ_AddRef(pobj=%08lX): Object is invalid and "
  150.             "is being ignored", pobj);
  151.         return (0);
  152.     }
  153.  
  154.     OBJ_EnterCriticalSection(pobj);
  155.  
  156. #ifdef DEBUG
  157.     if (pobj->wType == OT_MSGSTORE)
  158.         Assert(!OBJ_TestFlag(pobj, MSF_BEINGDESTROYED));
  159. #endif
  160.  
  161.     AssertSz1(      pobj->wType == OT_MSGSTORE
  162.               ||    pobj->cRef >= 1, "OBJ_AddRef(): Bogus cRef (%08lX)", pobj->cRef);
  163.  
  164.     cRef = ++pobj->cRef;
  165.  
  166.     OBJ_LeaveCriticalSection(pobj);
  167.  
  168.     return (cRef);
  169. }
  170.  
  171. /* OBJ_Release ------------------------------------------------------------- */
  172.  
  173. /* Used by Message Store, Message, and Attachment objects. All other objects */
  174. /* have their own implementations of Release. */
  175.  
  176. STDMETHODIMP_(ULONG) OBJ_Release(POBJ pobj)
  177. {
  178.     LONG cRef;
  179.  
  180.     if (!pobj)
  181.         return (0);
  182.  
  183.     if (OBJ_IsInvalid(pobj, Release))
  184.     {
  185.         TraceSz1("SampleMS: OBJ_Release(pobj=%08lX): Object is invalid and is "
  186.             "being ignored", pobj);
  187.         return (0);
  188.     }
  189.  
  190.     OBJ_EnterCriticalSection(pobj);
  191.  
  192.     AssertSz(pobj->cRef > 0, "OBJ_Release(): Too many releases");
  193.  
  194.     cRef = --pobj->cRef;
  195.  
  196.     if (cRef == 0)
  197.     {
  198.         if (pobj->wType != OT_MSGSTORE)
  199.             pobj->lpVtbl = 0;
  200.  
  201.         if (pobj->pobjHead == 0)
  202.         {
  203.             OBJ_Destroy(pobj);
  204.             return (0);
  205.         }
  206.     }
  207.  
  208.     OBJ_LeaveCriticalSection(pobj);
  209.  
  210.     return (cRef);
  211. }
  212.  
  213. /* OBJ_Enqueue / OBJ_Dequeue / OBJ_Destroy --------------------------------- */
  214.  
  215. void OBJ_Enqueue(POBJ pobj, POBJ pobjParent)
  216. {
  217.     pobj->pobjParent = pobjParent;
  218.     pobj->pobjNext = pobjParent->pobjHead;
  219.     pobjParent->pobjHead = pobj;
  220. }
  221.  
  222. void OBJ_Dequeue(POBJ pobj)
  223. {
  224.     if (pobj->pobjParent != NULL)
  225.     {
  226.         POBJ *ppobj = &pobj->pobjParent->pobjHead;
  227.  
  228.         while (TRUE)
  229.         {
  230.             POBJ pobjCur = *ppobj;
  231.  
  232.             if (pobjCur == NULL)
  233.                 break;
  234.  
  235.             if (pobjCur == pobj)
  236.             {
  237.                 *ppobj = pobj->pobjNext;
  238.                 break;
  239.             }
  240.  
  241.             ppobj = &pobjCur->pobjNext;
  242.         }
  243.  
  244.         pobj->pobjParent = 0;
  245.     }
  246. }
  247.  
  248. /* 
  249.  * OBJ_Destroy
  250.  * 
  251.  * Destroy an object. If this object was the last thing causing the parent to
  252.  * exist, then we should destroy the parent, and so on up the chain. There are
  253.  * two actual critical sections in the sample store. One is in the msp (message
  254.  * store provider) object. The other is in the msl (message store logon) object.
  255.  * All other objects in the sample store contain a pointer to the msl object's 
  256.  * critical section (they all share it). When we arrive at this routine, we 
  257.  * should have the object's critical section locked, i.e., the msl critical
  258.  * section should be locked. That's why there are calls to leave a critical
  259.  * section that aren't balanced with an enter.
  260.  */
  261.  
  262. void OBJ_Destroy(POBJ pobj)
  263. {
  264.     PIMS pims;
  265.     POBJ pobjParent;
  266.     LPFNNEUTER lpfnNeuter;
  267.     LPMAPISUP psup;
  268.  
  269.     pims = pobj->pims;
  270.  
  271.     while (1)
  272.     {
  273.         /* Call a routine to make the object free any memory */
  274.         /* or other structures it has. (We call this "neutering" the object.) */
  275.  
  276.         if ((lpfnNeuter = rgfnNeuter[pobj->wType]) != 0)
  277.             lpfnNeuter(pobj);
  278.  
  279.         pobjParent = pobj->pobjParent;
  280.  
  281.         if (pobj == (POBJ) pims)
  282.         {
  283.             if (pobjParent != NULL)
  284.             {
  285.                 /* The parent in this case is the msp (message store provider) */
  286.                 /* object. We need to get its critical section in order to */
  287.                 /* safely dequeue the message store object. */
  288.  
  289.                 OBJ_EnterCriticalSection(pobjParent);
  290.                 OBJ_Dequeue(pobj);
  291.                 OBJ_LeaveCriticalSection(pobjParent);
  292.             }
  293.  
  294.             pobjParent = (POBJ) pims->pmsl;
  295.             psup = pims->psup;
  296.  
  297.             pobj->lpVtbl = 0;
  298.             LMFree(&pims->lmr, pobj);
  299.  
  300.             /* This leave balances the enter in the calling function. */
  301.             /* Since we just freed the message store object, we can't leave */
  302.             /* critical section using that pointer. Therefore, use the msl */
  303.             /* (message store logon) object's critical section instead. They */
  304.             /* are the same (see header comment at top of function). */
  305.  
  306.             OBJ_LeaveCriticalSection(pobjParent);
  307.  
  308.             UlRelease(psup);    /* do this last */
  309.             break;
  310.         }
  311.  
  312.         OBJ_Dequeue(pobj);
  313.  
  314.         pobj->lpVtbl = 0;
  315.         LMFree(&pims->lmr, pobj);
  316.  
  317.         pobj = pobjParent;
  318.  
  319.         if (pobj == 0 || pobj->cRef || pobj->pobjHead)
  320.         {
  321.             /* This leave balances the enter in the calling function. */
  322.  
  323.             OBJ_LeaveCriticalSection((POBJ) pims);
  324.             break;
  325.         }
  326.     }
  327. }
  328.