home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / trialva / ibmcppw / sdk / mapi / win16 / dev / sample.ms / mspobj.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-11  |  7.6 KB  |  323 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.     AssertSz1(      pobj->wType == OT_MSGSTORE
  157.               ||    pobj->cRef >= 1, "OBJ_AddRef(): Bogus cRef (%08lX)", pobj->cRef);
  158.  
  159.     cRef = ++pobj->cRef;
  160.  
  161.     OBJ_LeaveCriticalSection(pobj);
  162.  
  163.     return (cRef);
  164. }
  165.  
  166. /* OBJ_Release ------------------------------------------------------------- */
  167.  
  168. /* Used by Message Store, Message, and Attachment objects. All other objects */
  169. /* have their own implementations of Release. */
  170.  
  171. STDMETHODIMP_(ULONG) OBJ_Release(POBJ pobj)
  172. {
  173.     LONG cRef;
  174.  
  175.     if (!pobj)
  176.         return (0);
  177.  
  178.     if (OBJ_IsInvalid(pobj, Release))
  179.     {
  180.         TraceSz1("SampleMS: OBJ_Release(pobj=%08lX): Object is invalid and is "
  181.             "being ignored", pobj);
  182.         return (0);
  183.     }
  184.  
  185.     OBJ_EnterCriticalSection(pobj);
  186.  
  187.     AssertSz(pobj->cRef > 0, "OBJ_Release(): Too many releases");
  188.  
  189.     cRef = --pobj->cRef;
  190.  
  191.     if (cRef == 0)
  192.     {
  193.         if (pobj->wType != OT_MSGSTORE)
  194.             pobj->lpVtbl = 0;
  195.  
  196.         if (pobj->pobjHead == 0)
  197.         {
  198.             OBJ_Destroy(pobj);
  199.             return (0);
  200.         }
  201.     }
  202.  
  203.     OBJ_LeaveCriticalSection(pobj);
  204.  
  205.     return (cRef);
  206. }
  207.  
  208. /* OBJ_Enqueue / OBJ_Dequeue / OBJ_Destroy --------------------------------- */
  209.  
  210. void OBJ_Enqueue(POBJ pobj, POBJ pobjParent)
  211. {
  212.     pobj->pobjParent = pobjParent;
  213.     pobj->pobjNext = pobjParent->pobjHead;
  214.     pobjParent->pobjHead = pobj;
  215. }
  216.  
  217. void OBJ_Dequeue(POBJ pobj)
  218. {
  219.     if (pobj->pobjParent != NULL)
  220.     {
  221.         POBJ *ppobj = &pobj->pobjParent->pobjHead;
  222.  
  223.         while (TRUE)
  224.         {
  225.             POBJ pobjCur = *ppobj;
  226.  
  227.             if (pobjCur == NULL)
  228.                 break;
  229.  
  230.             if (pobjCur == pobj)
  231.             {
  232.                 *ppobj = pobj->pobjNext;
  233.                 break;
  234.             }
  235.  
  236.             ppobj = &pobjCur->pobjNext;
  237.         }
  238.  
  239.         pobj->pobjParent = 0;
  240.     }
  241. }
  242.  
  243. /* 
  244.  * OBJ_Destroy
  245.  * 
  246.  * Destroy an object. If this object was the last thing causing the parent to
  247.  * exist, then we should destroy the parent, and so on up the chain. There are
  248.  * two actual critical sections in the sample store. One is in the msp (message
  249.  * store provider) object. The other is in the msl (message store logon) object.
  250.  * All other objects in the sample store contain a pointer to the msl object's 
  251.  * critical section (they all share it). When we arrive at this routine, we 
  252.  * should have the object's critical section locked, i.e., the msl critical
  253.  * section should be locked. That's why there are calls to leave a critical
  254.  * section that aren't balanced with an enter.
  255.  */
  256.  
  257. void OBJ_Destroy(POBJ pobj)
  258. {
  259.     PIMS pims;
  260.     POBJ pobjParent;
  261.     LPFNNEUTER lpfnNeuter;
  262.     LPMAPISUP psup;
  263.  
  264.     pims = pobj->pims;
  265.  
  266.     while (1)
  267.     {
  268.         /* Call a routine to make the object free any memory */
  269.         /* or other structures it has. (We call this "neutering" the object.) */
  270.  
  271.         if ((lpfnNeuter = rgfnNeuter[pobj->wType]) != 0)
  272.             lpfnNeuter(pobj);
  273.  
  274.         pobjParent = pobj->pobjParent;
  275.  
  276.         if (pobj == (POBJ) pims)
  277.         {
  278.             if (pobjParent != NULL)
  279.             {
  280.                 /* The parent in this case is the msp (message store provider) */
  281.                 /* object. We need to get its critical section in order to */
  282.                 /* safely dequeue the message store object. */
  283.  
  284.                 OBJ_EnterCriticalSection(pobjParent);
  285.                 OBJ_Dequeue(pobj);
  286.                 OBJ_LeaveCriticalSection(pobjParent);
  287.             }
  288.  
  289.             pobjParent = (POBJ) pims->pmsl;
  290.             psup = pims->psup;
  291.  
  292.             pobj->lpVtbl = 0;
  293.             LMFree(&pims->lmr, pobj);
  294.  
  295.             /* This leave balances the enter in the calling function. */
  296.             /* Since we just freed the message store object, we can't leave */
  297.             /* critical section using that pointer. Therefore, use the msl */
  298.             /* (message store logon) object's critical section instead. They */
  299.             /* are the same (see header comment at top of function). */
  300.  
  301.             OBJ_LeaveCriticalSection(pobjParent);
  302.  
  303.             UlRelease(psup);    /* do this last */
  304.             break;
  305.         }
  306.  
  307.         OBJ_Dequeue(pobj);
  308.  
  309.         pobj->lpVtbl = 0;
  310.         LMFree(&pims->lmr, pobj);
  311.  
  312.         pobj = pobjParent;
  313.  
  314.         if (pobj == 0 || pobj->cRef || pobj->pobjHead)
  315.         {
  316.             /* This leave balances the enter in the calling function. */
  317.  
  318.             OBJ_LeaveCriticalSection((POBJ) pims);
  319.             break;
  320.         }
  321.     }
  322. }
  323.