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

Windows编程

开发平台:

Visual C++

  1. /*
  2.  *  S M H C F G . C
  3.  *
  4.  *  Sample mail handling hook configuration
  5.  *  Copyright 1992-95 Microsoft Corporation.  All Rights Reserved.
  6.  */
  7. #include "_pch.h"
  8. /*
  9.  *  Configuration Properties
  10.  *  
  11.  *  sptConfigProps
  12.  *  
  13.  *      This is the set of properties that we expect to find in the
  14.  *      provider's profile section.
  15.  *  
  16.  *  sptRule
  17.  *  
  18.  *      This is the set of properties that are expected to be found in
  19.  *      each rule's profile section.
  20.  */
  21. const SizedSPropTagArray (cpMax, sptConfigProps) =
  22. {
  23.     cpMax,
  24.     {
  25.         PR_PROFILE_NAME,
  26.         PR_SMH_FLAGS,
  27.         PR_SMH_RULES,
  28.         PR_SMH_RULE_NAMES,
  29.         PR_SMH_OOF_TEXT,
  30.         PR_SMH_OOF_ENABLED,
  31.         PR_SMH_OOF_RTF,
  32.         PR_SMH_SOUND_SCHEMES,
  33.         PR_SMH_REPFWD_SCHEMES,
  34.         PR_SMH_EXCLUSIONS
  35.     }
  36. };
  37. const SizedSPropTagArray (cpRLMax, sptRule) =
  38. {
  39.     cpRLMax,
  40.     {
  41.         PR_DISPLAY_NAME,
  42.         PR_RULE_TYPE,
  43.         PR_RULE_DATA,
  44.         PR_RULE_FLAGS,
  45.         PR_RULE_TARGET_ENTRYID,
  46.         PR_RULE_TARGET_PATH,
  47.         PR_RULE_STORE_ENTRYID,
  48.         PR_RULE_STORE_DISPLAY_NAME,
  49.         PR_RULE_SOUND_LOPRI,
  50.         PR_RULE_SOUND_NORMAL,
  51.         PR_RULE_SOUND_HIPRI,
  52.         PR_RULE_FORWARD_RECIP,
  53.         PR_RULE_FORWARD_RECIP_ENTRYID,
  54.         PR_RULE_REP_FWD_RTF,
  55.         PR_RULE_REP_FWD_TEXT
  56.     }
  57. };
  58. /*
  59.  *  Configuration event name
  60.  */
  61. const TCHAR lpszConfigEvt[] = "SMH_CONFIGURATION_EVENT";
  62. /*
  63.  *  HrOpenSingleProvider()
  64.  *  
  65.  *  Purpose:
  66.  *  
  67.  *      Opens the profile section of this service provider.  This is done
  68.  *      by opening the message service table and querying all rows.
  69.  *      Since the SMH service contains only one provider, there is only
  70.  *      one row in the table.  This contains our profile section.  Use
  71.  *      the PR_PROFILE_UID to open the section.
  72.  *  
  73.  *  Arguments:
  74.  *  
  75.  *      lpadmin         the IProfileAdmin object
  76.  *      lppprof [OUT]   on return contains the profile section obj
  77.  *  
  78.  *  Returns:
  79.  *  
  80.  *      (HRESULT)
  81.  *      lppprof [OUT]   contains the profile section object iff the call
  82.  *                      is successful.
  83.  */
  84. HRESULT
  85. HrOpenSingleProvider (LPPROVIDERADMIN lpadmin, LPPROFSECT FAR * lppprof)
  86. {
  87.     HRESULT hr;
  88.     LPMAPITABLE lptbl = NULL;
  89.     LPSRowSet lprws = NULL;
  90.     SPropTagArray sptProvider = {1, {PR_PROVIDER_UID}};
  91.     SRestriction res = {0};
  92.     res.rt = RES_EXIST;
  93.     res.res.resExist.ulPropTag = PR_PROVIDER_DLL_NAME;
  94.     hr = lpadmin->lpVtbl->GetProviderTable (lpadmin, 0, &lptbl);
  95.     if (!HR_FAILED (hr))
  96.     {
  97.         hr = lptbl->lpVtbl->SetColumns (lptbl, &sptProvider, 0L);
  98.         if (!HR_FAILED (hr))
  99.         {
  100.             hr = lptbl->lpVtbl->Restrict (lptbl, &res, 0);
  101.             if (!HR_FAILED (hr))
  102.             {
  103.                 hr = lptbl->lpVtbl->QueryRows (lptbl, 10, 0, &lprws);
  104.                 if (!HR_FAILED (hr) && lprws->cRows)
  105.                 {
  106.                     Assert (lprws->cRows == 1);
  107.                     Assert (lprws->aRow[0].cValues == 1);
  108.                     Assert (lprws->aRow[0].lpProps);
  109.                     Assert (lprws->aRow[0].lpProps[0].ulPropTag == PR_PROVIDER_UID);
  110.                     hr = lpadmin->lpVtbl->OpenProfileSection (lpadmin,
  111.                         (LPMAPIUID)lprws->aRow[0].lpProps[0].Value.bin.lpb,
  112.                         NULL,
  113.                         MAPI_MODIFY,
  114.                         lppprof);
  115.                     MAPIFreeBuffer (lprws->aRow[0].lpProps);
  116.                 }
  117.                 MAPIFreeBuffer (lprws);
  118.             }
  119.         }
  120.         UlRelease (lptbl);
  121.     }
  122.     DebugTraceResult (HrOpenSingleProvider, hr);
  123.     return hr;
  124. }
  125. /*
  126.  *  HrMergeValues()
  127.  *  
  128.  *  Purpose:
  129.  *  
  130.  *      Merges two property value arrays into one.  By making a copy of
  131.  *      the first and then adding/replacing props from the second.
  132.  *  
  133.  *      IMPORTANT: if there are any property values that are separately
  134.  *      allocated with either MAPIAllocateBuffer() or MAPIAllocateMore(),
  135.  *      then these property values must remain valid as long as the
  136.  *      merged property array is expected to be valid.
  137.  *  
  138.  *  Returns:
  139.  *  
  140.  *      (HRESULT)
  141.  */
  142. HRESULT
  143. HrMergeValues (ULONG cval1,
  144.     LPSPropValue lpval1,
  145.     ULONG cval2,
  146.     LPSPropValue lpval2,
  147.     LPALLOCATEBUFFER lpfnAlloc,
  148.     ULONG FAR * lpcvalMerged,
  149.     LPSPropValue FAR * lppvalMerged)
  150. {
  151.     SCODE sc;
  152.     LPSPropValue lpval = NULL;
  153.     UINT cb;
  154.     UINT ip;
  155.     cb = (UINT)(cval1 + cval2) * sizeof(SPropValue);
  156.     sc = (*lpfnAlloc)(cb, &lpval);
  157.     if (!FAILED (sc))
  158.     {
  159.         /*  Slurp the original data across */
  160.         memcpy (lpval, lpval1, (UINT)cval1 * sizeof(SPropValue));
  161.         /*  Move the new stuff over */
  162.         while (cval2--)
  163.         {
  164.             for (ip = 0; ip < (UINT)cval1; ip++)
  165.             {
  166.                 /*  See if we match properties */
  167.                 if (PROP_ID (lpval[ip].ulPropTag) == PROP_ID (lpval2[cval2].ulPropTag))
  168.                 {
  169.                     /*  We matched, but are we a real property */
  170.                     if (PROP_TYPE (lpval2[cval2].ulPropTag) != PT_ERROR)
  171.                         lpval[ip] = lpval2[cval2];
  172.                     break;
  173.                 }
  174.             }
  175.             if (ip == cval1)
  176.                 lpval[cval1++] = lpval2[cval2];
  177.         }
  178.         *lpcvalMerged = cval1;
  179.         *lppvalMerged = lpval;
  180.     }
  181.     DebugTraceSc (HrMergeValues(), sc);
  182.     return ResultFromScode (sc);
  183. }
  184. /*
  185.  *  HrUpdateProfileFormat()
  186.  *  
  187.  *  Purpose:
  188.  *  
  189.  *      Converts the WMS level of SMH profile properties to post WMS
  190.  *      levels.  Namely rules are now stored via a pair of properties
  191.  *      in the profile.  PR_SMH_RULES has been changed to a multi-valued
  192.  *      binary property and PR_SMH_RULE_NAMES contains the display names
  193.  *      for the rules.  The prevents the configuration functions from
  194.  *      opening all profile sections to build the list of rules.
  195.  *  
  196.  *  Arguments:
  197.  *  
  198.  *      lpvOPSCtxt          Context passed to OpenProfileSection()
  199.  *                          (a session or an profadmin object)
  200.  *      lpfnOpenProfSect    Pointer to OpenProfileSection()
  201.  *      lpfnMore            MAPIAllocateMore() function
  202.  *      lpfnFree            MAPIFreeBuffer() function
  203.  *      lpvalNew            propvalue array for the converted values
  204.  *      lpvalOld            propvalue of the old PR_SMH_RULES
  205.  *  
  206.  *  Returns:
  207.  *  
  208.  *      (HRESULT)
  209.  */
  210. HRESULT
  211. HrUpdateProfileFormat (LPVOID lpvOPSCtxt,
  212.     LPOPENPROFSECT lpfnOpenProfSect,
  213.     LPALLOCATEMORE lpfnMore,
  214.     LPFREEBUFFER lpfnFree,
  215.     LPSPropValue lpvalNew,
  216.     LPSPropValue lpvalOld)
  217. {
  218.     SCODE sc = S_OK;
  219.     LPMAPIUID lpmuid;
  220.     LPPROFSECT lpsec = NULL;
  221.     LPSBinary lpbin;
  222.     LPSPropValue lpval = NULL;
  223.     LPTSTR FAR * lppsz;
  224.     SizedSPropTagArray (2, spt) = {2, {PR_DISPLAY_NAME, PR_RULE_TYPE}};
  225.     UINT cb;
  226.     UINT crl;
  227.     UINT i;
  228.     ULONG cval;
  229.     
  230.     DebugTrace ("SMH: updating profile to new formatn");
  231.     /*  Make sure that the size is an even number of UIDs */
  232.     Assert ((lpvalOld->Value.bin.cb % sizeof(MAPIUID)) == 0);
  233.     crl = (UINT)lpvalOld->Value.bin.cb / sizeof(MAPIUID);
  234.     /*  Allocate space for the two new properties */
  235.     cb = crl * sizeof(SBinary);
  236.     sc = (*lpfnMore) (cb, lpvalNew, &lpbin);
  237.     if (FAILED (sc))
  238.         goto ret;
  239.     memset (lpbin, 0, cb);
  240.     
  241.     cb = crl * sizeof(LPTSTR);
  242.     sc = (*lpfnMore) (cb, lpvalNew, (LPVOID FAR *)&lppsz);
  243.     if (FAILED (sc))
  244.         goto ret;
  245.     memset (lppsz, 0, cb);
  246.     
  247.     /*  Iterate through the old list building the two new lists as we go */
  248.     
  249.     lpmuid = (LPMAPIUID)lpvalOld->Value.bin.lpb;
  250.     for (i = 0; crl--; lpmuid++)
  251.     {
  252.         /*  Open the old profile section and get PR_DISPLAY_NAME
  253.          *  and PR_RULE_TYPE for conversion purposes.  The type
  254.          *  will be converted and reset into the profile section.
  255.          *  Thus, completing the conversion for that section.
  256.          *
  257.          *  The display name will be extracted and copied out to
  258.          *  the external names property and will be saved out when
  259.          *  all section conversions are completed
  260.          */
  261.         if (!HR_FAILED ((*lpfnOpenProfSect) (lpvOPSCtxt, lpmuid, NULL, MAPI_MODIFY, &lpsec)) &&
  262.             !HR_FAILED (lpsec->lpVtbl->GetProps (lpsec, (LPSPropTagArray)&spt, 0, &cval, &lpval)) &&
  263.             !FAILED ((*lpfnMore) (sizeof(MAPIUID), lpvalNew, &lpbin[i].lpb)) &&
  264.             !FAILED ((*lpfnMore) (lstrlen (lpval[0].Value.LPSZ) + 1, lpvalNew, &lppsz[i])))
  265.         {
  266.             switch (lpval[1].Value.l)
  267.             {
  268.               case 1:
  269.                 lpval[1].Value.l = RL_SUBJECT;
  270.                 break;
  271.               case 2:
  272.                 lpval[1].Value.l = RL_SENDER;
  273.                 break;
  274.               case 4:
  275.                 lpval[1].Value.l = RL_HAS_ATTACH;
  276.                 break;
  277.               case 8:
  278.                 lpval[1].Value.l = RL_BODY;
  279.                 break;
  280.               case 16:
  281.                 lpval[1].Value.l = RL_TO_RECIP;
  282.                 break;
  283.               case 32:
  284.                 lpval[1].Value.l = RL_CC_RECIP;
  285.                 break;
  286.               case 64:
  287.                 lpval[1].Value.l = RL_BCC_RECIP;
  288.                 break;
  289.               case 128:
  290.                 lpval[1].Value.l = RL_ANY_RECIP;
  291.                 break;
  292.               case 256:
  293.                 lpval[1].Value.l = RL_MSG_CLASS;
  294.                 break;
  295.             }
  296.             if (!HR_FAILED (HrSetOneProp ((LPMAPIPROP)lpsec, &lpval[1])))
  297.             {
  298.                 DebugTrace ("SMH: converting '%s' rulen", lpval[0].Value.LPSZ);
  299.                 lpbin[i].cb = sizeof(MAPIUID);
  300.                 memcpy (lpbin[i].lpb, lpmuid, sizeof(MAPIUID));
  301.                 lstrcpy (lppsz[i], lpval[0].Value.LPSZ);
  302.                 i++;
  303.             }
  304.         }
  305.         (*lpfnFree) (lpval);
  306.         UlRelease (lpsec);
  307.         lpval = NULL;
  308.         lpsec = NULL;
  309.     }
  310.     lpvalNew[ipRules].ulPropTag = PR_SMH_RULES;
  311.     lpvalNew[ipRules].Value.MVbin.cValues = i;
  312.     lpvalNew[ipRules].Value.MVbin.lpbin = lpbin;
  313.     lpvalNew[ipNames].ulPropTag = PR_SMH_RULE_NAMES;
  314.     lpvalNew[ipNames].Value.MVSZ.cValues = i;
  315.     lpvalNew[ipNames].Value.MVSZ.LPPSZ = lppsz;
  316. ret:
  317.     DebugTraceSc (HrUpdateProfileFormat(), sc);
  318.     return ResultFromScode (sc ? sc : ((i == crl) ? 0 : MAPI_W_ERRORS_RETURNED));
  319. }
  320.         
  321. /*
  322.  *  HrGetConfigEvent()
  323.  *  
  324.  *  Purpose:
  325.  *  
  326.  *      Gets the configuration event handle.  The handle is used to
  327.  *      signal logged in handlers that their configuration has been
  328.  *      modified and, at the next reasonable chance, should be reloaded.
  329.  *  
  330.  *      Called at SMH init time only.
  331.  *  
  332.  *  Arguments:
  333.  *  
  334.  *      lphevt  [OUT]   contains the handle iff the call succeeds
  335.  *  
  336.  *  Returns:
  337.  *  
  338.  *      (HRESULT)
  339.  */
  340. #ifdef  _WIN32
  341. HRESULT
  342. HrGetConfigEvent (HANDLE FAR * lphevt)
  343. {
  344.     HANDLE hevt = NULL;
  345.         
  346.     if (!(hevt = CreateEvent (NULL, TRUE, FALSE, lpszConfigEvt)) &&
  347.         !(hevt = OpenEvent (EVENT_MODIFY_STATE, FALSE, lpszConfigEvt)))
  348.         ResultFromScode (MAPI_E_NOT_ENOUGH_RESOURCES);
  349.     *lphevt = hevt;
  350.     return hrSuccess;
  351. }
  352. #endif  /* _WIN32 */
  353. /*
  354.  *  SignalConfigChanged()
  355.  *  
  356.  *  Purpose:
  357.  *  
  358.  *      Sets the configuration event such that logged in hooks can update
  359.  *      their configuration on the fly.
  360.  *  
  361.  *      Called from within the service entry when configuration changes
  362.  *      are commited.
  363.  */
  364. #ifdef  _WIN32
  365. VOID
  366. SignalConfigChanged (VOID)
  367. {
  368.     HANDLE hevt = NULL;
  369.     
  370.     if (hevt = OpenEvent (EVENT_MODIFY_STATE, FALSE, lpszConfigEvt))
  371.     {
  372.         SetEvent (hevt);
  373.         CloseHandle (hevt);
  374.     }
  375.     return;
  376. }
  377. #endif  /* _WIN32 */
  378. /*
  379.  *  FConfigChanged()
  380.  *  
  381.  *  Purpose:
  382.  *  
  383.  *      Tests the configuration event such that logged in hooks can update
  384.  *      their configuration on the fly if the configuration has changed.
  385.  *  
  386.  *      Called from within the SMH object at regualr intervals
  387.  *  
  388.  *  Returns:
  389.  *  
  390.  *      TRUE iff the config changed
  391.  *  
  392.  */
  393. #ifdef  _WIN32
  394. BOOL
  395. FConfigChanged (HANDLE hevt)
  396. {
  397.     ULONG dw;
  398.     dw = WaitForSingleObject (hevt, 0);
  399.     Assert (dw != WAIT_ABANDONED);
  400.     return (dw == WAIT_OBJECT_0);
  401. }
  402. #endif  /* _WIN32 */
  403. /*
  404.  *  SMH_ServiceEntry()
  405.  *  
  406.  *  Purpose:
  407.  *  
  408.  *      The ServiceEntry() function is the MAPI entry point to configure
  409.  *      a service for use in a profile.  The call can then bring up UI to
  410.  *      ensure configuration of the SMH provider.
  411.  *  
  412.  *  Parameters:
  413.  *  
  414.  *      hinst           DLL instance
  415.  *      lpmalloc        OLE style allocator (used by PropSheet())
  416.  *      lpsup           MAPI profile support object
  417.  *      ulUIParam       hwnd that is to be used as UI parent
  418.  *      ulFlags         configuration flags
  419.  *      ulContext       configuration action
  420.  *      cval            count of caller supplied properties
  421.  *      lpval           caller supplied properties to be configured
  422.  *      lpadmin         IProviderAdmin object
  423.  *      lppmerr [OUT]   extended error information
  424.  *  
  425.  *  Operation:
  426.  *  
  427.  *      The ServiceEntry() uses the IProviderAdmin object to open its
  428.  *      profile section and retrieve the current set of properties.  The
  429.  *      caller supplied properties are then merged into the set of
  430.  *      current properties.
  431.  *  
  432.  *      If either this set of properties is not sufficient for
  433.  *      configuration or the caller specifically asked for configuration
  434.  *      UI, then ServiceEntry() will make calls to bring up its config
  435.  *      UI.
  436.  *  
  437.  *      ServiceEntry() recognizes several configuration flags.  If
  438.  *      SERVICE_UI_ALWAYS and/or SERVICE_UI_ALLOWED are set, UI is
  439.  *      allowed and we be brought up if appropriate.  Is
  440.  *      MSG_SERVICE_UI_READ_ONLY is set, then the UI should not 
  441.  *      allow the configuration to be modified.
  442.  *  
  443.  *      The configuration contexts MSG_SERVICE_DELETE, MSG_SERVICE_INSTALL, 
  444.  *      and MSG_SERVICE_UNINSTALL are ignored and no action is taken.
  445.  *      MSG_SERVICE_CONFIGURE and MSG_SERVICE_CREATE allow the caller to
  446.  *      create or update the configuration properties in this providers
  447.  *      profile section. 
  448.  *  
  449.  *      SMH will not return extended information in the MAPIERROR in case
  450.  *      of error
  451.  */
  452. HRESULT STDAPICALLTYPE
  453. SMH_ServiceEntry(
  454.     HINSTANCE hinst,
  455.     LPMALLOC lpmalloc,
  456.     LPMAPISUP lpsup,
  457.     ULONG ulUIParam,
  458.     ULONG ulFlags,
  459.     ULONG ulContext,
  460.     ULONG cval,
  461.     LPSPropValue lpval,
  462.     LPPROVIDERADMIN lpadmin,
  463.     LPMAPIERROR FAR * lppmerr)
  464. {
  465.     HRESULT hr = hrSuccess;
  466.     BOOL fUI = FALSE;
  467.     LPALLOCATEBUFFER lpfnAlloc = NULL;
  468.     LPALLOCATEMORE lpfnAllocMore = NULL;
  469.     LPFREEBUFFER lpfnFree = NULL;
  470.     LPMAPIUID lpmuid = NULL;
  471.     LPPROFSECT lpprof = NULL;
  472.     LPPROFSECT lpprofSvc = NULL;
  473.     LPSCD lpscd = NULL;
  474.     LPSPropValue lpvalCur = NULL;
  475.     LPSPropValue lpvalNew = NULL;
  476.     LPSPropValue lpvalOld;
  477.     SPropValue val;
  478.     UINT csec = 0;
  479.     UINT i;
  480.     ULONG cvalCur;
  481.     ULONG cvalNew;
  482.     ULONG ulMyFlags;
  483.     if ((ulContext == MSG_SERVICE_INSTALL) ||
  484.         (ulContext == MSG_SERVICE_UNINSTALL))
  485.         goto ret;
  486.     if ((ulContext != MSG_SERVICE_CONFIGURE) &&
  487.         (ulContext != MSG_SERVICE_CREATE) &&
  488.         (ulContext != MSG_SERVICE_DELETE))
  489.     {
  490.         hr = ResultFromScode (MAPI_E_NO_SUPPORT);
  491.         goto ret;
  492.     }
  493.     if (ulFlags & MAPI_UNICODE)
  494.     {
  495.         /*  Unicode is not supported by SMH */
  496.         hr = ResultFromScode (MAPI_E_BAD_CHARWIDTH);
  497.         goto ret;
  498.     }
  499.     /*  Find out our UI options */
  500.     fUI = !!(ulFlags & SERVICE_UI_ALWAYS);
  501.     ulMyFlags = (ulFlags & MSG_SERVICE_UI_READ_ONLY)
  502.         ? UI_READONLY
  503.         : 0;
  504.     /*  Get memory routines */
  505.     hr = lpsup->lpVtbl->GetMemAllocRoutines (lpsup,
  506.                             &lpfnAlloc,
  507.                             &lpfnAllocMore,
  508.                             &lpfnFree);
  509.     if (HR_FAILED (hr))
  510.         goto ret;
  511.     /*  Open the profile section */
  512.     hr = HrOpenSingleProvider (lpadmin, &lpprof);
  513.     if (HR_FAILED (hr))
  514.         goto ret;
  515.     /*  Get the values already in the profile */
  516.     hr = lpprof->lpVtbl->GetProps (lpprof,
  517.                             (LPSPropTagArray)&sptConfigProps,
  518.                             0,
  519.                             &cvalCur,
  520.                             &lpvalCur);
  521.     if (HR_FAILED (hr))
  522.         goto ret;
  523.     /*  Check that the rules are stored in the correct format */
  524.     
  525.     if (lpvalCur[ipRules].ulPropTag != PR_SMH_RULES)
  526.     {
  527.         hr = HrGetOneProp ((LPMAPIPROP)lpprof,
  528.                     CHANGE_PROP_TYPE(PR_SMH_RULES, PT_BINARY),
  529.                     &lpvalOld);
  530.         if (!HR_FAILED (hr))
  531.         {
  532.             /*  The rules are stored in the wrong format */
  533.             hr = HrUpdateProfileFormat (lpadmin,
  534.                             lpadmin->lpVtbl->OpenProfileSection,
  535.                             lpfnAllocMore,
  536.                             lpfnFree,
  537.                             lpvalCur,
  538.                             lpvalOld);
  539.             (*lpfnFree) (lpvalOld);
  540.             if (HR_FAILED (hr))
  541.                 goto ret;
  542.             /*  Save out anything we got back */
  543.             lpprof->lpVtbl->SetProps (lpprof, cpMax, lpvalCur, NULL);
  544.         }
  545.     }
  546.     if (ulContext != MSG_SERVICE_DELETE)
  547.     {
  548.         /*  Merge what was in the profile with what was passed in */
  549.         hr = HrMergeValues (cvalCur,
  550.                             lpvalCur,
  551.                             cval,
  552.                             lpval,
  553.                             lpfnAlloc,
  554.                             &cvalNew,
  555.                             &lpvalNew);
  556.         if (HR_FAILED (hr))
  557.             goto ret;
  558.         /*  If we dont have all the props we need, then
  559.          *  we will have to ask for them
  560.          */
  561.         fUI = fUI || (lpvalNew[ipFlags].ulPropTag != PR_SMH_FLAGS);
  562.         if ((lpvalNew[ipFlags].ulPropTag != PR_SMH_FLAGS) &&
  563.             (!(ulFlags & (SERVICE_UI_ALLOWED | SERVICE_UI_ALWAYS)) ||
  564.             (ulFlags & MSG_SERVICE_UI_READ_ONLY)))
  565.         {
  566.             /*  We need UI but can't have it. */
  567.             hr = ResultFromScode (MAPI_E_UNCONFIGURED);
  568.             goto ret;
  569.         }
  570.         if (fUI)
  571.         {
  572.             /*  Do the config dialog */
  573.             if (!FAILED ((*lpfnAlloc) (sizeof(SCD), &lpscd)))
  574.             {
  575.                 memset (lpscd, 0, sizeof(SCD));
  576.                 lpscd->hinst = hinst;
  577.                 lpscd->hwnd = (HWND)ulUIParam;
  578.                 lpscd->lpfnAlloc = lpfnAlloc;
  579.                 lpscd->lpfnAllocMore = lpfnAllocMore;
  580.                 lpscd->lpfnFree = lpfnFree;
  581.                 lpscd->lpmalloc = lpmalloc;
  582.                 lpscd->lpval = lpvalNew;
  583.                 lpscd->lpsec = lpprof;
  584.                 lpscd->lpsup = lpsup;
  585.                 lpscd->lpadmin = lpadmin;
  586.                 lpscd->ulFlags = ulMyFlags;
  587.                 hr = HrDisplayPropSheets (hinst, (HWND)ulUIParam, lpscd);
  588.             }
  589.             else
  590.             {
  591.                 hr = ResultFromScode (MAPI_E_NOT_ENOUGH_MEMORY);
  592.                 goto ret;
  593.             }
  594.         }
  595.         /*  Open the service profile section and set PR_SERVICE_EXTRA_UIDS */
  596.         if (!HR_FAILED (lpadmin->lpVtbl->OpenProfileSection (lpadmin,
  597.                                             NULL,
  598.                                             NULL,
  599.                                             MAPI_MODIFY,
  600.                                             &lpprofSvc)))
  601.         {
  602.             /*  PR_SERVICE_EXTRA_UIDS is composed of all additional
  603.              *  sections used by SMH.  By setting this value, we gain
  604.              *  the ability to have the service copied andor moved
  605.              *  while having the additional sections move across with
  606.              *  it.
  607.              */
  608.             if (lpvalNew[ipRules].ulPropTag == PR_SMH_RULES)
  609.                 csec += (UINT)lpvalNew[ipRules].Value.MVbin.cValues;
  610.             
  611.             if (csec && !FAILED ((*lpfnAlloc) (csec * sizeof(MAPIUID), &lpmuid)))
  612.             {
  613.                 for (i = 0; i < csec; i++)
  614.                     memcpy (&lpmuid[i],
  615.                         lpvalNew[ipRules].Value.MVbin.lpbin[i].lpb,
  616.                         sizeof(MAPIUID));
  617.                 val.ulPropTag = PR_SERVICE_EXTRA_UIDS;
  618.                 val.Value.bin.cb = csec * sizeof(MAPIUID);
  619.                 val.Value.bin.lpb = (LPBYTE)lpmuid;
  620.                 lpprofSvc->lpVtbl->SetProps (lpprofSvc, 1, &val, NULL);
  621.                 lpprofSvc->lpVtbl->SaveChanges (lpprofSvc, 0);
  622.                 (*lpfnFree) (lpmuid);
  623.             }
  624.             UlRelease (lpprofSvc);
  625.         }
  626.     }
  627.     
  628. ret:
  629. #ifdef  _WIN32
  630.     if (!HR_FAILED (hr))
  631.         SignalConfigChanged ();
  632. #endif
  633.     /*  Cleanup what was left behind */
  634.     if (lpscd)
  635.     {   
  636.         for (i = 0; i < lpscd->crl; i++)
  637.         {
  638.             (*lpfnFree) (lpscd->lppsz[i]);
  639.             (*lpfnFree) (lpscd->lpbin[i].lpb);
  640.         }
  641.         (*lpfnFree) (lpscd->lppsz);
  642.         (*lpfnFree) (lpscd->lpbin);
  643.         (*lpfnFree) (lpscd);
  644.     }
  645.                 
  646.     if (lpfnFree)
  647.     {
  648.         (*lpfnFree) (lpvalCur);
  649.         (*lpfnFree) (lpvalNew);
  650.     }
  651.     UlRelease (lpprof);
  652.     DebugTraceResult (SMH_ServiceEntry, hr);
  653.     return hr;
  654. };