home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / trialva / ibmcppw / sdk / mapi / win16 / dev / sample.ab / abcont.c next >
Encoding:
C/C++ Source or Header  |  1995-07-11  |  41.1 KB  |  1,680 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.     if (IsBadReadPtr(lpABC, sizeof(ABCNT)))
  551.     {
  552.         /*
  553.          *  No jump table found
  554.          */
  555.         return 1;
  556.     }
  557.  
  558.     /*
  559.      *  Check to see that it's the correct jump table
  560.      */
  561.     if (lpABC->lpVtbl != &vtblABC)
  562.     {
  563.         /*
  564.          *  Not my jump table
  565.          */
  566.         return 1;
  567.     }
  568.  
  569.     EnterCriticalSection(&lpABC->cs);
  570.     lcInit = --lpABC->lcInit;
  571.     LeaveCriticalSection(&lpABC->cs);
  572.  
  573.     if (lcInit == 0)
  574.     {
  575.  
  576.         /*
  577.          *  Get rid of the lpPropData
  578.          */
  579.         if (lpABC->lpPropData)
  580.             lpABC->lpPropData->lpVtbl->Release(lpABC->lpPropData);
  581.  
  582.         /*
  583.          *  Get rid of the details table
  584.          */
  585.         if (lpABC->lpTDatDetails)
  586.             lpABC->lpTDatDetails->lpVtbl->Release(lpABC->lpTDatDetails);
  587.  
  588.         /*  
  589.          *  Release our reference to the ABLogon object.
  590.          */
  591.         if (lpABC->lpABLogon)
  592.         {
  593.             lpABC->lpABLogon->lpVtbl->Release(lpABC->lpABLogon);
  594.             lpABC->lpABLogon = NULL;
  595.         }
  596.  
  597.         /*
  598.          *  Destroy the critical section for this object
  599.          */
  600.  
  601.         DeleteCriticalSection(&lpABC->cs);
  602.  
  603.         /*
  604.          *  Set the Jump table to NULL.  This way the client will find out
  605.          *  real fast if it's calling a method on a released object.  That is,
  606.          *  the client will crash.  Hopefully, this will happen during the
  607.          *  development stage of the client.
  608.          */
  609.         lpABC->lpVtbl = NULL;
  610.  
  611.         /*
  612.          *  Need to free the object
  613.          */
  614.  
  615.         lpABC->lpFreeBuff(lpABC);
  616.         return 0;
  617.     }
  618.  
  619.     return lpABC->lcInit;
  620.  
  621. }
  622.  
  623.  
  624. /*
  625.  -  ABC_SaveChanges
  626.  -
  627.  *  This is used to save changes associated with the search dialog
  628.  *  in order to get the advanced search restriction and to save changes
  629.  *  associated with the container details dialog.
  630.  *
  631.  */
  632.  
  633. SPropTagArray tagaSAB_FILE =
  634. {
  635.     1,
  636.     {
  637.         PR_SAB_FILE_TEMP
  638.     }
  639. };
  640.  
  641. STDMETHODIMP
  642. ABC_SaveChanges(LPABCNT lpABC, ULONG ulFlags)
  643. {
  644.     HRESULT hResult = hrSuccess;
  645.     ULONG ulCount;
  646.     LPSPropValue lpspv = NULL;
  647.     ULONG FAR *rgulAccess = NULL;
  648.     ULONG ulAccess = IPROP_CLEAN | IPROP_READWRITE; 
  649.     LPSPropTagArray ptagaSAB_FILE = (LPSPropTagArray) &tagaSAB_FILE;
  650.     LPPROPDATA lpPropData = (LPPROPDATA) lpABC->lpPropData;
  651.  
  652.     /*
  653.      *  Check to see if it has a jump table
  654.      */
  655.     if (IsBadReadPtr(lpABC, sizeof(ABCNT)))
  656.     {
  657.         /*
  658.          *  No jump table found
  659.          */
  660.         hResult = ResultFromScode(E_INVALIDARG);
  661.         return hResult;
  662.     }
  663.  
  664.     /*
  665.      *  Check to see that it's the correct jump table
  666.      */
  667.     if (lpABC->lpVtbl != &vtblABC)
  668.     {
  669.         /*
  670.          *  Not my jump table
  671.          */
  672.         hResult = ResultFromScode(E_INVALIDARG);
  673.         return hResult;
  674.     }
  675.  
  676.  
  677.     EnterCriticalSection(&lpABC->cs);
  678.  
  679.     /*
  680.      *  Check to see if anyone has dirtied the PR_SAB_FILE_TEMP
  681.      */
  682.     (void) lpPropData->lpVtbl->HrGetPropAccess(lpPropData,
  683.                                         &ptagaSAB_FILE,
  684.                                         &rgulAccess);
  685.  
  686.     if (!rgulAccess || !((*rgulAccess) & IPROP_DIRTY))
  687.     {
  688.         /*
  689.          *  No, nothing to update then head on out
  690.          */
  691.  
  692.         goto ret;
  693.     }
  694.  
  695.     /*
  696.      *  Set back to being clean
  697.      */
  698.     (void )lpPropData->lpVtbl->HrSetPropAccess(lpPropData,
  699.                                         ptagaSAB_FILE,
  700.                                         &ulAccess);
  701.  
  702.     /*
  703.      * Get the temporary sab file name
  704.      */
  705.     hResult = lpPropData->lpVtbl->GetProps(
  706.         lpPropData,
  707.         &tagaSAB_FILE,
  708.         0,      /* ansi */
  709.         &ulCount,
  710.         &lpspv);
  711.     if (HR_FAILED(hResult))
  712.     {
  713.         goto ret;
  714.     }
  715.  
  716.     if (lpspv->ulPropTag != PR_SAB_FILE_TEMP)
  717.     {
  718.         /*
  719.          *  There's no reason this property shouldn't be there.
  720.          */
  721.         hResult = ResultFromScode(MAPI_E_CORRUPT_DATA);
  722.         goto ret;
  723.     }
  724.  
  725.     /*
  726.      *  Save the new name back into the object as PR_SAB_FILE
  727.      */
  728.     lpspv->ulPropTag = PR_SAB_FILE;
  729.     
  730.     hResult = lpPropData->lpVtbl->SetProps(
  731.             lpPropData,
  732.             1,
  733.             lpspv, NULL);
  734.  
  735.     if (HR_FAILED(hResult))
  736.     {
  737.         /*
  738.          *  Do nothing...  So I couldn't save it away this time...
  739.          */
  740.         hResult = hrSuccess;
  741.         goto ret;
  742.     }
  743.  
  744.     /*
  745.      *  Update every other object that needs this new information
  746.      */
  747.     hResult = HrReplaceCurrentFileName(lpABC->lpABLogon, lpspv->Value.lpszA);
  748.  
  749.  
  750. ret:
  751.  
  752.     LeaveCriticalSection(&lpABC->cs);
  753.  
  754.     lpABC->lpFreeBuff(lpspv);
  755.     lpABC->lpFreeBuff(rgulAccess);
  756.     DebugTraceResult(ABC_SaveChanges, hResult);
  757.     return hResult;
  758. }
  759.  
  760. /*************************************************************************
  761.  *
  762.  -  ABC_OpenProperty
  763.  -
  764.  *
  765.  *  This method allows the opening of the following object:
  766.  *
  767.  *  PR_BUTTON_PRESS  :-  Gets the MAPIControl object associated
  768.  *                       with the button on this container's details.
  769.  *  PR_DETAILS_TABLE :-  Gets the display table associated with
  770.  *                       the details for this container.
  771.  *  PR_SEARCH        :-  Gets the advanced search object associated with
  772.  *                       this container.
  773.  *  PR_CONTAINER_CONTENTS  :-  Same as GetContentsTable()
  774.  *  PR_CONTAINER_HIERARCHY :-  Same as GetHierarchyTable()
  775.  *
  776.  *
  777.  */
  778. STDMETHODIMP
  779. ABC_OpenProperty(LPABCNT lpABC,
  780.     ULONG ulPropTag,
  781.     LPCIID lpiid,
  782.     ULONG ulInterfaceOptions,
  783.     ULONG ulFlags,
  784.     LPUNKNOWN * lppUnk)
  785. {
  786.     HRESULT hResult;
  787.  
  788.     /*
  789.      *  Check to see if it's big enough to be this object
  790.      */
  791.     if (IsBadReadPtr(lpABC, sizeof(ABCNT)))
  792.     {
  793.         /*
  794.          *  Not big enough to be this object
  795.          */
  796.         hResult = ResultFromScode(E_INVALIDARG);
  797.         goto out;
  798.     }
  799.  
  800.     /*
  801.      *  Check to see that it's the correct vtbl
  802.      */
  803.     if (lpABC->lpVtbl != &vtblABC)
  804.     {
  805.         /*
  806.          *  Not my vtbl
  807.          */
  808.         hResult = ResultFromScode(E_INVALIDARG);
  809.         goto out;
  810.     }
  811.  
  812.  
  813.     if (IsBadWritePtr(lppUnk, sizeof(LPUNKNOWN)))
  814.     {
  815.         /*
  816.          *  Got to be able to return an object
  817.          */
  818.         hResult = ResultFromScode(E_INVALIDARG);
  819.         goto out;
  820.     }
  821.  
  822.     if (IsBadReadPtr(lpiid, (UINT) sizeof(IID)))
  823.     {
  824.         /*
  825.          *  An interface ID is required for this call.
  826.          */
  827.  
  828.         hResult = ResultFromScode(E_INVALIDARG);
  829.         goto out;
  830.     }
  831.  
  832.     /*
  833.      *  Make sure we are getting a valid PropTag.
  834.      */
  835.     if (FBadPropTag(ulPropTag))
  836.     {
  837.         hResult = ResultFromScode(E_INVALIDARG);
  838.         goto out;
  839.     }
  840.  
  841.     /*
  842.      *  check for unknown flags
  843.      */
  844.     if (ulFlags & ~(  MAPI_DEFERRED_ERRORS | STREAM_APPEND
  845.                     | MAPI_CREATE | MAPI_MODIFY))
  846.     {
  847.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  848.         goto out;
  849.     }
  850.  
  851.     /*
  852.      *  STREAM_APPEND is only valid on a stream interface.
  853.      */
  854.     if (   (ulFlags & STREAM_APPEND)
  855.         && memcmp(lpiid, &IID_IStream, sizeof(IID)) )
  856.     {
  857.         hResult = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  858.         goto out;
  859.     }
  860.  
  861.     /*
  862.      *  Check for flags we can't support
  863.      */
  864.  
  865.     if (ulFlags & (MAPI_CREATE|MAPI_MODIFY))
  866.     {
  867.         hResult = ResultFromScode(E_ACCESSDENIED);
  868.         goto out;
  869.     }
  870.         
  871.     if (ulInterfaceOptions & ~MAPI_UNICODE)
  872.     {
  873.         /*
  874.          *  Only UNICODE flag should be set for any of the objects that might
  875.          *  be returned from this object.
  876.          */
  877.         
  878.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  879.         goto out;
  880.     }
  881.     
  882.     if ( ulInterfaceOptions & MAPI_UNICODE )
  883.     {
  884.         hResult = ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  885.         DebugTraceArg( ABC_OpenProperty, "bad character width" );
  886.         goto out;
  887.         
  888.     }
  889.     
  890.  
  891.     /*
  892.      *  Details for this directory entry
  893.      */
  894.  
  895.     if ((ulPropTag == PR_DETAILS_TABLE) ||
  896.         (ulPropTag == PR_BUTTON_PRESS) ||
  897.         (ulPropTag == PR_CONTAINER_CONTENTS) ||
  898.         (ulPropTag == PR_CONTAINER_HIERARCHY) ||
  899.         (ulPropTag == PR_SEARCH))
  900.     {
  901.  
  902.         /*
  903.          *  Check to see if they're expecting a table interface for all props but
  904.          *  PR_BUTTON_PRESS.
  905.          */
  906.         if ((ulPropTag != PR_BUTTON_PRESS) &&
  907.             (ulPropTag != PR_SEARCH) &&
  908.             memcmp(lpiid, &IID_IMAPITable, sizeof(IID)))
  909.         {
  910.             hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  911.             goto out;
  912.         }
  913.  
  914.         switch (ulPropTag)
  915.         {
  916.  
  917.         case PR_BUTTON_PRESS:
  918.             {
  919.                 /*
  920.                  *  Check to see if they're expecting a generic control interface
  921.                  */
  922.                 if (memcmp(lpiid, &IID_IMAPIControl, sizeof(IID)))
  923.                 {
  924.                     hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  925.                     goto out;
  926.                 }
  927.  
  928.                 hResult = HrNewABCButton(lpABC,
  929.                     ulInterfaceOptions,
  930.                     ulFlags,
  931.                     (LPMAPICONTROL FAR *) lppUnk);
  932.  
  933.                 break;
  934.             }
  935.  
  936.         case PR_DETAILS_TABLE:
  937.             {
  938.                 hResult = HrGetDetailsDialog(lpABC, (LPMAPITABLE *) lppUnk);
  939.                 break;
  940.             }
  941.  
  942.         case PR_SEARCH:
  943.             {
  944.                 /*
  945.                  *  Check to see if they're expecting a generic control interface
  946.                  */
  947.                 if (memcmp(lpiid, &IID_IMAPIContainer, sizeof(IID)))
  948.                 {
  949.                     hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  950.                     goto out;
  951.                 }
  952.  
  953.                 hResult = HrNewSearch((LPMAPICONTAINER *) lppUnk,
  954.                                         lpABC->lpABLogon,
  955.                                         lpiid,
  956.                                         lpABC->hLibrary,
  957.                                         lpABC->lpAllocBuff,
  958.                                         lpABC->lpAllocMore,
  959.                                         lpABC->lpFreeBuff,
  960.                                         lpABC->lpMalloc);
  961.                 break;
  962.             }
  963.  
  964.         case PR_CONTAINER_CONTENTS:
  965.             {
  966.                 hResult = ABC_GetContentsTable(lpABC, 0, (LPMAPITABLE *) lppUnk);
  967.                 break;
  968.             }
  969.  
  970.         case PR_CONTAINER_HIERARCHY:
  971.             {
  972.                 hResult = ABC_GetHierarchyTable(lpABC, 0, (LPMAPITABLE *) lppUnk);
  973.                 break;
  974.             }
  975.  
  976.         default:
  977.             break;
  978.         }
  979.     } else
  980.     {
  981.  
  982.         hResult = ResultFromScode(MAPI_E_NO_SUPPORT);
  983.     }
  984.  
  985. out:
  986.  
  987.     DebugTraceResult(ABC_OpenProperty, hResult);
  988.     return hResult;
  989. }
  990.  
  991. /*************************************************************************
  992.  *
  993.  -  ABC_GetContentsTable
  994.  -
  995.  *
  996.  *  Retrieves the IMAPITable that has the contents of this container.
  997.  */
  998. STDMETHODIMP
  999. ABC_GetContentsTable(LPABCNT lpABC, ULONG ulFlags,
  1000.     LPMAPITABLE * lppTable)
  1001. {
  1002.  
  1003.     HRESULT hResult;
  1004.  
  1005.     /*
  1006.      *  Validate parameters
  1007.      */
  1008.  
  1009.     /*
  1010.      *  Check to see if it's large enough to be this object
  1011.      */
  1012.     if (IsBadReadPtr(lpABC, sizeof(ABCNT)))
  1013.     {
  1014.         /*
  1015.          *  Not large enough to be this object
  1016.          */
  1017.         hResult = ResultFromScode(E_INVALIDARG);
  1018.         goto out;
  1019.     }
  1020.  
  1021.     /*
  1022.      *  Check to see that it's the correct vtbl
  1023.      */
  1024.     if (lpABC->lpVtbl != &vtblABC)
  1025.     {
  1026.         /*
  1027.          *  Not my vtbl
  1028.          */
  1029.         hResult = ResultFromScode(E_INVALIDARG);
  1030.         goto out;
  1031.     }
  1032.  
  1033.     /*
  1034.      *  Check lppTable to validate its writability
  1035.      */
  1036.     if (IsBadWritePtr(lppTable, sizeof(LPMAPITABLE)))
  1037.     {
  1038.         hResult = ResultFromScode(E_INVALIDARG);
  1039.         goto out;
  1040.     }
  1041.  
  1042.     /*
  1043.      *  Check flags
  1044.      */
  1045.     if (ulFlags & ~(MAPI_UNICODE|MAPI_DEFERRED_ERRORS|MAPI_ASSOCIATED))
  1046.     {
  1047.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  1048.         goto out;
  1049.     }
  1050.  
  1051.     /*
  1052.      *  Certain flags are not supported
  1053.      */
  1054.     if (ulFlags & (MAPI_ASSOCIATED))
  1055.     {
  1056.         hResult = ResultFromScode(MAPI_E_NO_SUPPORT);
  1057.         goto out;
  1058.     }
  1059.     
  1060.     if ( ulFlags & MAPI_UNICODE )
  1061.     {
  1062.         DebugTraceArg( ABC_GetContentsTable, "Bad character width" );
  1063.         hResult = ResultFromScode( MAPI_E_BAD_CHARWIDTH );
  1064.         goto out;
  1065.     }
  1066.  
  1067.     /*
  1068.      *  Create the new Contents table
  1069.      */
  1070.     hResult = HrNewIVTAbc(lppTable,
  1071.                           lpABC->lpABLogon,
  1072.                           (LPABCONT) lpABC,
  1073.                           lpABC->hLibrary,
  1074.                           lpABC->lpAllocBuff,
  1075.                           lpABC->lpAllocMore,
  1076.                           lpABC->lpFreeBuff,
  1077.                           lpABC->lpMalloc);
  1078.  
  1079. out:
  1080.  
  1081.     DebugTraceResult(ABC_GetContentsTable, hResult);
  1082.     return hResult;
  1083. }
  1084.  
  1085. /*
  1086.  -  ABC_GetHierarchyTable
  1087.  -
  1088.  *
  1089.  *  There is no hierarchy table associated with this object.
  1090.  *
  1091.  */
  1092. STDMETHODIMP
  1093. ABC_GetHierarchyTable(LPABCNT lpABC, ULONG ulFlags,
  1094.     LPMAPITABLE * lppTable)
  1095. {
  1096.     HRESULT hResult;
  1097.  
  1098.     /*
  1099.      *  Check to see if it has a lpVtbl object member
  1100.      */
  1101.     if (IsBadReadPtr(lpABC, offsetof(ABCNT, lpVtbl)+sizeof(ABC_Vtbl *)))
  1102.     {
  1103.         /*
  1104.          *  Not large enough
  1105.          */
  1106.         hResult = MakeResult(E_INVALIDARG);
  1107.         DebugTraceResult(ABC_HierarchyTable, hResult);
  1108.         return hResult;
  1109.     }
  1110.  
  1111.     /*
  1112.      *  Check to see that the Vtbl is large enough to include this method
  1113.      */
  1114.     if (IsBadReadPtr(lpABC->lpVtbl,
  1115.         offsetof(ABC_Vtbl, GetHierarchyTable)+sizeof(ABC_GetHierarchyTable_METHOD *)))
  1116.     {
  1117.         /*
  1118.          *  Jump table not derived from IUnknown
  1119.          */
  1120.  
  1121.         hResult = MakeResult(E_INVALIDARG);
  1122.         DebugTraceResult(ABC_HierarchyTable, hResult);
  1123.         return hResult;
  1124.     }
  1125.  
  1126.     /*
  1127.      *  Check to see if the method is the same
  1128.      */
  1129.     if (ABC_GetHierarchyTable != lpABC->lpVtbl->GetHierarchyTable)
  1130.     {
  1131.         /*
  1132.          *  Wrong object - the object passed doesn't have this
  1133.          *  method.
  1134.          */
  1135.         hResult = ResultFromScode(E_INVALIDARG);
  1136.         DebugTraceResult(ABC_HierarchyTable, hResult);
  1137.         return hResult;
  1138.     }
  1139.  
  1140.     /*
  1141.      *  See if I can set the return variable
  1142.      */
  1143.     if (IsBadWritePtr(lppTable, sizeof(LPMAPITABLE)))
  1144.     {
  1145.         hResult = ResultFromScode(E_INVALIDARG);
  1146.         goto out;
  1147.     }
  1148.  
  1149.     /*
  1150.      *  Check flags:
  1151.      *    The only valid flags are CONVENIENT_DEPTH and MAPI_DEFERRED_ERRORS
  1152.      */
  1153.  
  1154.     if (ulFlags & ~(CONVENIENT_DEPTH | MAPI_DEFERRED_ERRORS))
  1155.     {
  1156.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  1157.         goto out;
  1158.     }
  1159.  
  1160.     /*
  1161.      *  We don't support this method on this object
  1162.      */
  1163.     hResult = ResultFromScode(MAPI_E_NO_SUPPORT);
  1164.  
  1165. out:
  1166.  
  1167.     DebugTraceResult(ABC_GetHierarchyTable, hResult);
  1168.     return hResult;
  1169. }
  1170.  
  1171. /*
  1172.  -  HrGetDetailsDialog
  1173.  -
  1174.  *  Builds a display table for this directory.
  1175.  */
  1176.  
  1177. HRESULT
  1178. HrGetDetailsDialog(LPABCNT lpABC, LPMAPITABLE * lppDetailsTable)
  1179. {
  1180.     HRESULT hResult;
  1181.  
  1182.     if (!lpABC->lpTDatDetails)
  1183.     {
  1184.  
  1185.         /* Create a display table */
  1186.         hResult = BuildDisplayTable(
  1187.             lpABC->lpAllocBuff,
  1188.             lpABC->lpAllocMore,
  1189.             lpABC->lpFreeBuff,
  1190.             lpABC->lpMalloc,
  1191.             lpABC->hLibrary,
  1192.             sizeof(rgdtpageDir) / sizeof(DTPAGE),
  1193.             rgdtpageDir,
  1194.             0,
  1195.             lppDetailsTable,
  1196.             &lpABC->lpTDatDetails);
  1197.     } else
  1198.     {
  1199.         hResult = lpABC->lpTDatDetails->lpVtbl->HrGetView(
  1200.             lpABC->lpTDatDetails,
  1201.             NULL,
  1202.             NULL,
  1203.             0,
  1204.             lppDetailsTable);
  1205.     }
  1206.  
  1207.     DebugTraceResult(HrGetDetailsDialog, hResult);
  1208.     return hResult;
  1209. }
  1210.  
  1211.  
  1212. /*
  1213.  *  Button object for this directory's details dialog
  1214.  */
  1215.  
  1216.  
  1217. /*
  1218.  *  Declaration of IMAPIControl object implementation
  1219.  */
  1220. #undef  INTERFACE
  1221. #define INTERFACE   struct _ABCBUTT
  1222.  
  1223. #undef  MAPIMETHOD_
  1224. #define MAPIMETHOD_(type,method)    MAPIMETHOD_DECLARE(type,method,ABCBUTT_)
  1225.         MAPI_IUNKNOWN_METHODS(IMPL)
  1226.         MAPI_IMAPICONTROL_METHODS(IMPL)
  1227.  
  1228. #undef  MAPIMETHOD_
  1229. #define MAPIMETHOD_(type,method)    MAPIMETHOD_TYPEDEF(type,method,ABCBUTT_)
  1230.         MAPI_IUNKNOWN_METHODS(IMPL)
  1231.         MAPI_IMAPICONTROL_METHODS(IMPL)
  1232.  
  1233. #undef  MAPIMETHOD_
  1234. #define MAPIMETHOD_(type,method)    STDMETHOD_(type,method)
  1235.  
  1236. DECLARE_MAPI_INTERFACE(ABCBUTT_)
  1237. {
  1238.     MAPI_IUNKNOWN_METHODS(IMPL)
  1239.     MAPI_IMAPICONTROL_METHODS(IMPL)
  1240. };
  1241.  
  1242. /*
  1243.  *
  1244.  *  Declaration of structure behind button
  1245.  *
  1246.  */
  1247. typedef struct _ABCBUTT
  1248. {
  1249.     ABCBUTT_Vtbl FAR * lpVtbl;
  1250.  
  1251.     SAB_IUnknown;
  1252.     /*
  1253.      *  My parent container object
  1254.      */
  1255.     LPABCNT     lpABC;
  1256.  
  1257. } ABCBUTT, *LPABCBUTT;
  1258.  
  1259.  
  1260. /*
  1261.  *  Fill in the vtbl
  1262.  */
  1263. ABCBUTT_Vtbl vtblABCBUTT =
  1264. {
  1265.     ABCBUTT_QueryInterface,
  1266.     (ABCBUTT_AddRef_METHOD *)       ROOT_AddRef,
  1267.     ABCBUTT_Release,
  1268.     (ABCBUTT_GetLastError_METHOD *) ROOT_GetLastError,
  1269.     ABCBUTT_Activate,
  1270.     ABCBUTT_GetState
  1271. };
  1272.  
  1273.  
  1274.  
  1275.  
  1276. /*
  1277.  -  HrNewABCButton
  1278.  -
  1279.  *  Creates the MAPIControl object that is the code behind the button
  1280.  *  on the Sample AB's directory details.
  1281.  */
  1282. HRESULT
  1283. HrNewABCButton( LPABCNT lpABC,
  1284.                 ULONG ulInterfaceOptions,
  1285.                 ULONG ulFlags,
  1286.                 LPMAPICONTROL FAR * lppMAPICont)
  1287. {
  1288.     LPABCBUTT lpABCButt = NULL;
  1289.     SCODE scode;
  1290.  
  1291.     scode = lpABC->lpAllocBuff(sizeof(ABCBUTT),(LPVOID *) &lpABCButt);
  1292.  
  1293.     if (FAILED(scode))
  1294.     {
  1295.         DebugTraceSc(HrNewABCButton, scode);
  1296.         return ResultFromScode(scode);
  1297.     }
  1298.  
  1299.     lpABCButt->lpVtbl = &vtblABCBUTT;
  1300.     lpABCButt->lcInit = 1;
  1301.     lpABCButt->hResult = hrSuccess;
  1302.     lpABCButt->idsLastError = 0;
  1303.  
  1304.     lpABCButt->hLibrary = lpABC->hLibrary;
  1305.     lpABCButt->lpAllocBuff = lpABC->lpAllocBuff;
  1306.     lpABCButt->lpAllocMore = lpABC->lpAllocMore;
  1307.     lpABCButt->lpFreeBuff = lpABC->lpFreeBuff;
  1308.     lpABCButt->lpMalloc = lpABC->lpMalloc;
  1309.     lpABCButt->lpABC = lpABC;
  1310.  
  1311.     /*
  1312.      *  I need my parent object to stay around while this object
  1313.      *  does so that I can get to it in my Activate() method.
  1314.      *  To do this just AddRef() it.
  1315.      */
  1316.     lpABC->lpVtbl->AddRef(lpABC);
  1317.  
  1318.     InitializeCriticalSection(&lpABCButt->cs);
  1319.     
  1320.     *lppMAPICont = (LPMAPICONTROL) lpABCButt;
  1321.  
  1322.     return hrSuccess;
  1323. }
  1324.  
  1325.  
  1326. /*************************************************************************
  1327.  *
  1328.  *
  1329.  -  ABCBUTT_QueryInterface
  1330.  -
  1331.  *
  1332.  *  Allows QI'ing to IUnknown and IMAPIControl.
  1333.  *
  1334.  */
  1335. STDMETHODIMP
  1336. ABCBUTT_QueryInterface( LPABCBUTT lpABCButt,
  1337.                         REFIID lpiid,
  1338.                         LPVOID FAR * lppNewObj)
  1339. {
  1340.  
  1341.     HRESULT hResult = hrSuccess;
  1342.  
  1343.     /*  Minimally validate the lpABCButt parameter */
  1344.  
  1345.     if (IsBadReadPtr(lpABCButt, sizeof(ABCBUTT)))
  1346.     {
  1347.         hResult = ResultFromScode(E_INVALIDARG);
  1348.         goto out;
  1349.     }
  1350.  
  1351.     if (lpABCButt->lpVtbl != &vtblABCBUTT)
  1352.     {
  1353.         hResult = ResultFromScode(E_INVALIDARG);
  1354.         goto out;
  1355.     }
  1356.     
  1357.     /*  Check the other parameters */
  1358.  
  1359.     if (!lpiid || IsBadReadPtr(lpiid, (UINT) sizeof(IID)))
  1360.     {
  1361.         hResult = ResultFromScode(E_INVALIDARG);
  1362.         goto out;
  1363.     }
  1364.         
  1365.     if (IsBadWritePtr(lppNewObj, (UINT) sizeof(LPVOID)))
  1366.     {
  1367.         hResult = ResultFromScode(E_INVALIDARG);
  1368.         goto out;
  1369.     }
  1370.  
  1371.     /*  See if the requested interface is one of ours */
  1372.  
  1373.     if (memcmp(lpiid, &IID_IUnknown, sizeof(IID)) &&
  1374.         memcmp(lpiid, &IID_IMAPIControl, sizeof(IID)))
  1375.     {
  1376.         *lppNewObj = NULL;      /* OLE requires zeroing [out] parameter */
  1377.         hResult = ResultFromScode(E_NOINTERFACE);
  1378.         goto out;
  1379.     }
  1380.  
  1381.     /*  We'll do this one. Bump the usage count and return a new pointer. */
  1382.  
  1383.     EnterCriticalSection(&lpABCButt->cs);
  1384.     ++lpABCButt->lcInit;
  1385.     LeaveCriticalSection(&lpABCButt->cs);
  1386.     
  1387.     *lppNewObj = lpABCButt;
  1388.  
  1389. out:
  1390.  
  1391.     DebugTraceResult(ABCBUTT_QueryInterface, hResult);
  1392.     return hResult;
  1393. }
  1394.  
  1395. /*
  1396.  -  ABCBUTT_Release
  1397.  -
  1398.  *  Releases and cleans up this object
  1399.  */
  1400. STDMETHODIMP_(ULONG)
  1401. ABCBUTT_Release(LPABCBUTT lpABCButt)
  1402. {
  1403.     long lcInit;
  1404.  
  1405.     /*  Minimally validate the lpABCButt parameter */
  1406.  
  1407.     if (IsBadReadPtr(lpABCButt, sizeof(ABCBUTT)))
  1408.     {
  1409.         return 1;
  1410.     }
  1411.  
  1412.     if (lpABCButt->lpVtbl != &vtblABCBUTT)
  1413.     {
  1414.         return 1;
  1415.     }
  1416.  
  1417.     EnterCriticalSection(&lpABCButt->cs);
  1418.     lcInit = --lpABCButt->lcInit;
  1419.     LeaveCriticalSection(&lpABCButt->cs);
  1420.     
  1421.     if (lcInit == 0)
  1422.     {
  1423.  
  1424.         /*
  1425.          *  Release my parent
  1426.          */
  1427.         lpABCButt->lpABC->lpVtbl->Release(lpABCButt->lpABC);
  1428.  
  1429.         /*
  1430.          *  Destroy the critical section for this object
  1431.          */
  1432.  
  1433.         DeleteCriticalSection(&lpABCButt->cs);
  1434.  
  1435.         /*
  1436.          *  Set the Jump table to NULL.  This way the client will find out
  1437.          *  real fast if it's calling a method on a released object.  That is,
  1438.          *  the client will crash.  Hopefully, this will happen during the
  1439.          *  development stage of the client.
  1440.          */
  1441.         lpABCButt->lpVtbl = NULL;
  1442.  
  1443.         /*
  1444.          *  Free the object
  1445.          */
  1446.  
  1447.         lpABCButt->lpFreeBuff(lpABCButt);
  1448.         return 0;
  1449.     }
  1450.  
  1451.     return lcInit;
  1452.  
  1453. }
  1454.  
  1455.  
  1456. /*
  1457.  -  ABCBUTT_Activate
  1458.  -
  1459.  *
  1460.  *  Activates this control.  In this case, it brings up the common file browsing
  1461.  *  dialog and allows the user to pick a different .SAB file.
  1462.  *
  1463.  *  Note that if all is successful it sends a display table notification.  The UI
  1464.  *  will respond to this by updating the particular control that was said to have
  1465.  *  changed in the notification.
  1466.  */
  1467. STDMETHODIMP
  1468. ABCBUTT_Activate(LPABCBUTT lpABCButt, ULONG ulFlags,
  1469.     ULONG ulUIParam)
  1470. {
  1471.     HRESULT hResult = hrSuccess;
  1472.     OPENFILENAME openfilename;
  1473.     char szFileName[MAX_PATH];
  1474.     char szDirName[MAX_PATH];
  1475.     SPropValue sProp;
  1476.     LPSPropValue lpspv = NULL;
  1477.     ULONG ulCount, ich;
  1478.  
  1479.  
  1480.     /*  Minimally validate the lpABCButt parameter */
  1481.  
  1482.     if (IsBadReadPtr(lpABCButt, sizeof(ABCBUTT)))
  1483.     {
  1484.         hResult = ResultFromScode(E_INVALIDARG);
  1485.         goto out;
  1486.     }
  1487.  
  1488.     if (lpABCButt->lpVtbl != &vtblABCBUTT)
  1489.     {
  1490.         hResult = ResultFromScode(E_INVALIDARG);
  1491.         goto out;
  1492.     }
  1493.  
  1494.  
  1495.     if (ulFlags)
  1496.     {
  1497.         /*
  1498.          *  No flags defined for this method
  1499.          */
  1500.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  1501.         goto out;
  1502.     }
  1503.  
  1504.     
  1505.     /*
  1506.      *  First, get the old SAB file name so that it shows up in the
  1507.      *  choose file dialog
  1508.      */
  1509.  
  1510.     hResult = lpABCButt->lpABC->lpPropData->lpVtbl->GetProps(
  1511.         lpABCButt->lpABC->lpPropData,
  1512.         &tagaSAB_FILE,
  1513.         0,              /* ansi */
  1514.         &ulCount,
  1515.         &lpspv);
  1516.     if (HR_FAILED(hResult))
  1517.     {
  1518.         goto out;
  1519.     }
  1520.  
  1521.     if (lpspv->ulPropTag != PR_SAB_FILE_TEMP)
  1522.     {
  1523.         /*
  1524.          *  Property wasn't there...
  1525.          */
  1526.         hResult = ResultFromScode(MAPI_E_CORRUPT_DATA);
  1527.  
  1528.         goto out;
  1529.     }
  1530.  
  1531.     lstrcpyA(szFileName, lpspv->Value.lpszA);
  1532.  
  1533.     szDirName[0] = '\0';
  1534.  
  1535.  
  1536.     /* get the path name */
  1537.     for (ich = lstrlenA(lpspv->Value.lpszA) - 1; ich >= 0; ich--)
  1538.     {
  1539.         if (lpspv->Value.lpszA[ich] == '\\')
  1540.         {
  1541.             lpspv->Value.lpszA[ich] = '\0';
  1542.             break;
  1543.         }
  1544.         else if (lpspv->Value.lpszA[ich] == ':')
  1545.         {
  1546.             lpspv->Value.lpszA[ich + 1] = '\0';
  1547.             break;
  1548.         }
  1549.     }
  1550.  
  1551.     lstrcpyA(szDirName, lpspv->Value.lpszA);
  1552.  
  1553.     /*
  1554.      *  Get the user to select one
  1555.      */
  1556.     openfilename.lStructSize = sizeof(OPENFILENAME);
  1557.     openfilename.hwndOwner = (HWND) ulUIParam;
  1558.     openfilename.hInstance = 0; /* Ignored */
  1559.     openfilename.lpstrFilter = "Sample AB files\0*.sab\0\0";
  1560.     openfilename.lpstrCustomFilter = NULL;
  1561.     openfilename.nMaxCustFilter = 0;
  1562.     openfilename.nFilterIndex = 0;
  1563.     openfilename.lpstrFile = szFileName;
  1564.     openfilename.nMaxFile = MAX_PATH;
  1565.     openfilename.lpstrFileTitle = NULL;
  1566.     openfilename.nMaxFileTitle = 0;
  1567.     openfilename.lpstrInitialDir = szDirName;
  1568.     openfilename.lpstrTitle = "Sample Address Book";
  1569.     openfilename.Flags = OFN_FILEMUSTEXIST |
  1570.         OFN_HIDEREADONLY |
  1571.         OFN_NOCHANGEDIR;
  1572.     openfilename.nFileOffset = 0;
  1573.     openfilename.nFileExtension = 0;
  1574.     openfilename.lpstrDefExt = "sab";
  1575.     openfilename.lCustData = 0;
  1576.     openfilename.lpfnHook = NULL;
  1577.     openfilename.lpTemplateName = NULL;
  1578.  
  1579.     /*
  1580.      *  Call up the common dialog
  1581.      */
  1582.     if (!GetOpenFileName(&openfilename))
  1583.     {
  1584.         hResult = hrSuccess;
  1585.         goto out;
  1586.     }
  1587.  
  1588.     /*
  1589.      *  Save SAB FileName into the container object
  1590.      */
  1591.  
  1592.     sProp.ulPropTag = PR_SAB_FILE_TEMP;
  1593.     sProp.Value.lpszA = szFileName;
  1594.  
  1595.     hResult = lpABCButt->lpABC->lpPropData->lpVtbl->SetProps(
  1596.         lpABCButt->lpABC->lpPropData,
  1597.         1,
  1598.         &sProp,
  1599.         NULL);
  1600.     if (HR_FAILED(hResult))
  1601.     {
  1602.         goto out;
  1603.     }
  1604.  
  1605.     /*
  1606.      *  Notify the details table so that everyone with a view open
  1607.      *  will get notified
  1608.      */
  1609.     if (lpABCButt->lpABC->lpTDatDetails)
  1610.     {
  1611.         sProp.ulPropTag = PR_CONTROL_ID;
  1612.         sProp.Value.bin.lpb = (LPBYTE) ¬ifdata;
  1613.         sProp.Value.bin.cb = sizeof(NOTIFDATA);
  1614.  
  1615.         hResult = lpABCButt->lpABC->lpTDatDetails->lpVtbl->HrNotify(
  1616.             lpABCButt->lpABC->lpTDatDetails,
  1617.             0,
  1618.             1,
  1619.             &sProp);
  1620.     }
  1621.  
  1622. out:
  1623.     lpABCButt->lpFreeBuff(lpspv);
  1624.     DebugTraceResult(ABCBUTT_Activate, hResult);
  1625.     return hResult;
  1626. }
  1627.  
  1628. /*
  1629.  -  ABCBUTT_GetState
  1630.  -
  1631.  *  Says whether this control should appear enabled or not at this time.
  1632.  *
  1633.  */
  1634. STDMETHODIMP
  1635. ABCBUTT_GetState(LPABCBUTT lpABCButt, ULONG ulFlags,
  1636.     ULONG * lpulState)
  1637. {
  1638.  
  1639.     HRESULT hResult = hrSuccess;
  1640.  
  1641.     /*  Minimally validate the lpABCButt parameter */
  1642.  
  1643.     if (IsBadReadPtr(lpABCButt, sizeof(ABCBUTT)))
  1644.     {
  1645.         hResult = ResultFromScode(E_INVALIDARG);
  1646.         goto out;
  1647.     }
  1648.  
  1649.     if (lpABCButt->lpVtbl != &vtblABCBUTT)
  1650.     {
  1651.         hResult = ResultFromScode(E_INVALIDARG);
  1652.         goto out;
  1653.     }
  1654.  
  1655.     if (IsBadWritePtr(lpulState, sizeof(ULONG)))
  1656.     {
  1657.         hResult = ResultFromScode(E_INVALIDARG);
  1658.         goto out;
  1659.     }
  1660.  
  1661.     if (ulFlags)
  1662.     {
  1663.         /*
  1664.          *  No flags defined for this method
  1665.          */
  1666.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  1667.         goto out;
  1668.     }
  1669.  
  1670.     /*
  1671.      *  Means that at this time this button should appear enabled.
  1672.      */
  1673.     *lpulState = MAPI_ENABLED;
  1674.  
  1675. out:
  1676.     DebugTraceResult(ABCBUTT_GetState, hResult);
  1677.     return hResult;
  1678. }
  1679.  
  1680.