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 / manager.sh / smhinpxp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  21.2 KB  |  727 lines

  1. /*
  2.  *  S M H I N P X P . C
  3.  *
  4.  *  Sample mail handling hook filter importing and exporting.
  5.  *  Copyright 1992-95 Microsoft Corporation.  All Rights Reserved.
  6.  */
  7.  
  8. #include "_pch.h"
  9. #include <commdlg.h>
  10.  
  11. extern SPropTagArray sptRule;
  12.  
  13. #define Align(_cb,_pad)         (((_cb)+((_pad)-1)) & ~((_pad)-1))
  14. #define Align8(_cb)             Align((_cb),8)
  15.  
  16. #ifdef WIN16
  17. #define SEG(_fp)                HIWORD((DWORD)_fp)
  18. #define OFF(_fp)                LOWORD((DWORD)_fp)
  19. #define PvRelocPv(_p,_bo,_bn)   ((LPVOID)MAKELONG(OFF(_p)-OFF(_bo)+OFF(_bn),SEG(_bn)))
  20. #else
  21. #define PvRelocPv(_p,_bo,_bn)   ((LPVOID)((LPBYTE)(_p)-(LPBYTE)(_bo)+(LPBYTE)(_bn)))
  22. #endif
  23.  
  24. static const BYTE rgbExportKey[] = { 0x4F, 0x6C, 0x61, 0x66, 0xDE, 0xAD };
  25.  
  26. /*
  27.  *  Property Flattening -------------------------------------------------------
  28.  */
  29.  
  30. /*
  31.  *  ScSizeFlattenedProps()
  32.  *  ScFlattenProps()
  33.  *  ScNormalizeFlattenedProps()
  34.  *  
  35.  *  These three functions are similar to the MAPI utility functions
  36.  *  ScCountProps(), ScCopyProps() and ScRelocProps().  SMH uses these
  37.  *  implementations because they are platform independant.  Additionally,
  38.  *  the SMH rule property sets are very simple and do not require support
  39.  *  for complex property types.
  40.  *  
  41.  *  To be platform independent, SMH pads all variable length properties
  42.  *  out to 8 byte aligment.  This ensures that all RISC platforms (MIPS,
  43.  *  ALPHA and PowerPC) will not suffer aligment problems when using the
  44.  *  normalized flattened property values.
  45.  *  
  46.  *  ScSizeFlattenedProps() calculates the size of a buffer required to
  47.  *  flatten the properties in the SPropValue array.
  48.  *  
  49.  *  ScFlattenProps() copies the properties from the source array to the
  50.  *  destination buffer.
  51.  *  
  52.  *  ScNormalizeFlattenedProps() goes through a flattened a property array
  53.  *  and bases all the pointers to a specific value.
  54.  */
  55. SCODE
  56. ScSizeFlattenedProps (UINT cv, LPSPropValue rgval, ULONG FAR * lpcb)
  57. {
  58.     SCODE sc = S_OK;
  59.     ULONG cb = 0;
  60.  
  61.     for (; cv--; rgval++)
  62.     {
  63.         cb += sizeof(SPropValue);
  64.         switch (PROP_TYPE (rgval->ulPropTag))
  65.         {
  66.           default:
  67.           case PT_UNSPECIFIED:
  68.           case PT_I2:
  69.           case PT_R4:
  70.           case PT_APPTIME:
  71.           case PT_DOUBLE:
  72.           case PT_BOOLEAN:
  73.           case PT_CURRENCY:
  74.           case PT_SYSTIME:
  75.           case PT_I8:
  76.           case PT_OBJECT:
  77.           case PT_CLSID:
  78.           case PT_MV_I2:
  79.           case PT_MV_LONG:
  80.           case PT_MV_R4:
  81.           case PT_MV_APPTIME:
  82.           case PT_MV_DOUBLE:
  83.           case PT_MV_CURRENCY:
  84.           case PT_MV_SYSTIME:
  85.           case PT_MV_CLSID:
  86.           case PT_MV_I8:
  87.           case PT_MV_BINARY:
  88.           case PT_MV_STRING8:
  89.           case PT_MV_UNICODE:
  90.  
  91.             sc = MAPI_E_UNEXPECTED_TYPE;
  92.             break;
  93.             
  94.           case PT_LONG:
  95.           case PT_ERROR:
  96.           case PT_NULL:
  97.  
  98.             /*  There is no additional data to include in
  99.              *  the size of the flattened props.
  100.              */
  101.             continue;
  102.  
  103.           case PT_BINARY:
  104.                 
  105.             cb += Align8 (rgval->Value.bin.cb);
  106.             break;
  107.  
  108.           case PT_STRING8:
  109.                 
  110.             cb += Align8 ((lstrlenA (rgval->Value.lpszA ) + 1) * sizeof(CHAR));
  111.             break;
  112.  
  113.           case PT_UNICODE:
  114.                 
  115.             cb += Align8 ((lstrlenW (rgval->Value.lpszW ) + 1) * sizeof(WCHAR));
  116.             break;
  117.  
  118.         }
  119.         
  120.         if (FAILED (sc))
  121.             break;
  122.     }
  123.  
  124.     *lpcb = cb;
  125.     DebugTraceSc (ScSizeFlattenedProps(), sc);
  126.     return sc;
  127. }
  128.  
  129.  
  130. SCODE
  131. ScFlattenProps (UINT cv, LPSPropValue rgval, LPBYTE lpb)
  132. {
  133.     SCODE sc = S_OK;
  134.     LPSPropValue rgvalDst = (LPSPropValue)lpb;
  135.     ULONG cb;
  136.  
  137.     /*  Copy over the base properties and setup
  138.      *  a pointer to the block of memory following
  139.      *  the property value array
  140.      */
  141.     memcpy (rgvalDst, rgval, cv * sizeof(SPropValue));
  142.     lpb += cv * sizeof(SPropValue);
  143.  
  144.     for (; cv--; rgval++, rgvalDst++)
  145.     {
  146.         switch (PROP_TYPE (rgval->ulPropTag))
  147.         {
  148.           default:
  149.           case PT_UNSPECIFIED:
  150.           case PT_I2:
  151.           case PT_R4:
  152.           case PT_APPTIME:
  153.           case PT_DOUBLE:
  154.           case PT_BOOLEAN:
  155.           case PT_CURRENCY:
  156.           case PT_SYSTIME:
  157.           case PT_I8:
  158.           case PT_OBJECT:
  159.           case PT_CLSID:
  160.           case PT_MV_I2:
  161.           case PT_MV_LONG:
  162.           case PT_MV_R4:
  163.           case PT_MV_APPTIME:
  164.           case PT_MV_DOUBLE:
  165.           case PT_MV_CURRENCY:
  166.           case PT_MV_SYSTIME:
  167.           case PT_MV_CLSID:
  168.           case PT_MV_I8:
  169.           case PT_MV_BINARY:
  170.           case PT_MV_STRING8:
  171.           case PT_MV_UNICODE:
  172.  
  173.             sc = MAPI_E_UNEXPECTED_TYPE;
  174.             break;
  175.  
  176.           case PT_LONG:
  177.           case PT_ERROR:
  178.           case PT_NULL:
  179.  
  180.             /*  There is no additional data to flatten for
  181.              *  these types of properties.  All the data is
  182.              *  contained in the SPropValue struct.
  183.              */
  184.             continue;
  185.             
  186.           case PT_BINARY:
  187.  
  188.             cb = rgval->Value.bin.cb;
  189.             rgvalDst->Value.bin.lpb = lpb;
  190.             memcpy (lpb, rgval->Value.bin.lpb, (UINT)cb);
  191.             break;
  192.  
  193.           case PT_STRING8:
  194.  
  195.             cb = lstrlenA (rgval->Value.lpszA) + 1;
  196.             rgvalDst->Value.lpszA = (LPSTR)lpb;
  197.             memcpy (lpb, rgval->Value.lpszA, cb);
  198.             break;
  199.  
  200.           case PT_UNICODE:
  201.               
  202.             cb = (lstrlenW (rgval->Value.lpszW) + 1) * sizeof(WCHAR);
  203.             rgvalDst->Value.lpszW = (LPWSTR)lpb;
  204.             memcpy (lpb, rgval->Value.lpszW, cb);
  205.             break;
  206.         }
  207.  
  208.         if (FAILED (sc))
  209.             break;
  210.  
  211.         /*  Align the size and adjust the data pointer */
  212.  
  213.         lpb += Align8 (cb);
  214.     }
  215.  
  216.     DebugTraceSc (ScFlattenProps(), sc);
  217.     return sc;
  218. }
  219.  
  220.  
  221. SCODE
  222. ScNormalizeFlattenedProps (UINT cv, LPSPropValue rgval, LPVOID lpvOld, LPVOID lpvNew)
  223. {
  224.     SCODE sc = S_OK;
  225.  
  226.     for (; cv--; rgval++)
  227.     {
  228.         switch (PROP_TYPE (rgval->ulPropTag))
  229.         {
  230.           default:
  231.           case PT_UNSPECIFIED:
  232.           case PT_I2:
  233.           case PT_R4:
  234.           case PT_APPTIME:
  235.           case PT_DOUBLE:
  236.           case PT_BOOLEAN:
  237.           case PT_CURRENCY:
  238.           case PT_SYSTIME:
  239.           case PT_I8:
  240.           case PT_OBJECT:
  241.           case PT_CLSID:
  242.           case PT_MV_I2:
  243.           case PT_MV_LONG:
  244.           case PT_MV_R4:
  245.           case PT_MV_APPTIME:
  246.           case PT_MV_DOUBLE:
  247.           case PT_MV_CURRENCY:
  248.           case PT_MV_SYSTIME:
  249.           case PT_MV_CLSID:
  250.           case PT_MV_I8:
  251.           case PT_MV_BINARY:
  252.           case PT_MV_STRING8:
  253.           case PT_MV_UNICODE:
  254.  
  255.             sc = MAPI_E_UNEXPECTED_TYPE;
  256.             break;
  257.  
  258.           case PT_LONG:
  259.           case PT_ERROR:
  260.           case PT_NULL:
  261.  
  262.             /*  Nothing to relocate */
  263.               
  264.             continue;
  265.  
  266.           case PT_BINARY:
  267.               
  268.             rgval->Value.bin.lpb = PvRelocPv (rgval->Value.bin.lpb, lpvOld, lpvNew);
  269.             break;
  270.  
  271.           case PT_STRING8:
  272.  
  273.             rgval->Value.lpszA = PvRelocPv (rgval->Value.lpszA, lpvOld, lpvNew);
  274.             break;
  275.  
  276.           case PT_UNICODE:
  277.  
  278.             rgval->Value.lpszW = PvRelocPv (rgval->Value.lpszW, lpvOld, lpvNew);
  279.             break;
  280.         }
  281.         
  282.         if (FAILED (sc))
  283.             break;
  284.     }
  285.  
  286.     DebugTraceSc (ScNormalizeFlattenedProps(), sc);
  287.     return sc;
  288. }
  289.  
  290.  
  291. /*
  292.  *  Common Dialog Helper Functions --------------------------------------------
  293.  */
  294.  
  295. #ifdef  WIN16
  296. #define COMMDLG             "commdlg.dll"
  297. #define GETOPENFILENAME     "GetOpenFileName"
  298. #define GETSAVEFILENAME     "GetSaveFileName"
  299. #else
  300. #define COMMDLG             "comdlg32"
  301. #define GETOPENFILENAME     "GetOpenFileNameA"
  302. #define GETSAVEFILENAME     "GetSaveFileNameA"
  303. #endif
  304. typedef BOOL  (WINAPI COMMDLG_GETOPENFILENAME)(LPOPENFILENAME);
  305. typedef COMMDLG_GETOPENFILENAME FAR * LPCOMMDLG_GETOPENFILENAME;
  306. typedef BOOL  (WINAPI COMMDLG_GETSAVEFILENAME)(LPOPENFILENAME);
  307. typedef COMMDLG_GETSAVEFILENAME FAR * LPCOMMDLG_GETSAVEFILENAME;
  308.    
  309. SCODE
  310. ScSetupCommdlg (HINSTANCE FAR * lplib,
  311.     LPCOMMDLG_GETOPENFILENAME FAR * lppfnOpen,
  312.     LPCOMMDLG_GETSAVEFILENAME FAR * lppfnSave)
  313. {
  314.     HINSTANCE hlib = LoadLibrary (COMMDLG);
  315.     
  316. #ifdef WIN16
  317.     if (hlib < HINSTANCE_ERROR)
  318.         hlib = NULL;
  319. #endif
  320.  
  321.     if (hlib)
  322.     {       
  323.         *lppfnOpen = (LPCOMMDLG_GETOPENFILENAME)GetProcAddress (hlib, GETOPENFILENAME);
  324.         *lppfnSave = (LPCOMMDLG_GETSAVEFILENAME)GetProcAddress (hlib, GETSAVEFILENAME);
  325.     }
  326.  
  327.     *lplib = hlib;
  328.  
  329.     return hlib ? S_OK : MAPI_E_CALL_FAILED;
  330. }
  331.  
  332.  
  333. UINT CALLBACK
  334. CommdlgHook (HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
  335. {
  336.     if (msg == WM_INITDIALOG)
  337.     {
  338.         CTL3D_Subclass (lpCtl3D, hdlg, CTL3D_ALL);
  339.         return TRUE;
  340.     }
  341.     
  342.     return FALSE;   
  343. }
  344.  
  345.  
  346. /*
  347.  *  Filter Exporting ----------------------------------------------------------
  348.  *  
  349.  *  SMH allows the importing and exporting of its filters.  This is
  350.  *  useful when the user has multiple machines available for use.  Or for
  351.  *  when the user needs to re-create their profile.
  352.  *
  353.  *  ScWriteRule() take the muid of a profile section that contains a
  354.  *  filter and writes the rule out to the passed in file handle.
  355.  *  
  356.  *  ScExportFilters() opens the export file and iterates through the
  357.  *  rules and calls ScWriteRule() for each filter.
  358.  */
  359. SCODE
  360. ScWriteRule (LPSCD lpscd, HFILE hf, LPMAPIUID lpmuid)
  361. {
  362.     SCODE sc = S_OK;
  363.     HRESULT hr;
  364.     LPPROFSECT lpsec = NULL;
  365.     LPSPropValue lpval = NULL;
  366.     LPSPropValue lpvalT = NULL;
  367.     ULONG cb;
  368.     ULONG cval;
  369.  
  370.     /*  Open the profile section for the rule */
  371.  
  372.     hr = lpscd->lpadmin->lpVtbl->OpenProfileSection (lpscd->lpadmin,
  373.                                         lpmuid,
  374.                                         NULL,
  375.                                         0,
  376.                                         &lpsec);
  377.     if (!HR_FAILED (hr))
  378.     {
  379.         /*  Get the set of properties describing the rule */
  380.  
  381.         hr = lpsec->lpVtbl->GetProps (lpsec,
  382.                                 (LPSPropTagArray)&sptRule,
  383.                                 0,
  384.                                 &cval,
  385.                                 &lpval);
  386.         if (!HR_FAILED (hr))
  387.         {
  388.             /*  When exporting, we do not want to
  389.              *  export the values for store-based
  390.              *  entryid's.  These can be profile
  391.              *  specific.
  392.              */
  393.             lpval[ipRLEid].ulPropTag = PR_NULL;
  394.             lpval[ipRLSEid].ulPropTag = PR_NULL;
  395.  
  396.             /*  Flatten the remaining property set and
  397.              *  write them out to the export file
  398.              */
  399.             sc = ScSizeFlattenedProps (cval, lpval, &cb);
  400.             if (!FAILED (sc))
  401.             {
  402.                 sc = (*lpscd->lpfnAlloc) (cb, &lpvalT);
  403.                 if (!FAILED (sc))
  404.                 {
  405.                     sc = ScFlattenProps (cval, lpval, (LPBYTE)lpvalT);
  406.                     if (!FAILED (sc))
  407.                     {
  408.                         sc = ScNormalizeFlattenedProps (cval, lpvalT, lpvalT, 0);
  409.                         if (!FAILED (sc))
  410.                         {
  411.                             /*  We have the flattened props, so
  412.                              *  write them out.
  413.                              */
  414.                             _lwrite (hf, (LPBYTE)&cb, sizeof(ULONG));
  415.                             _lwrite (hf, (LPBYTE)lpvalT, (UINT)cb);
  416.                         }
  417.                     }
  418.                 }
  419.             }
  420.         }
  421.     }
  422.     if (HR_FAILED (hr))
  423.         sc = GetScode (sc);
  424.     
  425.     (*lpscd->lpfnFree) (lpvalT);
  426.     (*lpscd->lpfnFree) (lpval);
  427.     UlRelease (lpsec);
  428.     
  429.     DebugTraceSc (ScWriteRule(), sc);
  430.     return sc;
  431. }
  432.  
  433.  
  434. SCODE
  435. ScExportFilters (LPSCD lpscd, HWND hwnd)
  436. {
  437.     SCODE sc = S_OK;
  438.     CHAR rgch[MAX_PATH];
  439.     HFILE hf;
  440.     HINSTANCE hlib = NULL;
  441.     LPCOMMDLG_GETOPENFILENAME lpfnOpen;
  442.     LPCOMMDLG_GETSAVEFILENAME lpfnSave;
  443.     OFSTRUCT ob;
  444.     OPENFILENAME ofn = {sizeof(OPENFILENAME)};
  445.     UINT irl;
  446.     UINT ofFlags = OF_READWRITE | OF_SHARE_EXCLUSIVE | OF_CREATE;
  447.  
  448.     /*  Setup the commdlg structures */
  449.     
  450.     lstrcpy (rgch, "smh.mrl");
  451.     ofn.hwndOwner = hwnd;
  452.     ofn.lpstrFilter = "Filter Export Files (*.mrl)\0*.mrl\0";
  453.     ofn.lpstrFile = rgch;
  454.     ofn.nMaxFile = MAX_PATH;
  455.     ofn.lpstrInitialDir = NULL;
  456.     ofn.lpstrTitle = "Create Filter Export File";
  457.     ofn.lpstrDefExt = "MRL";
  458.     ofn.hInstance = lpscd->hinst;
  459.     ofn.lCustData = 0;
  460.     ofn.lpfnHook = (LPOFNHOOKPROC)CommdlgHook;
  461.     ofn.Flags = OFN_PATHMUSTEXIST       |
  462.                 OFN_HIDEREADONLY        |
  463.                 OFN_NOCHANGEDIR         |
  464.                 OFN_ENABLEHOOK          |
  465.                 OFN_OVERWRITEPROMPT;
  466.  
  467.     if (FWin4Shell ())
  468.         ofn.Flags |= OFN_EXPLORER;
  469.  
  470.     /*  Get commdlg loaded and ready to serve */
  471.  
  472.     if (!FAILED (ScSetupCommdlg (&hlib, &lpfnOpen, &lpfnSave)))
  473.     {
  474.         /*  Prompt the user for the file to use */
  475.         
  476.         if ((*lpfnSave) (&ofn))
  477.         {
  478.             /*  Open the file and iterate through the rules;
  479.              *  Writing each one out as we go.
  480.              */
  481.             hf = OpenFile (rgch, &ob, ofFlags);
  482.             if (hf != HFILE_ERROR)
  483.             {
  484.                 _lwrite (hf, (LPBYTE)rgbExportKey, sizeof(rgbExportKey));
  485.                 _lwrite (hf, (LPBYTE)&lpscd->crl, sizeof(ULONG));
  486.                 for (irl = 0; irl < lpscd->crl; irl++)
  487.                 {
  488.                     sc = ScWriteRule (lpscd, hf, (LPMAPIUID)lpscd->lpbin[irl].lpb);
  489.                     if (FAILED (sc))
  490.                         break;
  491.                 }
  492.  
  493.                 _lclose (hf);
  494.             }
  495.         }
  496.         FreeLibrary (hlib);
  497.     }
  498.  
  499.     DebugTraceSc (ScExportFilters(), sc);
  500.     return sc;
  501. }
  502.  
  503.  
  504. /*
  505.  *  Filter Importing ----------------------------------------------------------
  506.  *  
  507.  *  SMH allows the importing and exporting of its filters.  This is
  508.  *  useful when the user has multiple machines available for use.  Or for
  509.  *  when the user needs to re-create their profile.
  510.  *  
  511.  *  ScInsertImportedRule() takes a SPropValue array and sets those values
  512.  *  into a profile section.  It will replace rules by name -- maybe some
  513.  *  sort of a conflict message would be good here, but... -- otherwise,
  514.  *  it will create a new profile section for each rule.  The filter is
  515.  *  then added to the filters page of the SMH config.
  516.  *  
  517.  *  ScReadRule() reads in the components of a flattened rule from the
  518.  *  passed in file handle.  It then tries to insert the rule into the
  519.  *  profile via ScInsertImportedRule().
  520.  *  
  521.  *  ScImportFilters() opens the imported rule file and iterates through
  522.  *  the file calling ScReadRule() for each contained filter.
  523.  */
  524. SCODE
  525. ScInsertImportedRule (LPSCD lpscd, HWND hctrl, LPSPropValue lpval)
  526. {
  527.     SCODE sc;
  528.     HRESULT hr = hrSuccess;
  529.     LPSBinary lpbin;
  530.     LPTSTR FAR * lppsz;
  531.     LPPROFSECT lpsec = NULL;
  532.     MAPIUID muid;
  533.     UINT irl;
  534.     UINT cb;
  535.  
  536.     /*  See if the filter alread exists -- if so, we wil replace it */
  537.     
  538.     for (irl = 0; irl < lpscd->crl; irl++)
  539.         if (!lstrcmpi (lpscd->lppsz[irl], lpval[ipRLDisp].Value.lpszA))
  540.             break;
  541.  
  542.     if (irl == lpscd->crl)
  543.         hr = lpscd->lpsup->lpVtbl->NewUID (lpscd->lpsup, &muid);
  544.     else
  545.         memcpy (&muid, lpscd->lpbin[irl].lpb, sizeof(MAPIUID));
  546.  
  547.     if (!HR_FAILED (hr))
  548.     {
  549.         hr = lpscd->lpadmin->lpVtbl->OpenProfileSection (lpscd->lpadmin,
  550.                                         &muid,
  551.                                         NULL,
  552.                                         MAPI_MODIFY,
  553.                                         &lpsec);
  554.         if (!HR_FAILED (hr))
  555.         {
  556.             hr = lpsec->lpVtbl->SetProps (lpsec, cpRLMax, lpval, NULL);
  557.             if (!HR_FAILED (hr))
  558.                 hr = lpsec->lpVtbl->SaveChanges (lpsec, 0);
  559.         }
  560.     }
  561.  
  562.     /*  Add the filter to the list of active filters */
  563.     
  564.     if (!HR_FAILED (hr))
  565.     {
  566.         if (irl == lpscd->crlMax)
  567.         {
  568.             /*  We need to make room for new entries */
  569.  
  570.             cb = (irl + GROW_SIZE) * sizeof(LPVOID);
  571.             if (FAILED (sc = (*lpscd->lpfnAlloc) (cb, (LPVOID FAR *)&lppsz)))
  572.                 goto ret;
  573.             memcpy (lppsz, lpscd->lppsz, lpscd->crl * sizeof(LPTSTR));
  574.                 
  575.             cb = (irl + GROW_SIZE) * sizeof(SBinary);
  576.             if (FAILED (sc = (*lpscd->lpfnAlloc) (cb, &lpbin)))
  577.                 goto ret;
  578.             memcpy (lpbin, lpscd->lpbin, lpscd->crl * sizeof(SBinary));
  579.  
  580.             /*  Swap out the old for the new */
  581.  
  582.             (*lpscd->lpfnFree) (lpscd->lppsz);
  583.             (*lpscd->lpfnFree) (lpscd->lpbin);
  584.             lpscd->crlMax += GROW_SIZE;
  585.             lpscd->lppsz = lppsz;
  586.             lpscd->lpbin = lpbin;
  587.         }
  588.  
  589.         sc = (*lpscd->lpfnAlloc) (lstrlen (lpval[ipRLDisp].Value.LPSZ) + 1, &lpscd->lppsz[irl]);
  590.         if (!FAILED (sc) &&
  591.             !FAILED (sc = (*lpscd->lpfnAlloc) (sizeof(MAPIUID), &lpscd->lpbin[irl].lpb)))
  592.         {
  593.             if ((ListBox_AddString (hctrl, lpval[ipRLDisp].Value.LPSZ) != LB_ERR) &&
  594.                 (ListBox_SetItemData (hctrl, irl, irl) != LB_ERR))
  595.             {
  596.                 /*  Copy the identifiers across */
  597.                     
  598.                 lstrcpy (lpscd->lppsz[irl], lpval[ipRLDisp].Value.LPSZ);
  599.                 memcpy (lpscd->lpbin[irl].lpb, &muid, sizeof(MAPIUID));
  600.                 lpscd->lpbin[irl].cb = sizeof(MAPIUID);
  601.                 lpscd->crl++;
  602.             }
  603.         }
  604.         else
  605.             hr = ResultFromScode (sc);
  606.     }
  607.  
  608. ret:
  609.     
  610.     UlRelease (lpsec);
  611.     DebugTraceResult (ScInsertImportedRule(), hr);
  612.     return GetScode (hr);
  613. }
  614.  
  615.  
  616. SCODE
  617. ScReadRule (LPSCD lpscd, HWND hctrl, HFILE hf)
  618. {
  619.     SCODE sc = S_OK;
  620.     LPSPropValue lpval = NULL;
  621.     ULONG cb;
  622.     
  623.     if (_lread (hf, (LPBYTE)&cb, sizeof(ULONG)) == sizeof(ULONG))
  624.     {
  625.         sc = (*lpscd->lpfnAlloc) (cb, &lpval);
  626.         if (!FAILED (sc))
  627.         {
  628.             if (_lread (hf, (LPBYTE)lpval, (UINT)cb) == cb)
  629.             {
  630.                 sc = ScNormalizeFlattenedProps (cpRLMax, lpval, 0, lpval);
  631.                 if (!FAILED (sc))
  632.                     sc = ScInsertImportedRule (lpscd, hctrl, lpval);
  633.             }
  634.         }
  635.     }
  636.     
  637.     (*lpscd->lpfnFree) (lpval);
  638.     DebugTraceSc (ScWriteRule(), sc);
  639.     return sc;
  640. }
  641.  
  642.  
  643. SCODE
  644. ScImportFilters (LPSCD lpscd, HWND hwnd, HWND hctrl)
  645. {
  646.     SCODE sc = S_OK;
  647.     BOOL fCtl3d = FALSE;
  648.     CHAR rgch[MAX_PATH];
  649.     CHAR rgchT[MAX_PATH + 60];
  650.     CHAR rgb[sizeof(rgbExportKey)];
  651.     HFILE hf;
  652.     OFSTRUCT ob;
  653.     UINT ofFlags = OF_READ | OF_SHARE_EXCLUSIVE;
  654.     UINT irl;
  655.     ULONG crlNew;
  656.     HINSTANCE hlib = NULL;
  657.     LPCOMMDLG_GETOPENFILENAME lpfnOpen;
  658.     LPCOMMDLG_GETSAVEFILENAME lpfnSave;
  659.     OPENFILENAME ofn = {sizeof(OPENFILENAME)};
  660.  
  661.     lstrcpy (rgch, "*.mrl");
  662.     ofn.hwndOwner = hwnd;
  663.     ofn.lpstrFilter = "Filter Export Files (*.mrl)\0*.mrl\0";
  664.     ofn.lpstrFile = rgch;
  665.     ofn.nMaxFile = MAX_PATH;
  666.     ofn.lpstrInitialDir = NULL;
  667.     ofn.lpstrTitle = "Open Filter Export File";
  668.     ofn.lpstrDefExt = "MRL";
  669.     ofn.hInstance = lpscd->hinst;
  670.     ofn.lCustData = 0;
  671.     ofn.lpfnHook = (LPOFNHOOKPROC)CommdlgHook;
  672.     ofn.Flags = OFN_PATHMUSTEXIST       |
  673.                 OFN_HIDEREADONLY        |
  674.                 OFN_ENABLEHOOK          |
  675.                 OFN_NOCHANGEDIR;
  676.  
  677.     if (FWin4Shell ())
  678.         ofn.Flags |= OFN_EXPLORER;
  679.  
  680.     if (!FAILED (ScSetupCommdlg (&hlib, &lpfnOpen, &lpfnSave)))
  681.     {
  682.         if ((*lpfnOpen) (&ofn))
  683.         {
  684.             hf = OpenFile (rgch, &ob, ofFlags);
  685.             if (hf != HFILE_ERROR)
  686.             {
  687.                 _lread (hf, (LPBYTE)rgb, sizeof(rgbExportKey));
  688.                 if (!memcmp (rgb, rgbExportKey, sizeof(rgbExportKey)))
  689.                 {
  690.                     _lread (hf, (LPBYTE)&crlNew, sizeof(ULONG));
  691.                     for (irl = 0; irl < crlNew; irl++)
  692.                     {
  693.                         sc = ScReadRule (lpscd, hctrl, hf);
  694.                         if (FAILED (sc))
  695.                             break;
  696.                     }
  697.                 }
  698.                 else
  699.                 {
  700.                     wsprintf (rgchT,
  701.                         "'%s' is an invalid or corrupt exported filter file.",
  702.                         rgch);
  703.  
  704.                     if (CTL3D_GetVer(lpCtl3D) >= 0x220 && !CTL3D_IsAutoSubclass(lpCtl3D))
  705.                         CTL3D_AutoSubclass (lpCtl3D, lpscd->hinst, &fCtl3d);
  706.                     MessageBox (hwnd,
  707.                         rgchT,
  708.                         "Import filters",
  709.                         MB_TASKMODAL | MB_OK | MB_ICONINFORMATION);
  710.                     CTL3D_CeaseAutoSubclass(lpCtl3D, fCtl3d);
  711.                 }
  712.  
  713.                 _lclose (hf);
  714.             }
  715.         }
  716.         else
  717.             sc = MAPI_E_USER_CANCEL;
  718.         
  719.         FreeLibrary (hlib);
  720.     }
  721.     
  722.     DebugTraceSc (ScImportFilters(), sc);
  723.     return sc;
  724. }
  725.  
  726.  
  727.