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 / peer.xp / xpoption.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  22.3 KB  |  849 lines

  1. /*
  2.  -  X P O P T I O N . C
  3.  -
  4.  *  Purpose:
  5.  *      Defines a wrapped implementation of an IMAPIProp interface
  6.  *      to be used by ScMsgOptionCallBack() and ScRecipOptionCallBack()
  7.  *      to wrap the IMAPIProp passed in.  This object is wrapped so we
  8.  *      can effect the behavior of the OpenProperty() call.  Specifically,
  9.  *      we wish to put up a Property Sheet when the user tries to open
  10.  *      the PR_DETAILS_TABLE property.
  11.  *
  12.  *      This file overloads the OpenProperty() method on the Wrapped
  13.  *      IMAPIProp in order to slam properties from a Display Table
  14.  *      into the underlying message object.  It also creates the
  15.  *      Display Table used by IMAPISession::MessageOptions().
  16.  *
  17.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  18.  */
  19.  
  20. #include "xppch.h"
  21. #include "xpresrc.h"
  22. #include "xpoption.h"
  23. #include <mapiutil.h>
  24.  
  25. /* Generic control structures */
  26.  
  27. DTBLPAGE dtblMsgOptPage =
  28. {sizeof(DTBLPAGE), 0, 0, 0};
  29. DTBLPAGE dtblRecipOptPage =
  30. {sizeof(DTBLPAGE), 0, 0, 0};
  31.  
  32. /* Display table control structures for the General property sheet. */
  33.  
  34. DTBLCHECKBOX chkPerMsgDefer =
  35. {sizeof(DTBLCHECKBOX), fMapiUnicode,
  36.     PR_SAMPLE_PER_MSG_DEFER};
  37. DTBLCHECKBOX chkPerRecipDefer =
  38. {sizeof(DTBLCHECKBOX), fMapiUnicode,
  39.     PR_SAMPLE_PER_RECIP_DEFER};
  40.  
  41. DTCTL rgdtctlMsgOpt[] =
  42. {
  43.     {DTCT_PAGE, 0, NULL, 0, NULL, 0, &dtblMsgOptPage},
  44.     {DTCT_CHECKBOX, DT_EDITABLE, NULL, 0, NULL, IDC_PER_MSG_DEFER, &chkPerMsgDefer}
  45. };
  46.  
  47. DTCTL rgdtctlRecipOpt[] =
  48. {
  49.     {DTCT_PAGE, 0, NULL, 0, NULL, 0, &dtblRecipOptPage},
  50.     {DTCT_CHECKBOX, DT_EDITABLE, NULL, 0, NULL, IDC_PER_RECIP_DEFER, &chkPerRecipDefer}
  51. };
  52.  
  53.  
  54. /* Display table pages */
  55.  
  56. DTPAGE rgdtpageMsgOpt[] =
  57. {
  58.     {
  59.         sizeof(rgdtctlMsgOpt) / sizeof(DTCTL),
  60.         (LPTSTR) MAKEINTRESOURCE(PerMsgOpt),
  61.         "",
  62.         rgdtctlMsgOpt
  63.     }
  64. };
  65.  
  66.  
  67. DTPAGE rgdtpageRecipOpt[] =
  68. {
  69.     {
  70.         sizeof(rgdtctlRecipOpt) / sizeof(DTCTL),
  71.         (LPTSTR) MAKEINTRESOURCE(PerRecipOpt),
  72.         "",
  73.         rgdtctlRecipOpt
  74.     }
  75. };
  76.  
  77.  
  78. /*
  79.  *  WMProp jump table is defined here...
  80.  */
  81.  
  82. WMPROP_Vtbl vtblOPT =
  83. {
  84.     WMPROP_QueryInterface,
  85.     WMPROP_AddRef,
  86.     WMPROP_Release,
  87.     WMPROP_GetLastError,
  88.     WMPROP_SaveChanges,
  89.     WMPROP_GetProps,
  90.     WMPROP_GetPropList,
  91.     WMPROP_OpenProperty,
  92.     WMPROP_SetProps,
  93.     WMPROP_DeleteProps,
  94.     WMPROP_CopyTo,
  95.     WMPROP_CopyProps,
  96.     WMPROP_GetNamesFromIDs,
  97.     WMPROP_GetIDsFromNames,
  98. };
  99.  
  100.  
  101. /*
  102.  *  Private functions prototypes
  103.  */
  104.  
  105. SCODE ScNewWrappedMAPIProp(
  106.     LPMAPIPROP lpMAPIProp,
  107.     HINSTANCE hInst,
  108.     LPMALLOC lpMalloc,
  109.     ULONG ulType,
  110.     ULONG cbOptionData,
  111.     LPBYTE lpbOptionData,
  112.     LPMAPISUP lpMAPISup,
  113.     LPWMPROP * lppWMProp);
  114.  
  115. OPTIONCALLBACK ScOptionDataCallBack;
  116.  
  117.  
  118. /*
  119.  -  ScOptionDataCallBack
  120.  -
  121.  *  Purpose:
  122.  *      Gets called by MAPI to wrap the source IMessage in
  123.  *      preparation to Display Table calls.
  124.  *
  125.  *  Parameters:
  126.  *      hInst               - Instance of myself from LoadLibrary call
  127.  *      lpMalloc            - OLE 2.0 style allocator
  128.  *      ulFlags             - OPTION_TYPE_MESSAGE | OPTION_TYPE_RECIPIENT
  129.  *      cbOptionData        - Size of OptionData I sent at Register time
  130.  *      lpbOptionData       - OptionData I sent at Register time
  131.  *      lpMAPISup           - A support object for mem routines
  132.  *      lpDataSource        - Underlying IMessage object
  133.  *      lppWrappedSource    - Returned wrapped version of lpDataSource
  134.  *      lppszErrorMsg       - Context sensitive error msg for MAPI
  135.  *      lppszErrorComponent - Help filename if one exists
  136.  *      lpulErrorContext    - Context in Help File
  137.  *
  138.  *  Returns:
  139.  *      sc                  - Scode of failure if any
  140.  */
  141.  
  142. STDINITMETHODIMP_(SCODE)
  143. ScOptionDataCallBack(
  144.     HINSTANCE hInst,
  145.     LPMALLOC lpMalloc,
  146.     ULONG ulFlags,
  147.     ULONG cbOptionData,
  148.     LPBYTE lpbOptionData,
  149.     LPMAPISUP lpMAPISup,
  150.     LPMAPIPROP lpDataSource,
  151.     LPMAPIPROP FAR * lppWrappedSource,
  152.     LPMAPIERROR FAR * lppMapiError )
  153. {
  154.     SCODE sc;
  155.     LPWMPROP lpWMProp = NULL;
  156.  
  157.     /* Do Parameter Validation Now */
  158.  
  159. #ifdef _WIN32
  160.     if (!hInst)
  161. #else
  162.     if (hInst < HINSTANCE_ERROR)
  163. #endif
  164.     {
  165.         DebugTrace("ScOptionDataCallBack() - Invalid hInst");
  166.         return E_INVALIDARG;
  167.     }
  168.  
  169.     if (ulFlags & (~(OPTION_TYPE_MESSAGE | OPTION_TYPE_RECIPIENT)))
  170.     {
  171.         DebugTrace("ScOptionDataCallBack() - Unknown ulFlags!");
  172.         return E_INVALIDARG;
  173.     }
  174.  
  175.     if (cbOptionData && !lpbOptionData)
  176.     {
  177.         DebugTrace("ScOptionDataCallBack() - Invalid lpbOptionData");
  178.         return E_INVALIDARG;
  179.     }
  180.  
  181.     if (cbOptionData)
  182.     {
  183.         if (IsBadReadPtr(lpbOptionData, (UINT) cbOptionData))
  184.         {
  185.             DebugTrace("ScOptionDataCallBack() - Invalid lpbOptionData");
  186.             return E_INVALIDARG;
  187.         }
  188.     }
  189.  
  190.     if (!lpMAPISup || IsBadReadPtr(lpMAPISup, sizeof(LPVOID)))
  191.     {
  192.         DebugTrace("ScOptionDataCallBack() - Invalid lpMAPISup");
  193.         return E_INVALIDARG;
  194.     }
  195.  
  196.     if (!lpDataSource || IsBadReadPtr(lpDataSource, sizeof(LPVOID)))
  197.     {
  198.         DebugTrace("ScOptionDataCallBack() - Invalid lpDataSource");
  199.         return E_INVALIDARG;
  200.     }
  201.  
  202.     if (!lppWrappedSource || IsBadWritePtr(lppWrappedSource, sizeof(LPVOID)))
  203.     {
  204.         DebugTrace("ScOptionDataCallBack() - Invalid lppWrappedSource");
  205.         return E_INVALIDARG;
  206.     }
  207.  
  208.     if (!lppMapiError || IsBadWritePtr(lppMapiError, sizeof(LPMAPIERROR)))
  209.     {
  210.         DebugTrace("ScOptionDataCallBack() - Invalid lppMapiError");
  211.         return E_INVALIDARG;
  212.     }
  213.  
  214.     *lppWrappedSource = NULL;
  215.     *lppMapiError = NULL;
  216.  
  217.     /* Everything is OK, Lets build the Wrapped Source now. */
  218.  
  219.     sc = ScNewWrappedMAPIProp(lpDataSource, hInst, lpMalloc, ulFlags, 
  220.             cbOptionData, lpbOptionData, lpMAPISup, &lpWMProp);
  221.  
  222.     if (sc)
  223.         goto ret;
  224.  
  225.     *lppWrappedSource = (LPMAPIPROP) lpWMProp;
  226.  
  227. ret:
  228.     return sc;
  229. }
  230.  
  231.  
  232. /*
  233.  -  ScNewWrappedMAPIProp
  234.  -
  235.  *  Purpose:
  236.  *      Creates a wrapped Per-Message or Per-Recipient Options
  237.  *      property interface to pass back to caller.  All methods
  238.  *      call through to the base class except OpenProperty(),
  239.  *      which intercepts PR_DETAILS_TABLE and creates a Display
  240.  *      Table to pass back to the caller.
  241.  *
  242.  *  Parameters:
  243.  *      lpMAPIProp          - The Property Interface to wrapper (an IMsg)
  244.  *      lpXPLogon           - The opaque XP Logon object
  245.  *      hInst               - My hInst of this DLL
  246.  *      ulType              - Either OPTION_TYPE_MESSAGE or _RECIPIENT
  247.  *      cbOptionData        - Size of my OptionData blob
  248.  *      lpbOptionData       - My OptionData blob
  249.  *      lpMAPISup           - Needed for memory alloc routines
  250.  *      lppWMProp           - Returned wrapped IMAPIProp object
  251.  *
  252.  *  Returns:
  253.  *      sc                  - Indicating Success/Failure
  254.  */
  255.  
  256. SCODE
  257. ScNewWrappedMAPIProp(
  258.     LPMAPIPROP lpMAPIProp,
  259.     HINSTANCE hInst,
  260.     LPMALLOC lpMalloc,
  261.     ULONG ulType,
  262.     ULONG cbOptionData,
  263.     LPBYTE lpbOptionData,
  264.     LPMAPISUP lpMAPISup,
  265.     LPWMPROP FAR * lppWMProp)
  266. {
  267.     HRESULT hr;
  268.     SCODE sc;
  269.     LPWMPROP lpWMProp = NULL;
  270.     LPBYTE lpb = NULL;
  271.     LPALLOCATEBUFFER lpAllocBuff = NULL;
  272.     LPALLOCATEMORE lpAllocMore = NULL;
  273.     LPFREEBUFFER lpFreeBuff = NULL;
  274.  
  275.     hr = lpMAPISup->lpVtbl->GetMemAllocRoutines(lpMAPISup,
  276.         &lpAllocBuff, &lpAllocMore, &lpFreeBuff);
  277.  
  278.     if (hr)
  279.     {
  280.         sc = GetScode(hr);
  281.         goto ret;
  282.     }
  283.  
  284.     sc = (*lpAllocBuff) (sizeof(WMPROP), &lpWMProp);
  285.  
  286.     if (sc)
  287.     {
  288.         goto ret;
  289.     }
  290.  
  291.     lpWMProp->lpVtbl = &vtblOPT;
  292.     lpWMProp->lcInit = 1;
  293.     lpWMProp->lpAllocBuff = lpAllocBuff;
  294.     lpWMProp->lpAllocMore = lpAllocMore;
  295.     lpWMProp->lpFreeBuff = lpFreeBuff;
  296.     lpWMProp->hInst = hInst;
  297.     lpWMProp->lpMalloc = lpMalloc;
  298.     lpWMProp->ulType = ulType;
  299.     lpWMProp->lpMAPIProp = lpMAPIProp;
  300.  
  301.     if (cbOptionData)
  302.     {
  303.         sc = (*lpAllocMore) (cbOptionData, lpWMProp, &lpb);
  304.  
  305.         if (sc)
  306.         {
  307.             goto ret;
  308.         }
  309.  
  310.         memcpy(lpb, lpbOptionData, (UINT) cbOptionData);
  311.  
  312.         lpWMProp->cbOptionData = cbOptionData;
  313.         lpWMProp->lpbOptionData = lpb;
  314.     }
  315.  
  316.     lpMalloc->lpVtbl->AddRef(lpMalloc);
  317.     lpMAPIProp->lpVtbl->AddRef(lpMAPIProp);
  318.  
  319.     *lppWMProp = lpWMProp;
  320.  
  321. ret:
  322.     if (sc && lpFreeBuff)
  323.         (*lpFreeBuff) (lpWMProp);
  324.  
  325.     return sc;
  326. }
  327.  
  328.  
  329. /*
  330.  -  WMPROP_OpenProperty
  331.  -
  332.  *  Purpose:
  333.  *      Traps a request to OpenProperty() on PR_DETAILS_TABLE so I
  334.  *      can supply a DisplayTable for the user.  Else, passes the
  335.  *      request to the underlying object.
  336.  *
  337.  */
  338.  
  339. STDMETHODIMP
  340. WMPROP_OpenProperty(
  341.     LPWMPROP lpWMProp,
  342.     ULONG ulPropTag,
  343.     LPCIID lpiid,
  344.     ULONG ulInterfaceOptions,
  345.     ULONG ulFlags,
  346.     LPUNKNOWN * lppUnk)
  347. {
  348.     HRESULT hResult;
  349.  
  350.     /* Check to see if it has a jump table */
  351.  
  352.     if (FBadUnknown(lpWMProp))
  353.     {
  354.         hResult = ResultFromScode(E_INVALIDARG);
  355.         DebugTraceResult(WMPROP_OpenProperty, hResult);
  356.         return hResult;
  357.     }
  358.  
  359.     /* Check to see that it's the correct jump table */
  360.  
  361.     if (lpWMProp->lpVtbl != &vtblOPT)
  362.     {
  363.         hResult = ResultFromScode(E_INVALIDARG);
  364.         DebugTraceResult(WMPROP_OpenProperty, hResult);
  365.         return hResult;
  366.     }
  367.  
  368.     if (IsBadWritePtr(lpWMProp->lpVtbl, offsetof(WMPROP_Vtbl, OpenProperty)))
  369.     {
  370.         hResult = ResultFromScode(E_INVALIDARG);
  371.         DebugTraceResult(WMPROP_OpenProperty, hResult);
  372.         return hResult;
  373.     }
  374.  
  375.     if ( ulInterfaceOptions & ~MAPI_UNICODE )
  376.     {
  377.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  378.         DebugTraceResult(WMPROP_OpenProperty, hResult);
  379.         return hResult;
  380.     }
  381.     
  382.     if ( ulInterfaceOptions & MAPI_UNICODE )
  383.     {
  384.         hResult = ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  385.         DebugTraceResult(WMPROP_OpenProperty, hResult);
  386.         return hResult;
  387.     }
  388.     
  389.     /* PR_DETAILS_TABLE is the secret code for "DisplayTable" */
  390.  
  391.     if (ulPropTag == PR_DETAILS_TABLE)
  392.     {
  393.         /* Check to see if they're expecting a table interface */
  394.  
  395.         if (memcmp(lpiid, &IID_IMAPITable, sizeof(IID)))
  396.         {
  397.             hResult = ResultFromScode(E_NOINTERFACE);
  398.             goto ret;
  399.         }
  400.  
  401.         if (lpWMProp->ulType == OPTION_TYPE_MESSAGE)
  402.         {
  403.             hResult = BuildDisplayTable(
  404.                 lpWMProp->lpAllocBuff,
  405.                 lpWMProp->lpAllocMore,
  406.                 lpWMProp->lpFreeBuff,
  407.                 lpWMProp->lpMalloc,
  408.                 lpWMProp->hInst,
  409.                 sizeof(rgdtpageMsgOpt) / sizeof(DTPAGE),
  410.                 rgdtpageMsgOpt,
  411.                 0,
  412.                 (LPMAPITABLE FAR *) lppUnk,
  413.                 NULL);
  414.         }
  415.         else
  416.         {
  417.             Assert(lpWMProp->ulType == OPTION_TYPE_RECIPIENT);
  418.  
  419.             hResult = BuildDisplayTable(
  420.                 lpWMProp->lpAllocBuff,
  421.                 lpWMProp->lpAllocMore,
  422.                 lpWMProp->lpFreeBuff,
  423.                 lpWMProp->lpMalloc,
  424.                 lpWMProp->hInst,
  425.                 sizeof(rgdtpageRecipOpt) / sizeof(DTPAGE),
  426.                 rgdtpageRecipOpt,
  427.                 0,
  428.                 (LPMAPITABLE FAR *) lppUnk,
  429.                 NULL);
  430.         }
  431.     }
  432.     else
  433.     {
  434.         hResult = lpWMProp->lpMAPIProp->lpVtbl->OpenProperty(
  435.             lpWMProp->lpMAPIProp, ulPropTag, lpiid,
  436.             ulInterfaceOptions, ulFlags, lppUnk);
  437.     }
  438.  
  439. ret:
  440.     DebugTraceResult(WMPROP_OpenProperty, hResult);
  441.     return hResult;
  442. }
  443.  
  444.  
  445. /*
  446.  -  WMPROP_QueryInterface
  447.  -  WMPROP_AddRef
  448.  -  WMPROP_Release
  449.  *
  450.  *  Purpose:
  451.  *      Wrapped version of the IUnknown methods.
  452.  */
  453.  
  454. STDMETHODIMP
  455. WMPROP_QueryInterface(
  456.     LPWMPROP lpWMProp,
  457.     REFIID lpiid,
  458.     LPVOID * lppNewObj)
  459. {
  460.     /* Check to see if it has a jump table */
  461.  
  462.     if (FBadUnknown(lpWMProp))
  463.     {
  464.         DebugTraceSc(WMPROP_QueryInterface, E_INVALIDARG);
  465.         return ResultFromScode(E_INVALIDARG);
  466.     }
  467.  
  468.     /* Check to see if the method is the same */
  469.  
  470.     if (WMPROP_QueryInterface != lpWMProp->lpVtbl->QueryInterface)
  471.     {
  472.         DebugTraceSc(WMPROP_QueryInterface, E_INVALIDARG);
  473.         return ResultFromScode(E_INVALIDARG);
  474.     }
  475.  
  476.     /*  Call the internal prop interface */
  477.  
  478.     return lpWMProp->lpMAPIProp->lpVtbl->QueryInterface(
  479.         lpWMProp->lpMAPIProp, lpiid, lppNewObj);
  480. }
  481.  
  482.  
  483. STDMETHODIMP_(ULONG)
  484. WMPROP_AddRef(LPWMPROP lpWMProp)
  485. {
  486.     /* Check to see if it has a jump table */
  487.  
  488.     if (FBadUnknown(lpWMProp))
  489.     {
  490.         DebugTrace("Bad lpWMProp in WMPROP_AddRef\n");
  491.         return 1;
  492.     }
  493.  
  494.     /* Check to see if the method is the same */
  495.  
  496.     if (WMPROP_AddRef != lpWMProp->lpVtbl->AddRef)
  497.     {
  498.         DebugTrace("Bad lpWMProp in WMPROP_AddRef\n");
  499.         return 1;
  500.     }
  501.  
  502.     return ++lpWMProp->lcInit;
  503. }
  504.  
  505.  
  506. STDMETHODIMP_(ULONG)
  507. WMPROP_Release(LPWMPROP lpWMProp)
  508. {
  509.     ULONG cRef;
  510.  
  511.     /* Check to see if it has a jump table */
  512.  
  513.     if (FBadUnknown(lpWMProp))
  514.     {
  515.         DebugTrace("Bad lpWMProp in WMPROP_Release\n");
  516.         return 1;
  517.     }
  518.  
  519.     /* Check to see if the method is the same */
  520.  
  521.     if (WMPROP_Release != lpWMProp->lpVtbl->Release)
  522.     {
  523.         DebugTrace("Bad lpWMProp in WMPROP_Release\n");
  524.         return 1;
  525.     }
  526.  
  527.     cRef = --lpWMProp->lcInit;
  528.  
  529.     if (lpWMProp->lcInit == 0)
  530.     {
  531.         /* Release the allocator that was handed to us */
  532.         
  533.         lpWMProp->lpMalloc->lpVtbl->Release(lpWMProp->lpMalloc);
  534.         
  535.         /* Release the underlying IMAPIProp object */
  536.         
  537.         lpWMProp->lpMAPIProp->lpVtbl->Release(lpWMProp->lpMAPIProp);
  538.  
  539.         /* Need to free the object */
  540.  
  541.         (*lpWMProp->lpFreeBuff) (lpWMProp);
  542.     }
  543.  
  544.     return cRef;
  545. }
  546.  
  547.  
  548. /*
  549.  -  WMPROP_GetLastError
  550.  -  WMPROP_SaveChanges
  551.  -  WMPROP_GetProps
  552.  -  WMPROP_GetPropList
  553.  -  WMPROP_OpenProperty
  554.  -  WMPROP_SetProps
  555.  -  WMPROP_DeleteProps
  556.  -  WMPROP_CopyTo
  557.  -  WMPROP_CopyProps
  558.  -  WMPROP_GetNamesFromID
  559.  -  WMPROP_GetIDsFromName
  560.  *
  561.  *  Purpose:
  562.  *      Wrapped version of the IMAPIProp methods.
  563.  */
  564.  
  565. STDMETHODIMP
  566. WMPROP_GetLastError(
  567.     LPWMPROP lpWMProp,
  568.     HRESULT hError,
  569.     ULONG ulFlags,
  570.     LPMAPIERROR FAR * lppMapiError )
  571. {
  572.     /* Validate the object */
  573.  
  574.     if (FBadUnknown(lpWMProp) ||
  575.         IsBadWritePtr(lpWMProp, sizeof(WMPROP)) ||
  576.         IsBadReadPtr(lpWMProp->lpVtbl, offsetof(WMPROP_Vtbl, GetLastError)) ||
  577.         WMPROP_GetLastError != lpWMProp->lpVtbl->GetLastError)
  578.     {
  579.         DebugTraceSc(WMPROP_GetLastError, E_INVALIDARG);
  580.         return ResultFromScode(E_INVALIDARG);
  581.     }
  582.  
  583.     if ( ulFlags & ~MAPI_UNICODE )
  584.     {
  585.         DebugTraceSc(WMPROP_GetLastError, MAPI_E_UNKNOWN_FLAGS);
  586.         return ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  587.     }
  588.     
  589.     if ( ulFlags & MAPI_UNICODE )
  590.     {
  591.         DebugTraceSc(WMPROP_GetLastError, MAPI_E_BAD_CHARWIDTH);
  592.         return ResultFromScode( MAPI_E_BAD_CHARWIDTH );
  593.     }
  594.     
  595.     return lpWMProp->lpMAPIProp->lpVtbl->GetLastError(
  596.             lpWMProp->lpMAPIProp, hError, ulFlags, lppMapiError );
  597. }
  598.  
  599.  
  600. STDMETHODIMP
  601. WMPROP_SaveChanges(
  602.     LPWMPROP lpWMProp,
  603.     ULONG ulFlags)
  604. {
  605.     /* Validate the object */
  606.  
  607.     if (FBadUnknown(lpWMProp) ||
  608.         IsBadWritePtr(lpWMProp, sizeof(WMPROP)) ||
  609.         IsBadReadPtr(lpWMProp->lpVtbl, offsetof(WMPROP_Vtbl, SaveChanges)) ||
  610.         WMPROP_SaveChanges != lpWMProp->lpVtbl->SaveChanges)
  611.     {
  612.         DebugTraceSc(WMPROP_SaveChanges,  E_INVALIDARG);
  613.         return ResultFromScode(E_INVALIDARG);
  614.     }
  615.  
  616.     /*  We don't want to really call SaveChanges() on the underlying object,
  617.         as this would make an incomplete message still under composition
  618.         actually appear in the folder where it was created.
  619.  
  620.         If we had some computed properties here, we should do so (since some
  621.         of them might have changed) and return any error encountered in
  622.         doing so. But we don't. So all we need to do is return success. */
  623.  
  624.     return hrSuccess;
  625. }
  626.  
  627.  
  628. STDMETHODIMP
  629. WMPROP_GetProps(
  630.     LPWMPROP lpWMProp,
  631.     LPSPropTagArray lpPropTagArray,
  632.     ULONG ulFlags,
  633.     ULONG * lpcValues,
  634.     LPSPropValue * lppPropArray)
  635. {
  636.     /* Validate the object */
  637.  
  638.     if (FBadUnknown(lpWMProp) ||
  639.         IsBadWritePtr(lpWMProp, sizeof(WMPROP)) ||
  640.         IsBadReadPtr(lpWMProp->lpVtbl, offsetof(WMPROP_Vtbl, GetProps)) ||
  641.         WMPROP_GetProps != lpWMProp->lpVtbl->GetProps)
  642.     {
  643.         DebugTraceSc(WMPROP_GetProps, E_INVALIDARG);
  644.         return ResultFromScode(E_INVALIDARG);
  645.     }
  646.     
  647.     if ( ulFlags & ~(MAPI_UNICODE) )
  648.     {
  649.         DebugTraceSc(WMPROP_GetProps, MAPI_E_UNKNOWN_FLAGS);
  650.         return ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  651.     }
  652.  
  653.     if ( ulFlags & MAPI_UNICODE )
  654.     {
  655.         DebugTraceSc(WMPROP_GetProps, MAPI_E_BAD_CHARWIDTH);
  656.         return ResultFromScode( MAPI_E_BAD_CHARWIDTH );
  657.     }
  658.     
  659.     return lpWMProp->lpMAPIProp->lpVtbl->GetProps(
  660.         lpWMProp->lpMAPIProp, lpPropTagArray, ulFlags,
  661.         lpcValues, lppPropArray);
  662. }
  663.  
  664.  
  665. STDMETHODIMP
  666. WMPROP_GetPropList(
  667.     LPWMPROP lpWMProp,
  668.     ULONG ulFlags,
  669.     LPSPropTagArray * lppPropTagArray)
  670. {
  671.     /* Validate the object */
  672.  
  673.     if (FBadUnknown(lpWMProp) ||
  674.         IsBadWritePtr(lpWMProp, sizeof(WMPROP)) ||
  675.         IsBadReadPtr(lpWMProp->lpVtbl, offsetof(WMPROP_Vtbl, GetPropList)) ||
  676.         WMPROP_GetPropList != lpWMProp->lpVtbl->GetPropList)
  677.     {
  678.         DebugTraceSc(WMPROP_GetPropList, E_INVALIDARG);
  679.         return ResultFromScode(E_INVALIDARG);
  680.     }
  681.  
  682.     if ( ulFlags & ~(MAPI_UNICODE) )
  683.     {
  684.         DebugTraceSc(WMPROP_GetProps, MAPI_E_UNKNOWN_FLAGS);
  685.         return ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  686.     }
  687.  
  688.     if ( ulFlags & MAPI_UNICODE )
  689.     {
  690.         DebugTraceSc(WMPROP_GetProps, MAPI_E_BAD_CHARWIDTH);
  691.         return ResultFromScode( MAPI_E_BAD_CHARWIDTH );
  692.     }
  693.     
  694.     return lpWMProp->lpMAPIProp->lpVtbl->GetPropList(
  695.         lpWMProp->lpMAPIProp, ulFlags, lppPropTagArray);
  696. }
  697.  
  698.  
  699. STDMETHODIMP
  700. WMPROP_SetProps(
  701.     LPWMPROP lpWMProp,
  702.     ULONG cValues,
  703.     LPSPropValue lpPropArray,
  704.     LPSPropProblemArray * lppProblems)
  705. {
  706.     /* Validate the object */
  707.  
  708.     if (FBadUnknown(lpWMProp) ||
  709.         IsBadWritePtr(lpWMProp, sizeof(WMPROP)) ||
  710.         IsBadReadPtr(lpWMProp->lpVtbl, offsetof(WMPROP_Vtbl, SetProps)) ||
  711.         WMPROP_SetProps != lpWMProp->lpVtbl->SetProps)
  712.     {
  713.         DebugTraceSc(WMPROP_SetProps, E_INVALIDARG);
  714.         return ResultFromScode(E_INVALIDARG);
  715.     }
  716.  
  717.     return lpWMProp->lpMAPIProp->lpVtbl->SetProps(lpWMProp->lpMAPIProp,
  718.         cValues, lpPropArray, lppProblems);
  719. }
  720.  
  721.  
  722. STDMETHODIMP
  723. WMPROP_DeleteProps(
  724.     LPWMPROP lpWMProp,
  725.     LPSPropTagArray lpPropTagArray,
  726.     LPSPropProblemArray * lppProblems)
  727. {
  728.     /* Validate the object */
  729.  
  730.     if (FBadUnknown(lpWMProp) ||
  731.         IsBadWritePtr(lpWMProp, sizeof(WMPROP)) ||
  732.         IsBadReadPtr(lpWMProp->lpVtbl, offsetof(WMPROP_Vtbl, DeleteProps)) ||
  733.         WMPROP_DeleteProps != lpWMProp->lpVtbl->DeleteProps)
  734.     {
  735.         DebugTraceSc(WMPROP_DeleteProps, E_INVALIDARG);
  736.         return ResultFromScode(E_INVALIDARG);
  737.     }
  738.  
  739.     return lpWMProp->lpMAPIProp->lpVtbl->DeleteProps(lpWMProp->lpMAPIProp,
  740.         lpPropTagArray, lppProblems);
  741. }
  742.  
  743.  
  744. STDMETHODIMP
  745. WMPROP_CopyTo(
  746.     LPWMPROP lpWMProp,
  747.     ULONG ciidExclude,
  748.     LPCIID rgiidExclude,
  749.     LPSPropTagArray lpExcludeProps,
  750.     ULONG ulUIParam,
  751.     LPMAPIPROGRESS lpProgress,
  752.     LPCIID lpInterface,
  753.     LPVOID lpDestObj,
  754.     ULONG ulFlags,
  755.     LPSPropProblemArray FAR * lppProblems)
  756. {
  757.     /* Validate the object */
  758.  
  759.     if (FBadUnknown(lpWMProp) ||
  760.         IsBadWritePtr(lpWMProp, sizeof(WMPROP)) ||
  761.         IsBadReadPtr(lpWMProp->lpVtbl, offsetof(WMPROP_Vtbl, CopyTo)) ||
  762.         WMPROP_CopyTo != lpWMProp->lpVtbl->CopyTo)
  763.     {
  764.         DebugTraceSc(WMPROP_CopyTo, E_INVALIDARG);
  765.         return ResultFromScode(E_INVALIDARG);
  766.     }
  767.  
  768.     return lpWMProp->lpMAPIProp->lpVtbl->CopyTo(lpWMProp->lpMAPIProp,
  769.         ciidExclude, rgiidExclude, lpExcludeProps, ulUIParam, 
  770.         lpProgress, lpInterface, lpDestObj, ulFlags, lppProblems);
  771. }
  772.  
  773.  
  774. STDMETHODIMP
  775. WMPROP_CopyProps(
  776.     LPWMPROP lpWMProp,
  777.     LPSPropTagArray lpIncludeProps,
  778.     ULONG ulUIParam,
  779.     LPMAPIPROGRESS lpProgress,
  780.     LPCIID lpInterface,
  781.     LPVOID lpDestObj,
  782.     ULONG ulFlags,
  783.     LPSPropProblemArray FAR * lppProblems)
  784. {
  785.     /* Validate the object */
  786.  
  787.     if (FBadUnknown(lpWMProp) ||
  788.         IsBadWritePtr(lpWMProp, sizeof(WMPROP)) ||
  789.         IsBadReadPtr(lpWMProp->lpVtbl, offsetof(WMPROP_Vtbl, CopyProps)) ||
  790.         WMPROP_CopyProps != lpWMProp->lpVtbl->CopyProps)
  791.     {
  792.         DebugTraceSc(WMPROP_CopyProps, E_INVALIDARG);
  793.         return ResultFromScode(E_INVALIDARG);
  794.     }
  795.  
  796.     return lpWMProp->lpMAPIProp->lpVtbl->CopyProps(lpWMProp->lpMAPIProp,
  797.         lpIncludeProps, ulUIParam, lpProgress, lpInterface, lpDestObj,
  798.         ulFlags, lppProblems);
  799. }
  800.  
  801.  
  802. STDMETHODIMP
  803. WMPROP_GetNamesFromIDs(
  804.     LPWMPROP lpWMProp,
  805.     LPSPropTagArray * lppPropTags,
  806.     LPGUID lpPropSetGuid,
  807.     ULONG ulFlags,
  808.     ULONG * lpcPropNames,
  809.     LPMAPINAMEID * *lpppPropNames)
  810. {
  811.     /* Validate the object */
  812.  
  813.     if (FBadUnknown(lpWMProp) ||
  814.         IsBadWritePtr(lpWMProp, sizeof(WMPROP)) ||
  815.         IsBadReadPtr(lpWMProp->lpVtbl, offsetof(WMPROP_Vtbl, GetNamesFromIDs)) ||
  816.         WMPROP_GetNamesFromIDs != lpWMProp->lpVtbl->GetNamesFromIDs)
  817.     {
  818.         DebugTraceSc(WMPROP_GetNamesFromIDs, E_INVALIDARG);
  819.         return ResultFromScode(E_INVALIDARG);
  820.     }
  821.  
  822.     return lpWMProp->lpMAPIProp->lpVtbl->GetNamesFromIDs(lpWMProp->lpMAPIProp,
  823.         lppPropTags, lpPropSetGuid, ulFlags, lpcPropNames, lpppPropNames);
  824. }
  825.  
  826.  
  827. STDMETHODIMP
  828. WMPROP_GetIDsFromNames(
  829.     LPWMPROP lpWMProp,
  830.     ULONG cPropNames,
  831.     LPMAPINAMEID * lppPropNames,
  832.     ULONG ulFlags,
  833.     LPSPropTagArray * lppPropTags)
  834. {
  835.     /* Validate the object */
  836.  
  837.     if (FBadUnknown(lpWMProp) ||
  838.         IsBadWritePtr(lpWMProp, sizeof(WMPROP)) ||
  839.         IsBadReadPtr(lpWMProp->lpVtbl, offsetof(WMPROP_Vtbl, GetIDsFromNames)) ||
  840.         WMPROP_GetIDsFromNames != lpWMProp->lpVtbl->GetIDsFromNames)
  841.     {
  842.         DebugTraceSc(WMPROP_GetIDsFromNames, E_INVALIDARG);
  843.         return ResultFromScode(E_INVALIDARG);
  844.     }
  845.  
  846.     return lpWMProp->lpMAPIProp->lpVtbl->GetIDsFromNames(lpWMProp->lpMAPIProp,
  847.         cPropNames, lppPropNames, ulFlags, lppPropTags);
  848. }
  849.