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

Windows编程

开发平台:

Visual C++

  1. /***********************************************************************
  2.  *
  3.  *  ABCONT.C
  4.  *
  5.  *  Sample AB directory container object
  6.  *
  7.  *  This file contains the code for implementing the Sample AB
  8.  *  directory container object.
  9.  *
  10.  *  This directory container was retrieved by OpenEntry on the entryid
  11.  *  retrieved from the single row of the hierarchy table (IVTROOT in root.c).
  12.  *
  13.  *  The following routines are implemented in this file:
  14.  *
  15.  *      HrNewSampDirectory
  16.  *      ABC_Release
  17.  *      ABC_SaveChanges
  18.  *      ABC_OpenProperty
  19.  *      ABC_GetContentsTable
  20.  *      ABC_GetHierarchyTable
  21.  *
  22.  *      HrGetDetailsDialog
  23.  *
  24.  *      HrNewABCButton
  25.  *      ABCBUTT_QueryInterface
  26.  *      ABCBUTT_Release
  27.  *      ABCBUTT_Activate
  28.  *      ABCBUTT_GetState
  29.  *
  30.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  31.  *
  32.  ***********************************************************************/
  33. #include "abp.h"
  34. #include "sampabp.rh"
  35. #include <smpab.h>
  36. /*
  37.  *  Proptags used only in this module
  38.  */
  39. #define PR_RADIO_BUTTON_VALUE       PROP_TAG(PT_LONG,   0x6601)
  40. #define PR_BUTTON_PRESS             PROP_TAG(PT_OBJECT, 0x6603)
  41. #define PR_SAB_FILE_TEMP            PROP_TAG(PT_TSTRING,0x6605)
  42. /*
  43.  *  Possible values for PR_RADIO_BUTTON_VALUE
  44.  */
  45. #define RADIO_BUTTON_1_RETURN_VALUE 1
  46. #define RADIO_BUTTON_2_RETURN_VALUE 2
  47. #define RADIO_BUTTON_3_RETURN_VALUE 3
  48. #define RADIO_BUTTON_4_RETURN_VALUE 4
  49. /*
  50.  *  Structure for the 'this'
  51.  */
  52. typedef struct _ABCNT
  53. {
  54.     const ABC_Vtbl FAR * lpVtbl;
  55.     SAB_Wrapped;
  56.     /* details display table */
  57.     LPTABLEDATA lpTDatDetails;
  58. } ABCNT, *LPABCNT;
  59. /*
  60.  *  This is the data structure passed to the
  61.  *  HrNotify method of the Table Data Object
  62.  *  in ABCBUTT_Activate that uniquely identifies
  63.  *  the control in the display table that needs
  64.  *  to be updated.
  65.  */
  66. typedef struct
  67. {
  68.     MAPIUID muid;
  69.     ULONG ulIdc;
  70. } NOTIFDATA;
  71. /*
  72.  *  The actual data.  Note that the control
  73.  *  is specified by IDC_DIR_SAB_FILE_NAME.
  74.  */
  75. NOTIFDATA notifdata =
  76. {MUIDABSAMPLE, IDC_DIR_SAB_FILE_NAME};
  77. /* Display table control structures for the Directory property sheet. */
  78. /*
  79.  *  Edit control that displays the current .SAB file.
  80.  */
  81. DTBLEDIT editDirFileName =
  82. {
  83.     sizeof(DTBLEDIT),
  84.     0,
  85.     MAX_PATH,
  86.     PR_SAB_FILE_TEMP
  87. };
  88. /*
  89.  *  Button control for changing the current .SAB file.
  90.  */
  91. DTBLBUTTON buttonDirChange =
  92. {
  93.     sizeof(DTBLBUTTON),
  94.     0,
  95.     PR_BUTTON_PRESS
  96. };
  97. /*
  98.  *  The next four controls are radio buttons.  Note how they
  99.  *  are related by their use of PR_RADIO_BUTTON_VALUE and
  100.  *  differentiated by RADIO_BUTTON_x_RETURN_VALUE.  Also note
  101.  *  the '4' which says how many controls are in this group
  102.  *  of radio buttons.
  103.  */
  104. DTBLRADIOBUTTON radiobuttonDir1 =
  105. {
  106.     sizeof(DTBLRADIOBUTTON),
  107.     0,
  108.     4,
  109.     PR_RADIO_BUTTON_VALUE,
  110.     RADIO_BUTTON_1_RETURN_VALUE
  111. };
  112. DTBLRADIOBUTTON radiobuttonDir2 =
  113. {
  114.     sizeof(DTBLRADIOBUTTON),
  115.     0,
  116.     4,
  117.     PR_RADIO_BUTTON_VALUE,
  118.     RADIO_BUTTON_2_RETURN_VALUE
  119. };
  120. DTBLRADIOBUTTON radiobuttonDir3 =
  121. {
  122.     sizeof(DTBLRADIOBUTTON),
  123.     0,
  124.     4,
  125.     PR_RADIO_BUTTON_VALUE,
  126.     RADIO_BUTTON_3_RETURN_VALUE
  127. };
  128. DTBLRADIOBUTTON radiobuttonDir4 =
  129. {
  130.     sizeof(DTBLRADIOBUTTON),
  131.     0,
  132.     4,
  133.     PR_RADIO_BUTTON_VALUE,
  134.     RADIO_BUTTON_4_RETURN_VALUE
  135. };
  136. /*
  137.  *  This is the page for the directory details.
  138.  */
  139. DTCTL rgdtctlDirGeneral[] =
  140. {
  141.     /*
  142.      *  directory general propery page
  143.      *  This names the pane for this page.
  144.      *  Although not currently not required in
  145.      *  this version, we expect to require it by
  146.      *  the time MAPI 1.0 ships.
  147.      */
  148.     {DTCT_PAGE, 0, NULL, 0, NULL, 0,
  149.         &dtblpage},
  150.     /* controls and edit control containing sab file name */
  151.     {DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL,
  152.         &dtbllabel},
  153.     {DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL,
  154.         &dtbllabel},
  155.     {DTCT_EDIT, 0, (LPBYTE) &notifdata, sizeof(NOTIFDATA),
  156.         szNoFilter, IDC_DIR_SAB_FILE_NAME, &editDirFileName},
  157.     /* control and push button for changing sab file */
  158.     {DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL,
  159.         &dtbllabel},
  160.     {DTCT_BUTTON, 0, NULL, 0, NULL, IDC_DIR_CHANGE,
  161.         &buttonDirChange},
  162.     /* radio button group box and radio buttons */
  163.     {DTCT_GROUPBOX, 0, NULL, 0, NULL, IDC_STATIC_CONTROL,
  164.         &dtblgroupbox},
  165.     {DTCT_RADIOBUTTON, DT_EDITABLE, NULL, 0, NULL, IDC_DIR_RADIO_1,
  166.         &radiobuttonDir1},
  167.     {DTCT_RADIOBUTTON, DT_EDITABLE, NULL, 0, NULL, IDC_DIR_RADIO_2,
  168.         &radiobuttonDir2},
  169.     {DTCT_RADIOBUTTON, DT_EDITABLE, NULL, 0, NULL, IDC_DIR_RADIO_3,
  170.         &radiobuttonDir3},
  171.     {DTCT_RADIOBUTTON, DT_EDITABLE, NULL, 0, NULL, IDC_DIR_RADIO_4,
  172.         &radiobuttonDir4},
  173. };
  174. /*
  175.  * Display table pages for Directory Details
  176.  */
  177. DTPAGE rgdtpageDir[] =
  178. {
  179.     {
  180.         sizeof(rgdtctlDirGeneral) / sizeof(DTCTL),
  181.         (LPTSTR) MAKEINTRESOURCE(DirGeneralPage),
  182.         "",
  183.         rgdtctlDirGeneral
  184.     }
  185. };
  186. /*
  187.  *  ABCont vtbl is filled in here.
  188.  */
  189. ABC_Vtbl vtblABC =
  190. {
  191.     (ABC_QueryInterface_METHOD *)       ROOT_QueryInterface,
  192.     (ABC_AddRef_METHOD *)               ROOT_AddRef,    
  193.     ABC_Release,
  194.     (ABC_GetLastError_METHOD *)         ROOT_GetLastError,
  195.     ABC_SaveChanges,
  196.     (ABC_GetProps_METHOD *)             WRAP_GetProps,
  197.     (ABC_GetPropList_METHOD *)          WRAP_GetPropList,
  198.     ABC_OpenProperty,
  199.     (ABC_SetProps_METHOD *)             WRAP_SetProps,
  200.     (ABC_DeleteProps_METHOD *)          WRAP_DeleteProps,
  201.     (ABC_CopyTo_METHOD *)               WRAP_CopyTo,
  202.     (ABC_CopyProps_METHOD *)            WRAP_CopyProps,
  203.     (ABC_GetNamesFromIDs_METHOD *)      WRAP_GetNamesFromIDs,
  204.     (ABC_GetIDsFromNames_METHOD *)      WRAP_GetIDsFromNames,
  205.     ABC_GetContentsTable,
  206.     ABC_GetHierarchyTable,
  207.     (ABC_OpenEntry_METHOD *)            ROOT_OpenEntry,
  208.     (ABC_SetSearchCriteria_METHOD *)    ROOT_SetSearchCriteria,
  209.     (ABC_GetSearchCriteria_METHOD *)    ROOT_GetSearchCriteria,
  210.     (ABC_CreateEntry_METHOD *)          ROOT_CreateEntry,
  211.     (ABC_CopyEntries_METHOD *)          ROOT_CopyEntries,
  212.     (ABC_DeleteEntries_METHOD *)        ROOT_DeleteEntries,
  213.     (ABC_ResolveNames_METHOD *)         ROOT_ResolveNames
  214. };
  215. /*
  216.  *  Private functions
  217.  */
  218. HRESULT HrNewABCButton( LPABCNT lpABC,
  219.                         ULONG ulInterfaceOptions,
  220.                         ULONG ulFlags,
  221.                         LPMAPICONTROL FAR * lppMAPICont);
  222. //HRESULT HrGetSearchDialog(LPABCNT lpABC, LPMAPITABLE * lppSearchTable);
  223. HRESULT HrGetDetailsDialog(LPABCNT lpABC, LPMAPITABLE * lppDetailsTable);
  224. /*
  225.  -  NewSampDirectory
  226.  -
  227.  *  Creates a Directory container object.
  228.  *
  229.  *
  230.  */
  231. /*
  232.  *  properties of which I want to track whether or not they've
  233.  *  been changed.
  234.  */
  235. enum { ivalWatchPR_SAB_FILE_TEMP = 0,
  236.         cvalWatchMax };
  237. SizedSPropTagArray(cvalWatchMax, tagaPropsToWatch) =
  238. {
  239.     cvalWatchMax,
  240.     {
  241.         PR_SAB_FILE_TEMP
  242.     }
  243. };
  244. /*
  245.  *  Properties that are initially set on this object
  246.  */
  247. enum {  ivalabcPR_DISPLAY_TYPE = 0,
  248.         ivalabcPR_OBJECT_TYPE,
  249.         ivalabcPR_ENTRYID,
  250.         ivalabcPR_RECORD_KEY,
  251.         ivalabcPR_SEARCH_KEY,
  252.         ivalabcPR_DISPLAY_NAME_A,
  253.         ivalabcPR_CONTAINER_FLAGS,
  254.         ivalabcPR_SAB_FILE,
  255.         ivalabcPR_SAB_FILE_TEMP,
  256.         ivalabcPR_RADIO_BUTTON_VALUE,
  257.         cvalabcMax };
  258. static SizedSPropTagArray( cvalabcMax, tagaABCAccess) =
  259. {
  260.     cvalabcMax,
  261.     {   PR_DISPLAY_TYPE,
  262.         PR_OBJECT_TYPE,
  263.         PR_ENTRYID,
  264.         PR_RECORD_KEY,
  265.         PR_SEARCH_KEY,
  266.         PR_DISPLAY_NAME_A,
  267.         PR_CONTAINER_FLAGS,
  268.         PR_SAB_FILE,
  269.         PR_SAB_FILE_TEMP,
  270.         PR_RADIO_BUTTON_VALUE
  271.       }
  272. };
  273. static ULONG    rgulABCAccess[cvalabcMax] =
  274. {
  275.       IPROP_READONLY | IPROP_CLEAN,     /* PR_DISPLAY_TYPE */
  276.       IPROP_READONLY | IPROP_CLEAN,     /* PR_OBJECT_TYPE */
  277.       IPROP_READONLY | IPROP_CLEAN,     /* PR_ENTRYID */
  278.       IPROP_READONLY | IPROP_CLEAN,     /* PR_RECORD_KEY */
  279.       IPROP_READONLY | IPROP_CLEAN,     /* PR_SEARCH_KEY */
  280.       IPROP_READONLY | IPROP_CLEAN,     /* PR_DISPLAY_NAME_A */
  281.       IPROP_READONLY | IPROP_CLEAN,     /* PR_CONTAINER_FLAGS */
  282.       IPROP_READWRITE | IPROP_CLEAN,    /* PR_SAB_FILE */
  283.       IPROP_READWRITE | IPROP_CLEAN,    /* PR_SAB_FILE_TEMP */
  284.       IPROP_READWRITE | IPROP_CLEAN     /* PR_RADIO_BUTTON_VALUE */
  285. };
  286. HRESULT
  287. HrNewSampDirectory( LPABCONT *          lppABC,
  288.                     ULONG *             lpulObjType,
  289.                     LPABLOGON           lpABLogon,
  290.                     LPCIID              lpInterface,
  291.                     HINSTANCE           hLibrary,
  292.                     LPALLOCATEBUFFER    lpAllocBuff,
  293.                     LPALLOCATEMORE      lpAllocMore,
  294.                     LPFREEBUFFER        lpFreeBuff,
  295.                     LPMALLOC            lpMalloc )
  296. {
  297.     HRESULT hResult = hrSuccess;
  298.     LPABCNT lpABC = NULL;
  299.     SCODE sc;
  300.     LPPROPDATA lpPropData = NULL;
  301.     SPropValue spv[cvalabcMax];
  302.     char szBuf[MAX_PATH];
  303.     MAPIUID * lpMuidLogon;
  304.     LPSTR lpszFileName;
  305.     DIR_ENTRYID eidRoot =   {   {0, 0, 0, 0},
  306.                                 MUIDABSAMPLE,
  307.                                 SAMP_VERSION,
  308.                                 SAMP_DIRECTORY };
  309.     
  310.     /*  Do I support this interface?? */
  311.     if (lpInterface)
  312.     {
  313.         if (memcmp(lpInterface, &IID_IABContainer, sizeof(IID)) &&
  314.             memcmp(lpInterface, &IID_IMAPIContainer, sizeof(IID)) &&
  315.             memcmp(lpInterface, &IID_IMAPIProp, sizeof(IID)) &&
  316.             memcmp(lpInterface, &IID_IUnknown, sizeof(IID)))
  317.         {
  318.             DebugTraceSc(HrNewSampDirectory, MAPI_E_INTERFACE_NOT_SUPPORTED);
  319.             return ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  320.         }
  321.     }
  322.     /*
  323.      *  Allocate space for the directory container structure
  324.      */
  325.     sc = lpAllocBuff( sizeof(ABCNT), (LPVOID *) &lpABC );
  326.     if (FAILED(sc))
  327.     {
  328.         hResult = ResultFromScode(sc);
  329.         goto err;
  330.     }
  331.     lpABC->lpVtbl = &vtblABC;
  332.     lpABC->lcInit = 1;
  333.     lpABC->hResult = hrSuccess;
  334.     lpABC->idsLastError = 0;
  335.     lpABC->hLibrary = hLibrary;
  336.     lpABC->lpAllocBuff = lpAllocBuff;
  337.     lpABC->lpAllocMore = lpAllocMore;
  338.     lpABC->lpFreeBuff = lpFreeBuff;
  339.     lpABC->lpMalloc = lpMalloc;
  340.     lpABC->lpABLogon = lpABLogon;
  341.     lpABC->lpTDatDetails = NULL;
  342.     /*
  343.      *  Create property storage object
  344.      */
  345.     sc = CreateIProp((LPIID) &IID_IMAPIPropData,
  346.         lpAllocBuff,
  347.         lpAllocMore,
  348.         lpFreeBuff,
  349.         lpMalloc,
  350.         &lpPropData);
  351.     if (FAILED(sc))
  352.     {
  353.         hResult = ResultFromScode(sc);
  354.         goto err;
  355.     }
  356.     /*
  357.      *  initialize the muid in the entry id
  358.      */
  359.     lpMuidLogon = LpMuidFromLogon(lpABLogon);
  360.     eidRoot.muidID = *lpMuidLogon;
  361.     /*
  362.      *  Set up initial set of properties associated with this
  363.      *  container.
  364.      */
  365.     spv[ivalabcPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
  366.     spv[ivalabcPR_DISPLAY_TYPE].Value.l = DT_NOT_SPECIFIC;
  367.     spv[ivalabcPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
  368.     spv[ivalabcPR_OBJECT_TYPE].Value.l = MAPI_ABCONT;
  369.     spv[ivalabcPR_ENTRYID].ulPropTag = PR_ENTRYID;
  370.     spv[ivalabcPR_ENTRYID].Value.bin.cb = sizeof(DIR_ENTRYID);
  371.     spv[ivalabcPR_ENTRYID].Value.bin.lpb = (LPBYTE) &eidRoot;
  372.     spv[ivalabcPR_RECORD_KEY].ulPropTag = PR_RECORD_KEY;
  373.     spv[ivalabcPR_RECORD_KEY].Value.bin.cb = sizeof(DIR_ENTRYID);
  374.     spv[ivalabcPR_RECORD_KEY].Value.bin.lpb = (LPBYTE) &eidRoot;
  375.     spv[ivalabcPR_SEARCH_KEY].ulPropTag = PR_SEARCH_KEY;
  376.     spv[ivalabcPR_SEARCH_KEY].Value.bin.cb = sizeof(DIR_ENTRYID);
  377.     spv[ivalabcPR_SEARCH_KEY].Value.bin.lpb = (LPBYTE) &eidRoot;
  378.     spv[ivalabcPR_DISPLAY_NAME_A].ulPropTag = PR_DISPLAY_NAME_A;
  379.     GenerateContainerDN(lpABLogon, szBuf);
  380.     spv[ivalabcPR_DISPLAY_NAME_A].Value.lpszA = szBuf;
  381.     spv[ivalabcPR_CONTAINER_FLAGS].ulPropTag = PR_CONTAINER_FLAGS;
  382.     spv[ivalabcPR_CONTAINER_FLAGS].Value.l = AB_RECIPIENTS;
  383.     /*
  384.      *  Get the current .SAB file name from our logon object
  385.      */
  386.     hResult = HrLpszGetCurrentFileName(lpABLogon, &lpszFileName);
  387.     if (HR_FAILED(hResult))
  388.     {
  389.         goto err;
  390.     }
  391.     spv[ivalabcPR_SAB_FILE].ulPropTag = PR_SAB_FILE;
  392.     spv[ivalabcPR_SAB_FILE].Value.lpszA = lpszFileName;
  393.     spv[ivalabcPR_SAB_FILE_TEMP].ulPropTag = PR_SAB_FILE_TEMP;
  394.     spv[ivalabcPR_SAB_FILE_TEMP].Value.lpszA = lpszFileName;
  395.     spv[ivalabcPR_RADIO_BUTTON_VALUE].ulPropTag = PR_RADIO_BUTTON_VALUE;
  396.     spv[ivalabcPR_RADIO_BUTTON_VALUE].Value.l = RADIO_BUTTON_1_RETURN_VALUE;
  397.     /*
  398.      *   Set the default properties
  399.      */
  400.     hResult = lpPropData->lpVtbl->SetProps(lpPropData,
  401.         cvalabcMax,
  402.         spv,
  403.         NULL);
  404.     /*
  405.      *  No longer need this buffer
  406.      */
  407.     lpFreeBuff(lpszFileName);
  408.     if (HR_FAILED(hResult))
  409.     {
  410.         goto err;
  411.     }
  412.     /*
  413.      *  We mark all properties as being CLEAN initially.  Only PR_SAB_FILE,
  414.      *  PR_SAB_FILE_TEMP, and PR_RADIO_BUTTON_VALUE are marked as READWRITE
  415.      *  (Readable/Writable by the client) the others are marked as READONLY
  416.      *  so that the client may not alter them.
  417.      *
  418.      *  Notice that the ABC_SaveChanges code checks the IPROP_DIRTY bit
  419.      *  on PR_SAB_FILE_TEMP to see if the client altered it!
  420.      */
  421.     (void) lpPropData->lpVtbl->HrSetPropAccess(lpPropData,
  422.                                 (LPSPropTagArray) &tagaABCAccess,
  423.                                 rgulABCAccess);
  424.     InitializeCriticalSection(&lpABC->cs);
  425.     /*  We must AddRef the lpABLogon object since we will be using it
  426.      */
  427.     lpABLogon->lpVtbl->AddRef(lpABLogon);
  428.     lpABC->lpPropData = (LPMAPIPROP) lpPropData;
  429.     *lppABC = (LPABCONT) lpABC;
  430.     *lpulObjType = MAPI_ABCONT;
  431. out:
  432.     DebugTraceResult(HrNewSampDirectory, hResult);
  433.     return hResult;
  434. err:
  435.     /*
  436.      *  free the ABContainer object
  437.      */
  438.     lpFreeBuff( lpABC );
  439.     /*
  440.      *  free the property storage object
  441.      */
  442.     if (lpPropData)
  443.         lpPropData->lpVtbl->Release(lpPropData);
  444.     goto out;
  445. }
  446. /*
  447.  -  ABC_Release
  448.  -
  449.  *  Decrement lcInit.
  450.  *      When lcInit == 0, free up the lpABC structure
  451.  *
  452.  */
  453. STDMETHODIMP_(ULONG)
  454. ABC_Release(LPABCNT lpABC)
  455. {
  456.     long lcInit;
  457.     
  458.     /*
  459.      *  Check to see if it has a jump table
  460.      */
  461.     
  462.     ABC_ValidateObject(Release, lpABC);
  463.     Validate_IUnknown_Release(lpABC);
  464.     EnterCriticalSection(&lpABC->cs);
  465.     lcInit = --lpABC->lcInit;
  466.     LeaveCriticalSection(&lpABC->cs);
  467.     if (lcInit == 0)
  468.     {
  469.         /*
  470.          *  Get rid of the lpPropData
  471.          */
  472.         if (lpABC->lpPropData)
  473.             lpABC->lpPropData->lpVtbl->Release(lpABC->lpPropData);
  474.         /*
  475.          *  Get rid of the details table
  476.          */
  477.         if (lpABC->lpTDatDetails)
  478.             lpABC->lpTDatDetails->lpVtbl->Release(lpABC->lpTDatDetails);
  479.         /*  
  480.          *  Release our reference to the ABLogon object.
  481.          */
  482.         if (lpABC->lpABLogon)
  483.         {
  484.             lpABC->lpABLogon->lpVtbl->Release(lpABC->lpABLogon);
  485.             lpABC->lpABLogon = NULL;
  486.         }
  487.         /*
  488.          *  Destroy the critical section for this object
  489.          */
  490.         DeleteCriticalSection(&lpABC->cs);
  491.         /*
  492.          *  Set the Jump table to NULL.  This way the client will find out
  493.          *  real fast if it's calling a method on a released object.  That is,
  494.          *  the client will crash.  Hopefully, this will happen during the
  495.          *  development stage of the client.
  496.          */
  497.         lpABC->lpVtbl = NULL;
  498.         /*
  499.          *  Need to free the object
  500.          */
  501.         lpABC->lpFreeBuff(lpABC);
  502.         return 0;
  503.     }
  504.     return lpABC->lcInit;
  505. }
  506. /*
  507.  -  ABC_SaveChanges
  508.  -
  509.  *  This is used to save changes associated with the search dialog
  510.  *  in order to get the advanced search restriction and to save changes
  511.  *  associated with the container details dialog.
  512.  *
  513.  */
  514. SPropTagArray tagaSAB_FILE =
  515. {
  516.     1,
  517.     {
  518.         PR_SAB_FILE_TEMP
  519.     }
  520. };
  521. STDMETHODIMP
  522. ABC_SaveChanges(LPABCNT lpABC, ULONG ulFlags)
  523. {
  524.     HRESULT hResult = hrSuccess;
  525.     ULONG ulCount;
  526.     LPSPropValue lpspv = NULL;
  527.     ULONG FAR *rgulAccess = NULL;
  528.     ULONG ulAccess = IPROP_CLEAN | IPROP_READWRITE; 
  529.     LPSPropTagArray ptagaSAB_FILE = (LPSPropTagArray) &tagaSAB_FILE;
  530.     LPPROPDATA lpPropData = (LPPROPDATA) lpABC->lpPropData;
  531.     
  532.     ABC_ValidateObject(SaveChanges, lpABC);
  533.     Validate_IMAPIProp_SaveChanges(lpABC, ulFlags);
  534.     
  535.     EnterCriticalSection(&lpABC->cs);
  536.     /*
  537.      *  Check to see if anyone has dirtied the PR_SAB_FILE_TEMP
  538.      */
  539.     (void) lpPropData->lpVtbl->HrGetPropAccess(lpPropData,
  540.                                         &ptagaSAB_FILE,
  541.                                         &rgulAccess);
  542.     if (!rgulAccess || !((*rgulAccess) & IPROP_DIRTY))
  543.     {
  544.         /*
  545.          *  No, nothing to update then head on out
  546.          */
  547.         goto ret;
  548.     }
  549.     /*
  550.      *  Set back to being clean
  551.      */
  552.     (void )lpPropData->lpVtbl->HrSetPropAccess(lpPropData,
  553.                                         ptagaSAB_FILE,
  554.                                         &ulAccess);
  555.     /*
  556.      * Get the temporary sab file name
  557.      */
  558.     hResult = lpPropData->lpVtbl->GetProps(
  559.         lpPropData,
  560.         &tagaSAB_FILE,
  561.         0,      /* ansi */
  562.         &ulCount,
  563.         &lpspv);
  564.     if (HR_FAILED(hResult))
  565.     {
  566.         goto ret;
  567.     }
  568.     if (lpspv->ulPropTag != PR_SAB_FILE_TEMP)
  569.     {
  570.         /*
  571.          *  There's no reason this property shouldn't be there.
  572.          */
  573.         hResult = ResultFromScode(MAPI_E_CORRUPT_DATA);
  574.         goto ret;
  575.     }
  576.     /*
  577.      *  Save the new name back into the object as PR_SAB_FILE
  578.      */
  579.     lpspv->ulPropTag = PR_SAB_FILE;
  580.     
  581.     hResult = lpPropData->lpVtbl->SetProps(
  582.             lpPropData,
  583.             1,
  584.             lpspv, NULL);
  585.     if (HR_FAILED(hResult))
  586.     {
  587.         /*
  588.          *  Do nothing...  So I couldn't save it away this time...
  589.          */
  590.         hResult = hrSuccess;
  591.         goto ret;
  592.     }
  593.     /*
  594.      *  Update every other object that needs this new information
  595.      */
  596.     hResult = HrReplaceCurrentFileName(lpABC->lpABLogon, lpspv->Value.lpszA);
  597. ret:
  598.     LeaveCriticalSection(&lpABC->cs);
  599.     lpABC->lpFreeBuff(lpspv);
  600.     lpABC->lpFreeBuff(rgulAccess);
  601.     DebugTraceResult(ABC_SaveChanges, hResult);
  602.     return hResult;
  603. }
  604. /*************************************************************************
  605.  *
  606.  -  ABC_OpenProperty
  607.  -
  608.  *
  609.  *  This method allows the opening of the following object:
  610.  *
  611.  *  PR_BUTTON_PRESS  :-  Gets the MAPIControl object associated
  612.  *                       with the button on this container's details.
  613.  *  PR_DETAILS_TABLE :-  Gets the display table associated with
  614.  *                       the details for this container.
  615.  *  PR_SEARCH        :-  Gets the advanced search object associated with
  616.  *                       this container.
  617.  *  PR_CONTAINER_CONTENTS  :-  Same as GetContentsTable()
  618.  *  PR_CONTAINER_HIERARCHY :-  Same as GetHierarchyTable()
  619.  *
  620.  *
  621.  */
  622. STDMETHODIMP
  623. ABC_OpenProperty(LPABCNT lpABC,
  624.     ULONG ulPropTag,
  625.     LPCIID lpiid,
  626.     ULONG ulInterfaceOptions,
  627.     ULONG ulFlags,
  628.     LPUNKNOWN * lppUnk)
  629. {
  630.     HRESULT hResult;
  631.     ABC_ValidateObject(OpenProperty, lpABC);
  632.     Validate_IMAPIProp_OpenProperty(lpABC, ulPropTag, lpiid, ulInterfaceOptions,
  633.                                     ulFlags, lppUnk);
  634.     /*
  635.      *  Check for flags we can't support
  636.      */
  637.     if (ulFlags & (MAPI_CREATE|MAPI_MODIFY))
  638.     {
  639.         hResult = ResultFromScode(E_ACCESSDENIED);
  640.         goto out;
  641.     }
  642.         
  643.     if (ulInterfaceOptions & ~MAPI_UNICODE)
  644.     {
  645.         /*
  646.          *  Only UNICODE flag should be set for any of the objects that might
  647.          *  be returned from this object.
  648.          */
  649.         
  650.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  651.         goto out;
  652.     }
  653.     
  654.     if ( ulInterfaceOptions & MAPI_UNICODE )
  655.     {
  656.         hResult = ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  657.         DebugTraceArg( ABC_OpenProperty, "bad character width" );
  658.         goto out;
  659.         
  660.     }
  661.     
  662.     /*
  663.      *  Details for this directory entry
  664.      */
  665.     if ((ulPropTag == PR_DETAILS_TABLE) ||
  666.         (ulPropTag == PR_BUTTON_PRESS) ||
  667.         (ulPropTag == PR_CONTAINER_CONTENTS) ||
  668.         (ulPropTag == PR_CONTAINER_HIERARCHY) ||
  669.         (ulPropTag == PR_SEARCH))
  670.     {
  671.         /*
  672.          *  Check to see if they're expecting a table interface for all props but
  673.          *  PR_BUTTON_PRESS.
  674.          */
  675.         if ((ulPropTag != PR_BUTTON_PRESS) &&
  676.             (ulPropTag != PR_SEARCH) &&
  677.             memcmp(lpiid, &IID_IMAPITable, sizeof(IID)))
  678.         {
  679.             hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  680.             goto out;
  681.         }
  682.         switch (ulPropTag)
  683.         {
  684.         case PR_BUTTON_PRESS:
  685.             {
  686.                 /*
  687.                  *  Check to see if they're expecting a generic control interface
  688.                  */
  689.                 if (memcmp(lpiid, &IID_IMAPIControl, sizeof(IID)))
  690.                 {
  691.                     hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  692.                     goto out;
  693.                 }
  694.                 hResult = HrNewABCButton(lpABC,
  695.                     ulInterfaceOptions,
  696.                     ulFlags,
  697.                     (LPMAPICONTROL FAR *) lppUnk);
  698.                 break;
  699.             }
  700.         case PR_DETAILS_TABLE:
  701.             {
  702.                 hResult = HrGetDetailsDialog(lpABC, (LPMAPITABLE *) lppUnk);
  703.                 break;
  704.             }
  705.         case PR_SEARCH:
  706.             {
  707.                 /*
  708.                  *  Check to see if they're expecting a generic control interface
  709.                  */
  710.                 if (memcmp(lpiid, &IID_IMAPIContainer, sizeof(IID)))
  711.                 {
  712.                     hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  713.                     goto out;
  714.                 }
  715.                 hResult = HrNewSearch((LPMAPICONTAINER *) lppUnk,
  716.                                         lpABC->lpABLogon,
  717.                                         lpiid,
  718.                                         lpABC->hLibrary,
  719.                                         lpABC->lpAllocBuff,
  720.                                         lpABC->lpAllocMore,
  721.                                         lpABC->lpFreeBuff,
  722.                                         lpABC->lpMalloc);
  723.                 break;
  724.             }
  725.         case PR_CONTAINER_CONTENTS:
  726.             {
  727.                 hResult = ABC_GetContentsTable(lpABC, 0, (LPMAPITABLE *) lppUnk);
  728.                 break;
  729.             }
  730.         case PR_CONTAINER_HIERARCHY:
  731.             {
  732.                 hResult = ABC_GetHierarchyTable(lpABC, 0, (LPMAPITABLE *) lppUnk);
  733.                 break;
  734.             }
  735.         default:
  736.             Assert(FALSE);
  737.             break;
  738.         }
  739.     } else
  740.     {
  741.         hResult = ResultFromScode(MAPI_E_NO_SUPPORT);
  742.     }
  743. out:
  744.     DebugTraceResult(ABC_OpenProperty, hResult);
  745.     return hResult;
  746. }
  747. /*************************************************************************
  748.  *
  749.  -  ABC_GetContentsTable
  750.  -
  751.  *
  752.  *  Retrieves the IMAPITable that has the contents of this container.
  753.  */
  754. STDMETHODIMP
  755. ABC_GetContentsTable(LPABCNT lpABC, ULONG ulFlags,
  756.     LPMAPITABLE * lppTable)
  757. {
  758.     HRESULT hResult;
  759.     /*
  760.      *  Validate parameters
  761.      */
  762.     ABC_ValidateObject(GetContentsTable, lpABC);
  763.     Validate_IMAPIContainer_GetContentsTable(lpABC, ulFlags, lppTable);
  764.     
  765.     /*
  766.      *  Certain flags are not supported
  767.      */
  768.     if (ulFlags & (MAPI_ASSOCIATED))
  769.     {
  770.         hResult = ResultFromScode(MAPI_E_NO_SUPPORT);
  771.         goto out;
  772.     }
  773.     
  774.     if ( ulFlags & MAPI_UNICODE )
  775.     {
  776.         DebugTraceArg( ABC_GetContentsTable, "Bad character width" );
  777.         hResult = ResultFromScode( MAPI_E_BAD_CHARWIDTH );
  778.         goto out;
  779.     }
  780.     /*
  781.      *  Create the new Contents table
  782.      */
  783.     hResult = HrNewIVTAbc(lppTable,
  784.                           lpABC->lpABLogon,
  785.                           (LPABCONT) lpABC,
  786.                           lpABC->hLibrary,
  787.                           lpABC->lpAllocBuff,
  788.                           lpABC->lpAllocMore,
  789.                           lpABC->lpFreeBuff,
  790.                           lpABC->lpMalloc);
  791. out:
  792.     DebugTraceResult(ABC_GetContentsTable, hResult);
  793.     return hResult;
  794. }
  795. /*
  796.  -  ABC_GetHierarchyTable
  797.  -
  798.  *
  799.  *  There is no hierarchy table associated with this object.
  800.  *
  801.  */
  802. STDMETHODIMP
  803. ABC_GetHierarchyTable(LPABCNT lpABC, ULONG ulFlags,
  804.     LPMAPITABLE * lppTable)
  805. {
  806.     HRESULT hResult;
  807.     /*
  808.      *  Check to see if it has a lpVtbl object member
  809.      */
  810.     if (IsBadReadPtr(lpABC, offsetof(ABCNT, lpVtbl)+sizeof(ABC_Vtbl *)))
  811.     {
  812.         /*
  813.          *  Not large enough
  814.          */
  815.         hResult = MakeResult(E_INVALIDARG);
  816.         DebugTraceResult(ABC_HierarchyTable, hResult);
  817.         return hResult;
  818.     }
  819.     /*
  820.      *  Check to see that the Vtbl is large enough to include this method
  821.      */
  822.     if (IsBadReadPtr(lpABC->lpVtbl,
  823.         offsetof(ABC_Vtbl, GetHierarchyTable)+sizeof(ABC_GetHierarchyTable_METHOD *)))
  824.     {
  825.         /*
  826.          *  Jump table not derived from IUnknown
  827.          */
  828.         hResult = MakeResult(E_INVALIDARG);
  829.         DebugTraceResult(ABC_HierarchyTable, hResult);
  830.         return hResult;
  831.     }
  832.     /*
  833.      *  Check to see if the method is the same
  834.      */
  835.     if (ABC_GetHierarchyTable != lpABC->lpVtbl->GetHierarchyTable)
  836.     {
  837.         /*
  838.          *  Wrong object - the object passed doesn't have this
  839.          *  method.
  840.          */
  841.         hResult = ResultFromScode(E_INVALIDARG);
  842.         DebugTraceResult(ABC_HierarchyTable, hResult);
  843.         return hResult;
  844.     }
  845.     Validate_IMAPIContainer_GetHierarchyTable(lpABC, ulFlags, lppTable);
  846.     
  847.     /*
  848.      *  We don't support this method on this object
  849.      */
  850.     hResult = ResultFromScode(MAPI_E_NO_SUPPORT);
  851.     DebugTraceResult(ABC_GetHierarchyTable, hResult);
  852.     return hResult;
  853. }
  854. /*
  855.  -  HrGetDetailsDialog
  856.  -
  857.  *  Builds a display table for this directory.
  858.  */
  859. HRESULT
  860. HrGetDetailsDialog(LPABCNT lpABC, LPMAPITABLE * lppDetailsTable)
  861. {
  862.     HRESULT hResult;
  863.     if (!lpABC->lpTDatDetails)
  864.     {
  865.         /* Create a display table */
  866.         hResult = BuildDisplayTable(
  867.             lpABC->lpAllocBuff,
  868.             lpABC->lpAllocMore,
  869.             lpABC->lpFreeBuff,
  870.             lpABC->lpMalloc,
  871.             lpABC->hLibrary,
  872.             sizeof(rgdtpageDir) / sizeof(DTPAGE),
  873.             rgdtpageDir,
  874.             0,
  875.             lppDetailsTable,
  876.             &lpABC->lpTDatDetails);
  877.     } else
  878.     {
  879.         hResult = lpABC->lpTDatDetails->lpVtbl->HrGetView(
  880.             lpABC->lpTDatDetails,
  881.             NULL,
  882.             NULL,
  883.             0,
  884.             lppDetailsTable);
  885.     }
  886.     DebugTraceResult(HrGetDetailsDialog, hResult);
  887.     return hResult;
  888. }
  889. /*
  890.  *  Button object for this directory's details dialog
  891.  */
  892. /*
  893.  *  Declaration of IMAPIControl object implementation
  894.  */
  895. #undef  INTERFACE
  896. #define INTERFACE   struct _ABCBUTT
  897. #undef  MAPIMETHOD_
  898. #define MAPIMETHOD_(type,method)    MAPIMETHOD_DECLARE(type,method,ABCBUTT_)
  899.         MAPI_IUNKNOWN_METHODS(IMPL)
  900.         MAPI_IMAPICONTROL_METHODS(IMPL)
  901. #undef  MAPIMETHOD_
  902. #define MAPIMETHOD_(type,method)    MAPIMETHOD_TYPEDEF(type,method,ABCBUTT_)
  903.         MAPI_IUNKNOWN_METHODS(IMPL)
  904.         MAPI_IMAPICONTROL_METHODS(IMPL)
  905. #undef  MAPIMETHOD_
  906. #define MAPIMETHOD_(type,method)    STDMETHOD_(type,method)
  907. DECLARE_MAPI_INTERFACE(ABCBUTT_)
  908. {
  909.     MAPI_IUNKNOWN_METHODS(IMPL)
  910.     MAPI_IMAPICONTROL_METHODS(IMPL)
  911. };
  912. /*
  913.  *
  914.  *  Declaration of structure behind button
  915.  *
  916.  */
  917. typedef struct _ABCBUTT
  918. {
  919.     ABCBUTT_Vtbl FAR * lpVtbl;
  920.     SAB_IUnknown;
  921.     /*
  922.      *  My parent container object
  923.      */
  924.     LPABCNT     lpABC;
  925. } ABCBUTT, *LPABCBUTT;
  926. /*
  927.  *  Fill in the vtbl
  928.  */
  929. ABCBUTT_Vtbl vtblABCBUTT =
  930. {
  931.     ABCBUTT_QueryInterface,
  932.     (ABCBUTT_AddRef_METHOD *)       ROOT_AddRef,
  933.     ABCBUTT_Release,
  934.     (ABCBUTT_GetLastError_METHOD *) ROOT_GetLastError,
  935.     ABCBUTT_Activate,
  936.     ABCBUTT_GetState
  937. };
  938. #define ABCBUTT_ValidateObject(Method, pThis)       
  939. {                                                   
  940.     HRESULT hResult;                                
  941.     if (IsBadReadPtr(pThis, sizeof(ABCBUTT)))       
  942.     {                                               
  943.         hResult = ResultFromScode(E_INVALIDARG);    
  944.         DebugTraceResult(ABCBUTT##_##Method, hResult);  
  945.         return hResult;                             
  946.     }                                               
  947.                                                     
  948.     if (pThis->lpVtbl != &vtblABCBUTT)              
  949.     {                                               
  950.         hResult = ResultFromScode(E_INVALIDARG);    
  951.         DebugTraceResult(ABCBUTT##_##Method, hResult);  
  952.         return hResult;                             
  953.     }                                               
  954. }
  955. /*
  956.  -  HrNewABCButton
  957.  -
  958.  *  Creates the MAPIControl object that is the code behind the button
  959.  *  on the Sample AB's directory details.
  960.  */
  961. HRESULT
  962. HrNewABCButton( LPABCNT lpABC,
  963.                 ULONG ulInterfaceOptions,
  964.                 ULONG ulFlags,
  965.                 LPMAPICONTROL FAR * lppMAPICont)
  966. {
  967.     LPABCBUTT lpABCButt = NULL;
  968.     SCODE scode;
  969.     scode = lpABC->lpAllocBuff(sizeof(ABCBUTT),(LPVOID *) &lpABCButt);
  970.     if (FAILED(scode))
  971.     {
  972.         DebugTraceSc(HrNewABCButton, scode);
  973.         return ResultFromScode(scode);
  974.     }
  975.     lpABCButt->lpVtbl = &vtblABCBUTT;
  976.     lpABCButt->lcInit = 1;
  977.     lpABCButt->hResult = hrSuccess;
  978.     lpABCButt->idsLastError = 0;
  979.     lpABCButt->hLibrary = lpABC->hLibrary;
  980.     lpABCButt->lpAllocBuff = lpABC->lpAllocBuff;
  981.     lpABCButt->lpAllocMore = lpABC->lpAllocMore;
  982.     lpABCButt->lpFreeBuff = lpABC->lpFreeBuff;
  983.     lpABCButt->lpMalloc = lpABC->lpMalloc;
  984.     lpABCButt->lpABC = lpABC;
  985.     /*
  986.      *  I need my parent object to stay around while this object
  987.      *  does so that I can get to it in my Activate() method.
  988.      *  To do this just AddRef() it.
  989.      */
  990.     lpABC->lpVtbl->AddRef(lpABC);
  991.     InitializeCriticalSection(&lpABCButt->cs);
  992.     
  993.     *lppMAPICont = (LPMAPICONTROL) lpABCButt;
  994.     return hrSuccess;
  995. }
  996. /*************************************************************************
  997.  *
  998.  *
  999.  -  ABCBUTT_QueryInterface
  1000.  -
  1001.  *
  1002.  *  Allows QI'ing to IUnknown and IMAPIControl.
  1003.  *
  1004.  */
  1005. STDMETHODIMP
  1006. ABCBUTT_QueryInterface( LPABCBUTT lpABCButt,
  1007.                         REFIID lpiid,
  1008.                         LPVOID FAR * lppNewObj)
  1009. {
  1010.     HRESULT hResult = hrSuccess;
  1011.     /*  Minimally validate the lpABCButt parameter */
  1012.     ABCBUTT_ValidateObject(QueryInterface, lpABCButt);
  1013.     Validate_IUnknown_QueryInterface(lpABCButt, lpiid, lppNewObj);
  1014.     /*  See if the requested interface is one of ours */
  1015.     if (memcmp(lpiid, &IID_IUnknown, sizeof(IID)) &&
  1016.         memcmp(lpiid, &IID_IMAPIControl, sizeof(IID)))
  1017.     {
  1018.         *lppNewObj = NULL;      /* OLE requires zeroing [out] parameter */
  1019.         hResult = ResultFromScode(E_NOINTERFACE);
  1020.         goto out;
  1021.     }
  1022.     /*  We'll do this one. Bump the usage count and return a new pointer. */
  1023.     EnterCriticalSection(&lpABCButt->cs);
  1024.     ++lpABCButt->lcInit;
  1025.     LeaveCriticalSection(&lpABCButt->cs);
  1026.     
  1027.     *lppNewObj = lpABCButt;
  1028. out:
  1029.     DebugTraceResult(ABCBUTT_QueryInterface, hResult);
  1030.     return hResult;
  1031. }
  1032. /*
  1033.  -  ABCBUTT_Release
  1034.  -
  1035.  *  Releases and cleans up this object
  1036.  */
  1037. STDMETHODIMP_(ULONG)
  1038. ABCBUTT_Release(LPABCBUTT lpABCButt)
  1039. {
  1040.     long lcInit;
  1041.     /*  Minimally validate the lpABCButt parameter */
  1042.     if (IsBadReadPtr(lpABCButt, sizeof(ABCBUTT)))
  1043.     {
  1044.         return 1;
  1045.     }
  1046.     if (lpABCButt->lpVtbl != &vtblABCBUTT)
  1047.     {
  1048.         return 1;
  1049.     }
  1050.     Validate_IUnknown_Release(lpABCButt);
  1051.     EnterCriticalSection(&lpABCButt->cs);
  1052.     lcInit = --lpABCButt->lcInit;
  1053.     LeaveCriticalSection(&lpABCButt->cs);
  1054.     
  1055.     if (lcInit == 0)
  1056.     {
  1057.         /*
  1058.          *  Release my parent
  1059.          */
  1060.         lpABCButt->lpABC->lpVtbl->Release(lpABCButt->lpABC);
  1061.         /*
  1062.          *  Destroy the critical section for this object
  1063.          */
  1064.         DeleteCriticalSection(&lpABCButt->cs);
  1065.         /*
  1066.          *  Set the Jump table to NULL.  This way the client will find out
  1067.          *  real fast if it's calling a method on a released object.  That is,
  1068.          *  the client will crash.  Hopefully, this will happen during the
  1069.          *  development stage of the client.
  1070.          */
  1071.         lpABCButt->lpVtbl = NULL;
  1072.         /*
  1073.          *  Free the object
  1074.          */
  1075.         lpABCButt->lpFreeBuff(lpABCButt);
  1076.         return 0;
  1077.     }
  1078.     return lcInit;
  1079. }
  1080. /*
  1081.  -  ABCBUTT_Activate
  1082.  -
  1083.  *
  1084.  *  Activates this control.  In this case, it brings up the common file browsing
  1085.  *  dialog and allows the user to pick a different .SAB file.
  1086.  *
  1087.  *  Note that if all is successful it sends a display table notification.  The UI
  1088.  *  will respond to this by updating the particular control that was said to have
  1089.  *  changed in the notification.
  1090.  */
  1091. STDMETHODIMP
  1092. ABCBUTT_Activate(LPABCBUTT lpABCButt, ULONG ulFlags,
  1093.     ULONG ulUIParam)
  1094. {
  1095.     HRESULT hResult = hrSuccess;
  1096.     OPENFILENAME openfilename;
  1097.     char szFileName[MAX_PATH];
  1098.     char szDirName[MAX_PATH];
  1099.     SPropValue sProp;
  1100.     LPSPropValue lpspv = NULL;
  1101.     ULONG ulCount, ich;
  1102.     /*  Minimally validate the lpABCButt parameter */
  1103.     ABCBUTT_ValidateObject(Activate, lpABCButt);
  1104.     Validate_IMAPIControl_Activate(lpABCButt, ulFlags, ulUIParam);
  1105.     
  1106.     if (ulFlags)
  1107.     {
  1108.         /*
  1109.          *  No flags defined for this method
  1110.          */
  1111.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  1112.         goto out;
  1113.     }
  1114.     
  1115.     /*
  1116.      *  First, get the old SAB file name so that it shows up in the
  1117.      *  choose file dialog
  1118.      */
  1119.     hResult = lpABCButt->lpABC->lpPropData->lpVtbl->GetProps(
  1120.         lpABCButt->lpABC->lpPropData,
  1121.         &tagaSAB_FILE,
  1122.         0,              /* ansi */
  1123.         &ulCount,
  1124.         &lpspv);
  1125.     if (HR_FAILED(hResult))
  1126.     {
  1127.         goto out;
  1128.     }
  1129.     if (lpspv->ulPropTag != PR_SAB_FILE_TEMP)
  1130.     {
  1131.         /*
  1132.          *  Property wasn't there...
  1133.          */
  1134.         hResult = ResultFromScode(MAPI_E_CORRUPT_DATA);
  1135.         goto out;
  1136.     }
  1137.     lstrcpyA(szFileName, lpspv->Value.lpszA);
  1138.     szDirName[0] = '';
  1139.     /* get the path name */
  1140.     for (ich = lstrlenA(lpspv->Value.lpszA) - 1; ich > 0; ich--)
  1141.     {
  1142.         if (lpspv->Value.lpszA[ich] == '\')
  1143.         {
  1144.             lpspv->Value.lpszA[ich] = '';
  1145.             break;
  1146.         }
  1147.         else if (lpspv->Value.lpszA[ich] == ':')
  1148.         {
  1149.             lpspv->Value.lpszA[ich + 1] = '';
  1150.             break;
  1151.         }
  1152.     }
  1153.     lstrcpyA(szDirName, lpspv->Value.lpszA);
  1154.     /*
  1155.      *  Get the user to select one
  1156.      */
  1157.     openfilename.lStructSize = sizeof(OPENFILENAME);
  1158.     openfilename.hwndOwner = (HWND) ulUIParam;
  1159.     openfilename.hInstance = 0; /* Ignored */
  1160.     openfilename.lpstrFilter = "Sample AB files*.sab";
  1161.     openfilename.lpstrCustomFilter = NULL;
  1162.     openfilename.nMaxCustFilter = 0;
  1163.     openfilename.nFilterIndex = 0;
  1164.     openfilename.lpstrFile = szFileName;
  1165.     openfilename.nMaxFile = MAX_PATH;
  1166.     openfilename.lpstrFileTitle = NULL;
  1167.     openfilename.nMaxFileTitle = 0;
  1168.     openfilename.lpstrInitialDir = szDirName;
  1169.     openfilename.lpstrTitle = "Sample Address Book";
  1170.     openfilename.Flags = OFN_FILEMUSTEXIST |
  1171.         OFN_HIDEREADONLY |
  1172.         OFN_NOCHANGEDIR;
  1173.     openfilename.nFileOffset = 0;
  1174.     openfilename.nFileExtension = 0;
  1175.     openfilename.lpstrDefExt = "sab";
  1176.     openfilename.lCustData = 0;
  1177.     openfilename.lpfnHook = NULL;
  1178.     openfilename.lpTemplateName = NULL;
  1179.     /*
  1180.      *  Call up the common dialog
  1181.      */
  1182.     if (!GetOpenFileName(&openfilename))
  1183.     {
  1184.         hResult = hrSuccess;
  1185.         goto out;
  1186.     }
  1187.     /*
  1188.      *  Save SAB FileName into the container object
  1189.      */
  1190.     sProp.ulPropTag = PR_SAB_FILE_TEMP;
  1191.     sProp.Value.lpszA = szFileName;
  1192.     hResult = lpABCButt->lpABC->lpPropData->lpVtbl->SetProps(
  1193.         lpABCButt->lpABC->lpPropData,
  1194.         1,
  1195.         &sProp,
  1196.         NULL);
  1197.     if (HR_FAILED(hResult))
  1198.     {
  1199.         goto out;
  1200.     }
  1201.     /*
  1202.      *  Notify the details table so that everyone with a view open
  1203.      *  will get notified
  1204.      */
  1205.     if (lpABCButt->lpABC->lpTDatDetails)
  1206.     {
  1207.         sProp.ulPropTag = PR_CONTROL_ID;
  1208.         sProp.Value.bin.lpb = (LPBYTE) &notifdata;
  1209.         sProp.Value.bin.cb = sizeof(NOTIFDATA);
  1210.         hResult = lpABCButt->lpABC->lpTDatDetails->lpVtbl->HrNotify(
  1211.             lpABCButt->lpABC->lpTDatDetails,
  1212.             0,
  1213.             1,
  1214.             &sProp);
  1215.     }
  1216. out:
  1217.     lpABCButt->lpFreeBuff(lpspv);
  1218.     DebugTraceResult(ABCBUTT_Activate, hResult);
  1219.     return hResult;
  1220. }
  1221. /*
  1222.  -  ABCBUTT_GetState
  1223.  -
  1224.  *  Says whether this control should appear enabled or not at this time.
  1225.  *
  1226.  */
  1227. STDMETHODIMP
  1228. ABCBUTT_GetState(LPABCBUTT lpABCButt, ULONG ulFlags,
  1229.     ULONG * lpulState)
  1230. {
  1231.     HRESULT hResult = hrSuccess;
  1232.     /*  Minimally validate the lpABCButt parameter */
  1233.     ABCBUTT_ValidateObject(GetStatus, lpABCButt);
  1234.     Validate_IMAPIControl_GetState(lpABCButt, ulFlags, lpulState);
  1235.     
  1236.     
  1237.     /*
  1238.      *  Means that at this time this button should appear enabled.
  1239.      */
  1240.     *lpulState = MAPI_ENABLED;
  1241.     DebugTraceResult(ABCBUTT_GetState, hResult);
  1242.     return hResult;
  1243. }