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 / flatfile.ab / abcont.c next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  37.8 KB  |  1,490 lines

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