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

Windows编程

开发平台:

Visual C++

  1. /*
  2.  -  X P S N D M S G . C
  3.  -
  4.  *  Purpose:
  5.  *      Code to support the MAPI Transport SPI entry points for
  6.  *      message transmission.
  7.  *      This module contains the following SPI entry points:
  8.  *
  9.  *          SubmitMessage()
  10.  *          EndMessage()
  11.  *
  12.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  13.  */
  14. #include "xppch.h"
  15. HRESULT HrAddDeferred(LPXPL lpxpl, LPMESSAGE lpMsg, ULONG *lpulMsgRef);
  16. /*
  17.  -  XPL_SubmitMessage
  18.  -
  19.  *  Purpose:
  20.  *      Called by the Spooler when it wishes to attempt transmission
  21.  *      of a message.
  22.  *
  23.  *  Parameters:
  24.  *      ulFlags             Flags from the Spooler. The only
  25.  *                          flag defined in the MAPI 1.0 TSPI
  26.  *                          is BEGIN_DEFERRED, and this transport
  27.  *                          doesn't do deferred transmission.
  28.  *      lpMessage           Pointer to message object that the
  29.  *                          Spooler wants sent.
  30.  *      lpulMsgRef          Pointer to where the transport should
  31.  *                          store a unsigned long for use in
  32.  *                          identifying TransportNotify() message
  33.  *                          events. Initialized to 1 by the
  34.  *                          Spooler. We use this to ID deferred
  35.  *                          messages using DEFERRED_MSG_REF.
  36.  *      lpulReturnParm      Used for several MAPI_E_XXX returns,
  37.  *                          but this transport doesn't do any
  38.  *                          of them.
  39.  *
  40.  *  Returns:
  41.  *      (HRESULT)           MAPI_E_BUSY if the Spooler calls
  42.  *                          here again while we're busy, else
  43.  *                          errors encountered if any.
  44.  *
  45.  *  Operation:
  46.  *      For non peer-to-peer, "send" the message to our outbound directory.
  47.  *
  48.  *      For peer-to-peer, use the ADRLIST builder HrBuildAdrList to attempt
  49.  *      transmission to each recipient and build both a sent ADRLIST and a
  50.  *      NDR ADRLIST. ModifyRecipients() on the Spooler message if there's
  51.  *      anyone in the sent ADRLIST. This tells the spooler which ones got
  52.  *      the mail.  If there were any recipients in the NDR ADRLIST, we need
  53.  *      to StatusRecips() with that list, and we will need to
  54.  *      ModifyRecipients() again with them.
  55.  *
  56.  *      For non peer-to-peer or p2p with NDR recipients, use the ADRLIST
  57.  *      builder HrBuildAdrList to make a ADRLIST with all of our unsent
  58.  *      recipients (for non p2p, delivery to all recipients consists of
  59.  *      putting a file into the outbound and for NDR cases, we just take
  60.  *      responsibility because we've already NDR'ed them) and
  61.  *      ModifyRecipients().
  62.  */
  63. STDMETHODIMP
  64. XPL_SubmitMessage(LPXPL lpxpl,
  65.     ULONG ulFlags,
  66.     LPMESSAGE lpMessage,
  67.     ULONG * lpulMsgRef,
  68.     ULONG * lpulReturnParm)
  69. {
  70.     LPTSTR lpszMyDir;
  71.     HRESULT hResult = 0;
  72.     SCODE sc = 0;
  73.     BOOL fUpdatedStatus = FALSE;
  74.     BOOL fPeer2Peer;
  75.     LPSPropValue lpPropArray = NULL;
  76.     LPMAPISUP lpMAPISup;
  77.     ULONG cValues;
  78.     LPSPropValue lpMsgProps = NULL;
  79.     static const SizedSPropTagArray(2, sptMsgDefer) =
  80.     {
  81.         2,
  82.         {
  83.             PR_SAMPLE_PER_MSG_DEFER,
  84.             PR_SAMPLE_PER_RECIP_DEFER
  85.         }
  86.     };
  87.     SPropValue spvRecipUnsent =
  88.     {PR_RESPONSIBILITY, 0L, FALSE};
  89.     SPropValue spvRecipDefer =
  90.     {PR_SAMPLE_PER_RECIP_DEFER, 0L, TRUE};
  91.     SRestriction rgsrOr[2];
  92.     SRestriction rgsrAnd[2];
  93.     SRestriction srExist;
  94.     SRestriction srRecipUnsent;
  95.     LPMAPITABLE lpTable = NULL;
  96.     LPMYADRLIST lpMyAdrListDone = NULL;
  97.     LPMYADRLIST lpMyAdrListNotDone = NULL;
  98.     /* Simple re-entrancy test. Should never happen anyway. */
  99.     if (lpxpl->ulTransportStatus & STATUS_OUTBOUND_ACTIVE)
  100.     {
  101.         hResult = ResultFromScode(MAPI_E_BUSY);
  102.         DebugTrace("XPL_SubmitMessage reentrancy test failed.n");
  103.         goto ret;
  104.     }
  105.     /* Signal that we're uploading. */
  106.     lpxpl->ulTransportStatus |= STATUS_OUTBOUND_ACTIVE;
  107.     hResult = HrUpdateTransportStatus(lpxpl, 0L);
  108.     if (hResult)
  109.         goto ret;
  110.     fUpdatedStatus = TRUE;
  111.     /*  Session's OK, hook up some local references */
  112.     sc = ScCopySessionProps(lpxpl, &lpPropArray, NULL);
  113.     if (FAILED(sc))
  114.     {
  115.         hResult = ResultFromScode(sc);
  116.         DebugTrace("ScCopySessionProps failed in SubmitMessage.n");
  117.         goto ret;
  118.     }
  119.     lpMAPISup = lpxpl->lpMAPISup;
  120.     fPeer2Peer = ((ArrayIndex(PR_SAMPLE_FLAGS, lpPropArray).Value.ul) & PR_SAMPLE_FLAG_PEER_TO_PEER) != 0;
  121.     lpszMyDir = ArrayIndex(PR_SAMPLE_OUTBOUND_DIR, lpPropArray).Value.LPSZ;
  122.     PrintfTransportLog(TEXT("Start Outbound: %s"),
  123.         ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpPropArray).Value.LPSZ);
  124.     /* Reset the timer for SpoolerYield() */
  125.     HrCheckSpoolerYield(lpMAPISup, TRUE);
  126.     /* Check if we are to defer this message */
  127.     hResult = lpMessage->lpVtbl->GetProps(lpMessage,
  128.         (LPSPropTagArray) &sptMsgDefer, 0, /* ansi */
  129.         &cValues, &lpMsgProps);
  130.     if (HR_FAILED(hResult))
  131.     {
  132.         DebugTrace("Failed getting props on the message.n");
  133.         goto ret;
  134.     }
  135.     /* We'll default fResendDeferred to TRUE unless we defer this msg */
  136.     lpxpl->fResendDeferred = TRUE;
  137.     /* If PR_SAMPLE_PER_MSG_DEFER exists and is TRUE, then we delete
  138.        this property from the message, and add this message to our
  139.        deferred list.  The lpulMsgRef is set to the value assigned to
  140.        the node in our list.  When EndMessage is called we search for
  141.        this Ref in to list.  If found, we return END_DONT_RESEND,
  142.        causing the spooler to defer the msg. */
  143.     if (lpMsgProps->ulPropTag == PR_SAMPLE_PER_MSG_DEFER)
  144.     {
  145.         lpMessage->lpVtbl->DeleteProps(lpMessage,
  146.             (LPSPropTagArray) &sptMsgDefer, NULL);
  147.         lpMessage->lpVtbl->SaveChanges(lpMessage, KEEP_OPEN_READWRITE);
  148.         if (lpMsgProps->Value.b == TRUE)
  149.         {
  150.             hResult = HrAddDeferred(lpxpl, lpMessage, lpulMsgRef);
  151.             goto ret;
  152.         }
  153.     }
  154.     /* Now, see if any Recipients have PR_SAMPLE_PER_RECIP_DEFER set to
  155.        TRUE in the RecipientTable.  If so, then slam a non-transmittable
  156.        property into the message to indicate we've deferred this message
  157.        for some recipients this time around.  If this property already
  158.        exists, then we know it has already been deferred and we should
  159.        just go ahead and send to all un-handled recipients.              */
  160.     if (lpMsgProps[1].ulPropTag == PR_SAMPLE_PER_RECIP_DEFER)
  161.     {
  162.         lpMessage->lpVtbl->DeleteProps(lpMessage,
  163.             (LPSPropTagArray) &sptMsgDefer, NULL);
  164.         lpMessage->lpVtbl->SaveChanges(lpMessage, KEEP_OPEN_READWRITE);
  165.         /*  Initialize a restriction -- we'll need it soon. */
  166.         srRecipUnsent.rt = RES_PROPERTY;
  167.         srRecipUnsent.res.resProperty.relop = RELOP_EQ;
  168.         srRecipUnsent.res.resProperty.ulPropTag = PR_RESPONSIBILITY;
  169.         srRecipUnsent.res.resProperty.lpProp = &spvRecipUnsent;
  170.     }
  171.     else
  172.     {
  173.         SRestriction srRecipDefer;
  174.         srRecipDefer.rt = RES_PROPERTY;
  175.         srRecipDefer.res.resProperty.relop = RELOP_EQ;
  176.         srRecipDefer.res.resProperty.ulPropTag = PR_SAMPLE_PER_RECIP_DEFER;
  177.         srRecipDefer.res.resProperty.lpProp = &spvRecipDefer;
  178.         hResult = lpMessage->lpVtbl->GetRecipientTable(
  179.             lpMessage, 0L, &lpTable);
  180.         if (hResult)
  181.         {
  182.             DebugTrace("GetRecipientTable failed in SubmitMessage.n");
  183.             goto ret;
  184.         }
  185.         hResult = lpTable->lpVtbl->FindRow(lpTable, &srRecipDefer,
  186.             BOOKMARK_BEGINNING, 0);
  187.         /* Check our .2 second timer! */
  188.         sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
  189.         if (sc == MAPI_W_CANCEL_MESSAGE)
  190.         {
  191.             DebugTrace("Cancelling message delivery.n");
  192.             goto ret;
  193.         }
  194.         if (GetScode(hResult) != MAPI_E_NOT_FOUND)
  195.         {
  196.             hResult = HrAddDeferred(lpxpl, lpMessage, lpulMsgRef);
  197.             if (HR_FAILED(hResult))
  198.             {
  199.                 DebugTrace("HrAddDeferred failed doing a per-recip deferral.n");
  200.                 goto ret;
  201.             }
  202.         }
  203.         else
  204.         {
  205.             hResult = lpTable->lpVtbl->SeekRow(lpTable,
  206.                 BOOKMARK_BEGINNING, 0L, NULL);
  207.         }
  208.         /*  Initialize a restriction -- we'll need it soon. */
  209.         spvRecipDefer.Value.b = FALSE;
  210.         srExist.rt = RES_EXIST;
  211.         srExist.res.resExist.ulPropTag = PR_SAMPLE_PER_RECIP_DEFER;
  212.         rgsrOr[0].rt = RES_NOT;
  213.         rgsrOr[0].res.resNot.lpRes = &srExist;
  214.         rgsrOr[1].rt = RES_PROPERTY;
  215.         rgsrOr[1].res.resProperty.relop = RELOP_EQ;
  216.         rgsrOr[1].res.resProperty.ulPropTag = PR_SAMPLE_PER_RECIP_DEFER;
  217.         rgsrOr[1].res.resProperty.lpProp = &spvRecipDefer;
  218.         rgsrAnd[0].rt = RES_PROPERTY;
  219.         rgsrAnd[0].res.resProperty.relop = RELOP_EQ;
  220.         rgsrAnd[0].res.resProperty.ulPropTag = PR_RESPONSIBILITY;
  221.         rgsrAnd[0].res.resProperty.lpProp = &spvRecipUnsent;
  222.         rgsrAnd[1].rt = RES_OR;
  223.         rgsrAnd[1].res.resOr.cRes = 2;
  224.         rgsrAnd[1].res.resOr.lpRes = rgsrOr;
  225.         srRecipUnsent.rt = RES_AND;
  226.         srRecipUnsent.res.resAnd.cRes = 2;
  227.         srRecipUnsent.res.resAnd.lpRes = rgsrAnd;
  228.     }
  229.     /* Check our .2 second timer before attempting to send */
  230.     sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
  231.     if (sc == MAPI_W_CANCEL_MESSAGE)
  232.     {
  233.         DebugTrace("Cancelling message delivery.n");
  234.         goto ret;
  235.     }
  236.     /*  If not peer-to-peer, "send message" to our outbound directory. */
  237.     if (!fPeer2Peer)
  238.     {
  239.         BOOL fSent;
  240.         hResult = HrSendOneMessage(lpxpl, lpPropArray,
  241.                 lpMessage, 0, lpszMyDir, &fSent);
  242.         if (hResult)
  243.         {
  244.             DebugTrace("Copying message to outbound failed.n");
  245.             goto ret;
  246.         }
  247.     }
  248.     /*  If we are peer-to-peer, send to all our recipients. */
  249.     else
  250.     {
  251.         /*  Get the recipient table from the message if we haven't already */
  252.         if (!lpTable)
  253.         {
  254.             hResult = lpMessage->lpVtbl->GetRecipientTable(
  255.                 lpMessage, 0L, &lpTable);
  256.             if (hResult)
  257.             {
  258.                 DebugTrace("GetRecipientTable failed in SubmitMessage.n");
  259.                 goto ret;
  260.             }
  261.         }
  262.         /*  Restrict to all unsent recipients */
  263.         hResult = lpTable->lpVtbl->Restrict(lpTable, &srRecipUnsent, 0L);
  264.         if (hResult)
  265.         {
  266.             DebugTrace("Restriction on recipient table  failed in SubmitMessage.n");
  267.             goto ret;
  268.         }
  269.         /* Check our .2 second timer! */
  270.         sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
  271.         if (sc == MAPI_W_CANCEL_MESSAGE)
  272.         {
  273.             DebugTrace("Cancelling message delivery.n");
  274.             goto ret;
  275.         }
  276.         /*  Send to the recipients which we can reach, and build ADRLISTs of
  277.             the sent and unsent recipients */
  278.         hResult = HrBuildAdrList(lpxpl, lpPropArray, lpMessage, lpTable,
  279.                 TRUE, HrSendOneMessage, &lpMyAdrListDone, &lpMyAdrListNotDone);
  280.         if (hResult)
  281.         {
  282.             DebugTrace("HrBuildAdrList failed in SubmitMessage.n");
  283.             goto ret;
  284.         }
  285.         /*  No error, do we have some recipients? If so, do the ModifyRecipients(). */
  286.         if (lpMyAdrListDone)
  287.         {
  288.             hResult = lpMessage->lpVtbl->ModifyRecipients(lpMessage,
  289.                     MODRECIP_MODIFY, lpMyAdrListDone->lpAdrList);
  290.             if (hResult)
  291.             {
  292.                 DebugTrace("ModifyRecipients failed in SubmitMessage.n");
  293.                 goto ret;
  294.             }
  295.             /* Now we need to save changes on the message. */
  296.             hResult = lpMessage->lpVtbl->SaveChanges(lpMessage,
  297.                     lpMyAdrListNotDone ? KEEP_OPEN_READWRITE : 0L);
  298.             if (hResult)
  299.             {
  300.                 DebugTrace("SaveChanges failed in SubmitMessage.n");
  301.                 goto ret;
  302.             }
  303.         }
  304.         /*  Check for unsent recipients. If there were any, we need to NDR
  305.             them and (finally) mark them as taken. If there were not any,
  306.             we're really finished and can just go and release the message. */
  307.         if (!lpMyAdrListNotDone)
  308.             goto ret;
  309.         hResult = lpMAPISup->lpVtbl->StatusRecips(lpMAPISup,
  310.                 lpMessage, lpMyAdrListNotDone->lpAdrList);
  311.         if (HR_FAILED(hResult))
  312.         {
  313.             DebugTrace("StatusRecips failed in SubmitMessage.n");
  314.             goto ret;
  315.         }
  316.         /*  StatusRecips killed the ADRLIST so zero out our pointer. */
  317.         lpMyAdrListNotDone->lpAdrList = NULL;
  318.         /* Get rid of the MYADRLISTs. */
  319.         FreeMyAdrList(lpxpl, lpMyAdrListDone);
  320.         FreeMyAdrList(lpxpl, lpMyAdrListNotDone);
  321.         lpMyAdrListDone = lpMyAdrListNotDone = NULL;
  322.         /*  Free the recipient table. */
  323.         lpTable->lpVtbl->Release(lpTable);
  324.         lpTable = NULL;
  325.     }
  326.     /* Check our .2 second timer after attempting to send */
  327.     sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
  328.     if (sc == MAPI_W_CANCEL_MESSAGE)
  329.     {
  330.         DebugTrace("Cancelling message delivery.n");
  331.         goto ret;
  332.     }
  333.     /*  At this point we have either:
  334.         a)  If not peer-to-peer, made a single container file in
  335.             the outbound directory
  336.         b)  If peer-to-peer, created a container file in every
  337.             inbound directory we were able to reach (but not all
  338.             of them) -- and have NDR'ed the ones we could not reach
  339.         All that remains to do is to mark all unsent recipients as
  340.         handled, since in the non-peer case the creation of the
  341.         container suffices as "handling" and in the peer case the
  342.         NDR message also does this.
  343.     */
  344.     hResult = lpMessage->lpVtbl->GetRecipientTable(lpMessage, 0L, &lpTable);
  345.     if (hResult)
  346.     {
  347.         DebugTrace("Second GetRecipientTable failed in SubmitMessage.n");
  348.         goto ret;
  349.     }
  350.     /*  Restrict the recipient table to the remaining unsent */
  351.     hResult = lpTable->lpVtbl->Restrict(lpTable, &srRecipUnsent, 0L);
  352.     if (hResult)
  353.     {
  354.         DebugTrace("Restriction on recipient table failed.n");
  355.         goto ret;
  356.     }
  357.     /*  Build the ADRLIST of the unsent recipients */
  358.     hResult = HrBuildAdrList(lpxpl, lpPropArray, lpMessage, lpTable,
  359.             TRUE, NULL,  &lpMyAdrListDone, &lpMyAdrListNotDone);
  360.     if (hResult)
  361.     {
  362.         DebugTrace("HrBuildAdrList failed in SubmitMessage.n");
  363.         goto ret;
  364.     }
  365.     Assert(!lpMyAdrListNotDone);
  366.     /*  No error, do we have some recipients? If so, do the ModifyRecipients(). */
  367.     if (lpMyAdrListDone)
  368.     {
  369.         hResult = lpMessage->lpVtbl->ModifyRecipients(lpMessage,
  370.                 MODRECIP_MODIFY, lpMyAdrListDone->lpAdrList);
  371.         if (hResult)
  372.         {
  373.             DebugTrace("ModifyRecipients failed in SubmitMessage.n");
  374.             goto ret;
  375.         }
  376.     }
  377.     /*  Release the table, we're finished with it */
  378.     UlRelease(lpTable);
  379.     lpTable = NULL;
  380.     /* With the recipient table work done, save changes again. */
  381.     hResult = lpMessage->lpVtbl->SaveChanges(lpMessage, 0L);
  382.     if (hResult)
  383.     {
  384.         DebugTrace("SaveChanges failed in SubmitMessage.n");
  385.         goto ret;
  386.     }
  387.     PrintfTransportLog(TEXT("End Outbound: %s"),
  388.         ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpPropArray).Value.LPSZ);
  389. ret:
  390.     /* Free-Up Memory */
  391.     lpxpl->FreeBuffer(lpPropArray);
  392.     lpxpl->FreeBuffer(lpMsgProps);
  393.     /* Get rid of any MYADRLISTs. */
  394.     FreeMyAdrList(lpxpl, lpMyAdrListDone);
  395.     FreeMyAdrList(lpxpl, lpMyAdrListNotDone);
  396.     /* Release any open table */
  397.     UlRelease(lpTable);
  398.     /* Release the spooler's message if need be */
  399.     UlRelease(lpMessage);
  400.     /* Reset upload status if set. If this errors, use the error only
  401.        if no other error had occurred here. */
  402.     if (fUpdatedStatus)
  403.     {
  404.         lpxpl->ulTransportStatus &= ~STATUS_OUTBOUND_ACTIVE;
  405.         (void)HrUpdateTransportStatus(lpxpl, 0L);
  406.     }
  407.     DebugTraceResult(XPL_SubmitMessage, hResult);
  408.     return hResult;
  409. }
  410. /*
  411.  -  XPL_EndMessage
  412.  -
  413.  *  Purpose:
  414.  *      Called by the Spooler to complete transmission of a message.
  415.  *
  416.  *  Parameters:
  417.  *      ulMsgRef            Opaque identifier from SubmitMessage
  418.  *      lpulFlags           Pointer to where the transport should
  419.  *                          store special flags on return. This
  420.  *                          Transport doesn't use any.
  421.  *
  422.  *  Returns:
  423.  *      (HRESULT)           Success.
  424.  *
  425.  *  Operation:
  426.  *      Clears unsigned long status, and returns success.
  427.  */
  428. STDMETHODIMP
  429. XPL_EndMessage(LPXPL lpxpl, ULONG ulMsgRef, ULONG * lpulFlags)
  430. {
  431.     LPDEFMSG lpDefMsg;
  432.     Assert(!IsBadWritePtr(lpulFlags, sizeof(ULONG)));
  433.     *lpulFlags = 0L;
  434.     /* If the ulMsgRef is non zero, look for it in the deferred
  435.        list.  If found, return END_DONT_RESEND to the Spooler.  */
  436.     if (ulMsgRef)
  437.     {
  438.         lpDefMsg = lpxpl->lpDeferredList;
  439.         while (lpDefMsg)
  440.         {
  441.             if (lpDefMsg->ulMsgRef == ulMsgRef)
  442.             {
  443.                 *lpulFlags = END_DONT_RESEND;
  444.                 break;
  445.             }
  446.         }
  447.     }
  448.     return hrSuccess;
  449. }
  450. /*
  451.  -  HrAddDeferred
  452.  -
  453.  *  Purpose:
  454.  *      Adds the EntryID and ulMsgRef of a message we are deferring
  455.  *      to our list of deferred message.
  456.  *
  457.  *  Parameters:
  458.  *      lpxpl           Transport session
  459.  *      lpMsg           The message we wish to defer
  460.  *      lpulMsgRef      Receives the reference we assign to this message
  461.  *
  462.  *  Returns:
  463.  *      hResult         Indicating Success/Failure
  464.  */
  465. HRESULT
  466. HrAddDeferred(LPXPL lpxpl, LPMESSAGE lpMsg, ULONG *lpulMsgRef)
  467. {
  468.     HRESULT hResult;
  469.     SCODE sc;
  470.     LPDEFMSG lpDefMsg = NULL;
  471.     ULONG cVals;
  472.     LPSPropValue lpEIDProp = NULL;
  473.     static SPropTagArray spta = {1, {PR_ENTRYID}};
  474.     /* Allocate a new DefMsg node */
  475.     sc = lpxpl->AllocateBuffer(sizeof(DEFMSG), (LPVOID *)&lpDefMsg);
  476.     if (FAILED(sc))
  477.     {
  478.         hResult = ResultFromScode(sc);
  479.         DebugTrace("Allocation failed in HrAddDeferred.n");
  480.         goto ret;
  481.     }
  482.     /* Get the EntryID of the message we are deferring */
  483.     hResult = lpMsg->lpVtbl->GetProps(lpMsg, &spta, 0, &cVals, &lpEIDProp);
  484.     if (HR_FAILED(hResult))
  485.     {
  486.         DebugTrace("GetProps failed in HrAddDeferred.n");
  487.         goto ret;
  488.     }
  489.     Assert(cVals == 1);
  490.     Assert(lpEIDProp);
  491.     Assert(lpEIDProp->ulPropTag == PR_ENTRYID);
  492.     /* We'll make our own copy of the EntryID */
  493.     sc = lpxpl->AllocateMore(lpEIDProp->Value.bin.cb, (LPVOID)lpDefMsg,
  494.             (LPVOID *)&(lpDefMsg->sbinEIDDef.lpb));
  495.     if (FAILED(sc))
  496.     {
  497.         hResult = ResultFromScode(sc);
  498.         DebugTrace("Allocation failed in HrAddDeferred.n");
  499.         goto ret;
  500.     }
  501.     /* Fill in this new node and add it to the list */
  502.     lpDefMsg->sbinEIDDef.cb = lpEIDProp->Value.bin.cb;
  503.     memcpy(lpDefMsg->sbinEIDDef.lpb, lpEIDProp->Value.bin.lpb,
  504.             (UINT)lpDefMsg->sbinEIDDef.cb);
  505.     lpDefMsg->ulMsgRef = ++lpxpl->ulDeferredMsgRef;
  506.     lpDefMsg->lpNext = lpxpl->lpDeferredList;
  507.     lpxpl->lpDeferredList = lpDefMsg;
  508.     lpxpl->fResendDeferred = FALSE;
  509.     *lpulMsgRef = lpDefMsg->ulMsgRef;
  510. ret:
  511.     if (HR_FAILED(hResult))
  512.         lpxpl->FreeBuffer(lpDefMsg);
  513.     lpxpl->FreeBuffer(lpEIDProp);
  514.     DebugTraceResult(HrAddDeferred, hResult);
  515.     return hResult;
  516. }