home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / trialva / ibmcppw / sdk / mapi / win16 / dev / sample.ab / abuser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-11  |  41.1 KB  |  1,513 lines

  1. /***********************************************************************
  2.  *
  3.  *  ABUSER.C
  4.  *
  5.  *  Sample AB Mail User object
  6.  *  This file contains the code for implementing the Sample AB
  7.  *  Mail user.
  8.  *
  9.  *  The mail user has a read-only interface.  Hence a few of the methods
  10.  *  will always return E_ACCESSDENIED.
  11.  *
  12.  *  Typically it would be in this module (particularly HrNewABUser) that
  13.  *  your provider would validate the existance of the entry associated
  14.  *  with a particular entryid.  The Sample Address Book doesn't do this
  15.  *  because it doesn't need to.
  16.  *
  17.  *  The following routines are implemented in this file:
  18.  *
  19.  *  HrNewSampUser
  20.  *  ABU_QueryInterface
  21.  *  ABU_Release
  22.  *  ABU_OpenProperty
  23.  *  HrBuildListBoxTable
  24.  *  HrBuildDDListboxTable
  25.  *  HrBuildComboBoxTable
  26.  *
  27.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  28.  *
  29.  ***********************************************************************/
  30.  
  31. #include "abp.h"
  32. #include "sampabp.rh"
  33.  
  34. /*
  35.  *  Defined in ABP.C
  36.  */
  37.  
  38. #define MAX_ADDRTYPE                        25
  39. #define MAX_EMAIL_ADDRESS                   MAX_PATH
  40. #define MAX_COMBO_EDIT                      25
  41. #define MAX_LISTBOX_ROWS                    25
  42.  
  43. /* property tags used on details property sheet */
  44. #define PR_CHECKBOX_1_VALUE             PROP_TAG(PT_BOOLEAN,0x6601)
  45. #define PR_CHECKBOX_2_VALUE             PROP_TAG(PT_BOOLEAN,0x6602)
  46. #define PR_CHECKBOX_3_VALUE             PROP_TAG(PT_BOOLEAN,0x6603)
  47. #define PR_LISTBOX_VALUE                PROP_TAG(PT_LONG,0x6604)
  48. #define PR_COMBOBOX_VALUE               PROP_TAG(PT_STRING8,0x6606)
  49. #define PR_DDLISTBOX_VALUE              PROP_TAG(PT_LONG,0x6608)
  50.  
  51. /* Display table control structures for the General and Options property sheets. */
  52.  
  53. /*  First Pane "General", this is the information specific about the first
  54.  *  edit control, which is used to display the display name of this user. */
  55. DTBLEDIT editUserDisplayName =
  56. {
  57.     sizeof(DTBLEDIT),
  58.     0,
  59.     MAX_DISPLAY_NAME,
  60.     PR_DISPLAY_NAME_A
  61. };
  62.  
  63. /*
  64.  *  "General" pane.  This is the information about the email address type associated
  65.  *  with this entry
  66.  */
  67. DTBLEDIT editUserEmailType =
  68. {
  69.     sizeof(DTBLEDIT),
  70.     0,
  71.     MAX_ADDRTYPE,
  72.     PR_ADDRTYPE_A
  73. };
  74.  
  75.  
  76. /*
  77.  *  "General" pane.  This is the information about the email address associated with
  78.  *  this entry.
  79.  */
  80. DTBLEDIT editUserEmailAddress =
  81. {
  82.     sizeof(DTBLEDIT),
  83.     0,
  84.     MAX_EMAIL_ADDRESS,
  85.     PR_EMAIL_ADDRESS_A
  86. };
  87.  
  88.  
  89. /*
  90.  *  This is the actual definition for the "General" pane.  It lists all the controls
  91.  *  found on it.
  92.  */
  93. DTCTL rgdtctlUserGeneral[] =
  94. {
  95.     /*
  96.      * general property page
  97.      *  MAPI UI will default this first pane to be named "General" in this release.
  98.      *  However, subsequent releases will not include this behaviour.  Because of this
  99.      *  it is stongly suggested that your provider provide a DTCT_PAGE control for each
  100.      *  pane.
  101.      */
  102.     {DTCT_PAGE, 0, NULL, 0, NULL, 0,
  103.         &dtblpage},
  104.  
  105.     /* display name control and edit control */
  106.     {DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL,
  107.         &dtbllabel},
  108.     {DTCT_EDIT, 0, NULL, 0, szNoFilter, IDC_USER_DISPLAY_NAME,
  109.         &editUserDisplayName},
  110.  
  111.     /* inbox path control and edit control */
  112.     {DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL,
  113.         &dtbllabel},
  114.     {DTCT_EDIT, 0, NULL, 0, szNoFilter, IDC_USER_INBOX_PATH,
  115.         &editUserEmailAddress},
  116.  
  117.     /* address type control and edit control */
  118.     {DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL,
  119.         &dtbllabel},
  120.     {DTCT_EDIT, 0, NULL, 0, szAddrTypeFilter, IDC_USER_EMAIL_TYPE,
  121.         &editUserEmailType},
  122. };
  123.  
  124. /* controls for the options property page */
  125. /*
  126.  *  "Options" property page.  This is the information that allows the
  127.  *  UI to fill in the listbox control on this pane.
  128.  */
  129.  DTBLLBX listbox1 =
  130. {
  131.     0,
  132.     PR_LISTBOX_VALUE,
  133.     PR_LISTBOX_TABLE
  134. };
  135.  
  136.  
  137. /*
  138.  *  "Options" property page.  The following three controls define a set of check boxes
  139.  *  that are found on this pane.  Notice that the three prop tags in these structures
  140.  *  are different - compare them to the radio buttons found in ABCONT.C.
  141.  */
  142.  DTBLCHECKBOX checkbox1 =
  143. {
  144.     sizeof(DTBLCHECKBOX),
  145.     0,
  146.     PR_CHECKBOX_1_VALUE
  147. };
  148.  
  149.  DTBLCHECKBOX checkbox2 =
  150. {
  151.     sizeof(DTBLCHECKBOX),
  152.     0,
  153.     PR_CHECKBOX_2_VALUE
  154. };
  155.  
  156.  DTBLCHECKBOX checkbox3 =
  157. {
  158.     sizeof(DTBLCHECKBOX),
  159.     0,
  160.     PR_CHECKBOX_3_VALUE
  161. };
  162.  
  163.  
  164. /*
  165.  *   "Options" property page.  This is the information required for
  166.  *  the UI to generate a drop down list box.
  167.  */
  168.  DTBLDDLBX ddlistbox1 =
  169. {
  170.     sizeof(DTBLDDLBX),
  171.     PR_DISPLAY_NAME_A,
  172.     PR_DDLISTBOX_VALUE,
  173.     PR_DDLISTBOX_TABLE
  174. };
  175.  
  176.  
  177. /*
  178.  *  "Options" property page.  This is the information required for the
  179.  *  UI to generate a combo box control.
  180.  */
  181.  DTBLCOMBOBOX combobox1 =
  182. {
  183.     sizeof(DTBLCOMBOBOX),
  184.     0,
  185.     MAX_COMBO_EDIT,
  186.     PR_COMBOBOX_VALUE,
  187.     PR_COMBOBOX_TABLE
  188. };
  189.  
  190. /*
  191.  *  This is the actual definition of the "Options" pane.  This lists all the
  192.  *  controls found on that page.
  193.  */
  194.  DTCTL rgdtctlUserAdvanced[] =
  195. {
  196.  
  197.     /* options property page
  198.      *  This tells the UI what the tab for this pane should say.
  199.      */
  200.     {DTCT_PAGE, 0, NULL, 0, NULL, 0, &dtblpage},
  201.  
  202.     /* control and listbox */
  203.     {DTCT_LABEL, 0, NULL, 0, NULL,
  204.         IDC_STATIC_CONTROL, &dtbllabel},
  205.     {DTCT_LBX, 0, NULL, 0, NULL,
  206.         IDC_USER_LISTBOX, &listbox1},
  207.  
  208.     /* group box and radio buttons */
  209.     {DTCT_GROUPBOX, 0, NULL, 0, NULL,
  210.         IDC_STATIC_CONTROL, &dtblgroupbox},
  211.     {DTCT_CHECKBOX, DT_EDITABLE, NULL, 0, NULL,
  212.         IDC_USER_CHECKBOX_1, &checkbox1},
  213.     {DTCT_CHECKBOX, DT_EDITABLE, NULL, 0, NULL,
  214.         IDC_USER_CHECKBOX_2, &checkbox2},
  215.     {DTCT_CHECKBOX, DT_EDITABLE, NULL, 0, NULL,
  216.         IDC_USER_CHECKBOX_3, &checkbox3},
  217.  
  218.     /* control and drop down listbox */
  219.     {DTCT_LABEL, 0, NULL, 0, NULL,
  220.         IDC_STATIC_CONTROL, &dtbllabel},
  221.     {DTCT_DDLBX, DT_EDITABLE, NULL, 0, NULL,
  222.         IDC_USER_DDLISTBOX, &ddlistbox1},
  223.  
  224.     /* control and combobox */
  225.     {DTCT_LABEL, 0, NULL, 0, NULL,
  226.         IDC_STATIC_CONTROL, &dtbllabel},
  227.     {DTCT_COMBOBOX, DT_EDITABLE, NULL, 0, szNoFilter,
  228.         IDC_USER_COMBOBOX, &combobox1},
  229. };
  230.  
  231. /* Display table pages */
  232.  
  233. /*
  234.  *  This lists the order in which the panes will appear in the UI.  The
  235.  *  UI is driven by a display table which is generated by a call to
  236.  *  BuildDisplayTable() which takes the following DTPAGE structure.
  237.  */
  238. DTPAGE rgdtpage[] =
  239. {
  240.     {
  241.         sizeof(rgdtctlUserGeneral) / sizeof(DTCTL),
  242.         (LPTSTR) MAKEINTRESOURCE(UserGeneralPage),
  243.         "",
  244.         rgdtctlUserGeneral
  245.     },
  246.     {
  247.         sizeof(rgdtctlUserAdvanced) / sizeof(DTCTL),
  248.         (LPTSTR) MAKEINTRESOURCE(UserAdvancedPage),
  249.         "",
  250.         rgdtctlUserAdvanced
  251.     }
  252.  
  253. };
  254.  
  255.  
  256. /*
  257.  *  Definition of the ABUSER object
  258.  */
  259. typedef struct _ABUSER
  260. {
  261.     const ABU_Vtbl FAR * lpVtbl;
  262.  
  263.     SAB_Wrapped;
  264.  
  265.     /*
  266.      *   Tables used in options property page
  267.      */
  268.     LPTABLEDATA lpTDatListBox;
  269.     LPTABLEDATA lpTDatDDListBox;
  270.     LPTABLEDATA lpTDatComboBox;
  271.  
  272.  
  273. } ABUSER, *LPABUSER;
  274.  
  275. /*
  276.  *  ABUser vtbl filled in here
  277.  */
  278. const ABU_Vtbl vtblABU =
  279. {
  280.  
  281.     ABU_QueryInterface,
  282.     (ABU_AddRef_METHOD *)           ROOT_AddRef,
  283.     ABU_Release,
  284.     (ABU_GetLastError_METHOD *)     ROOT_GetLastError,
  285.     (ABU_SaveChanges_METHOD *)      WRAP_SaveChanges,
  286.     (ABU_GetProps_METHOD *)         WRAP_GetProps,
  287.     (ABU_GetPropList_METHOD *)      WRAP_GetPropList,
  288.     ABU_OpenProperty,
  289.     (ABU_SetProps_METHOD *)         WRAP_SetProps,
  290.     (ABU_DeleteProps_METHOD *)      WRAP_DeleteProps,
  291.     (ABU_CopyTo_METHOD *)           WRAP_CopyTo,
  292.     (ABU_CopyProps_METHOD *)        WRAP_CopyProps,
  293.     (ABU_GetNamesFromIDs_METHOD *)  WRAP_GetNamesFromIDs,
  294.     (ABU_GetIDsFromNames_METHOD *)  WRAP_GetIDsFromNames,
  295. };
  296.  
  297.  
  298. HRESULT HrBuildListBoxTable(LPABUSER lpABUser);
  299. HRESULT HrBuildDDListBoxTable(LPABUSER lpABUser);
  300. HRESULT HrBuildComboBoxTable(LPABUSER lpABUser);
  301.  
  302. enum {  ivalusrPR_DISPLAY_TYPE = 0,
  303.         ivalusrPR_OBJECT_TYPE,
  304.         ivalusrPR_ENTRYID,
  305.         ivalusrPR_RECORD_KEY,
  306.         ivalusrPR_DISPLAY_NAME_A,
  307.         ivalusrPR_TRANSMITABLE_DISPLAY_NAME_A,
  308.         ivalusrPR_EMAIL_ADDRESS_A,
  309.         ivalusrPR_ADDRTYPE_A,
  310.         ivalusrPR_SEARCH_KEY,
  311.         ivalusrPR_LISTBOX_VALUE,
  312.         ivalusrPR_CHECKBOX_1_VALUE,
  313.         ivalusrPR_CHECKBOX_2_VALUE,
  314.         ivalusrPR_CHECKBOX_3_VALUE,
  315.         ivalusrPR_DDLISTBOX_VALUE,
  316.         ivalusrPR_COMBOBOX_VALUE,
  317.         ivalusrPR_TEMPLATEID,
  318.         cvalusrMax };
  319.  
  320. static SizedSPropTagArray( cvalusrMax, tagaABUAccess) =
  321. {
  322.     cvalusrMax,
  323.     {   PR_DISPLAY_TYPE,
  324.         PR_OBJECT_TYPE,
  325.         PR_ENTRYID,
  326.         PR_RECORD_KEY,
  327.         PR_DISPLAY_NAME_A,
  328.         PR_TRANSMITABLE_DISPLAY_NAME_A,
  329.         PR_EMAIL_ADDRESS_A,
  330.         PR_ADDRTYPE_A,
  331.         PR_SEARCH_KEY,
  332.         PR_LISTBOX_VALUE,
  333.         PR_CHECKBOX_1_VALUE,
  334.         PR_CHECKBOX_2_VALUE,
  335.         PR_CHECKBOX_3_VALUE,
  336.         PR_DDLISTBOX_VALUE,
  337.         PR_COMBOBOX_VALUE,
  338.         PR_TEMPLATEID
  339.       }
  340. };
  341.  
  342. static ULONG    rgulABUAccess[cvalusrMax] =
  343. {
  344.     IPROP_READONLY | IPROP_CLEAN,   /* PR_DISPLAY_TYPE */
  345.     IPROP_READONLY | IPROP_CLEAN,   /* PR_OBJECT_TYPE */
  346.     IPROP_READONLY | IPROP_CLEAN,   /* PR_ENTRYID */
  347.     IPROP_READONLY | IPROP_CLEAN,   /* PR_RECORD_KEY */
  348.     IPROP_READONLY | IPROP_CLEAN,   /* PR_DISPLAY_NAME_A */
  349.     IPROP_READONLY | IPROP_CLEAN,   /* PR_TRANSMITABLE_DISPLAY_NAME_A */
  350.     IPROP_READONLY | IPROP_CLEAN,   /* PR_EMAIL_ADDRESS_A */
  351.     IPROP_READONLY | IPROP_CLEAN,   /* PR_ADDRTYPE_A */
  352.     IPROP_READONLY | IPROP_CLEAN,   /* PR_SEARCH_KEY */
  353.     IPROP_READWRITE | IPROP_CLEAN,  /* PR_LISTBOX_VALUE */
  354.     IPROP_READWRITE | IPROP_CLEAN,  /* PR_CHECKBOX_1_VALUE */
  355.     IPROP_READWRITE | IPROP_CLEAN,  /* PR_CHECKBOX_2_VALUE */
  356.     IPROP_READWRITE | IPROP_CLEAN,  /* PR_CHECKBOX_3_VALUE */
  357.     IPROP_READWRITE | IPROP_CLEAN,  /* PR_DDLISTBOX_VALUE */
  358.     IPROP_READWRITE | IPROP_CLEAN,  /* PR_COMBOBOX_VALUE */
  359.     IPROP_READONLY | IPROP_CLEAN    /* PR_TEMPLATEID */
  360. };
  361.  
  362.  
  363. /*************************************************************************
  364.  *
  365.  -  HrNewSampUser
  366.  -
  367.  *  Creates the IMAPIProp associated with a mail user.
  368.  *
  369.  *
  370.  */
  371. HRESULT
  372. HrNewSampUser(  LPMAILUSER *        lppMAPIPropEntry,
  373.                 ULONG *             lpulObjType,
  374.                 ULONG               cbEntryID,
  375.                 LPENTRYID           lpEntryID,
  376.                 LPABLOGON           lpABPLogon,
  377.                 LPCIID              lpInterface,
  378.                 HINSTANCE           hLibrary,
  379.                 LPALLOCATEBUFFER    lpAllocBuff,
  380.                 LPALLOCATEMORE      lpAllocMore,
  381.                 LPFREEBUFFER        lpFreeBuff,
  382.                 LPMALLOC            lpMalloc )
  383. {
  384.     LPABUSER lpABUser = NULL;
  385.     SCODE sc;
  386.     HRESULT hr = hrSuccess;
  387.     LPPROPDATA lpPropData = NULL;
  388.     SPropValue spv[cvalusrMax];
  389.     ULONG cbT = 0;
  390.     LPBYTE lpbT = NULL;
  391.     LPSTR lpszEMA = NULL;
  392.  
  393.     /*  Do I support this interface?? */
  394.     if (lpInterface)
  395.     {
  396.         if (memcmp(lpInterface, &IID_IMailUser, sizeof(IID)) &&
  397.             memcmp(lpInterface, &IID_IMAPIProp, sizeof(IID)) &&
  398.             memcmp(lpInterface, &IID_IUnknown, sizeof(IID)))
  399.         {
  400.             DebugTraceSc(HrNewSampUser, MAPI_E_INTERFACE_NOT_SUPPORTED);
  401.             return ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  402.         }
  403.     }
  404.     /*
  405.      *  Allocate space for the ROOT structure
  406.      */
  407.     sc = lpAllocBuff(sizeof(ABUSER), (LPVOID *) &lpABUser);
  408.     if (FAILED(sc))
  409.     {
  410.         hr = ResultFromScode(sc);
  411.         goto err;
  412.     }
  413.  
  414.     lpABUser->lpVtbl = &vtblABU;
  415.     lpABUser->lcInit = 1;
  416.     lpABUser->hResult = hrSuccess;
  417.     lpABUser->idsLastError = 0;
  418.  
  419.     lpABUser->hLibrary = hLibrary;
  420.     lpABUser->lpAllocBuff = lpAllocBuff;
  421.     lpABUser->lpAllocMore = lpAllocMore;
  422.     lpABUser->lpFreeBuff = lpFreeBuff;
  423.     lpABUser->lpMalloc = lpMalloc;
  424.  
  425.     lpABUser->lpABLogon = lpABPLogon;
  426.     lpABUser->lpTDatListBox = NULL;
  427.     lpABUser->lpTDatDDListBox = NULL;
  428.     lpABUser->lpTDatComboBox = NULL;
  429.  
  430.     /*
  431.      *  Create property storage object
  432.      */
  433.  
  434.     sc = CreateIProp((LPIID) &IID_IMAPIPropData,
  435.         lpAllocBuff,
  436.         lpAllocMore,
  437.         lpFreeBuff,
  438.         lpMalloc,
  439.         &lpPropData);
  440.  
  441.     if (FAILED(sc))
  442.     {
  443.         hr = ResultFromScode(sc);
  444.         goto err;
  445.     }
  446.  
  447.     /*
  448.      *  Set up initial set of properties associated with this
  449.      *  mailuser.
  450.      */
  451.  
  452.     /*
  453.      *  Easy ones first
  454.      */
  455.  
  456.     spv[ivalusrPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
  457.     spv[ivalusrPR_DISPLAY_TYPE].Value.l = DT_MAILUSER;
  458.  
  459.     spv[ivalusrPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
  460.     spv[ivalusrPR_OBJECT_TYPE].Value.l = MAPI_MAILUSER;
  461.  
  462.     spv[ivalusrPR_ENTRYID].ulPropTag = PR_ENTRYID;
  463.     spv[ivalusrPR_ENTRYID].Value.bin.cb = sizeof(USR_ENTRYID);
  464.     spv[ivalusrPR_ENTRYID].Value.bin.lpb = (LPBYTE) lpEntryID;
  465.  
  466.     /*
  467.      *  Now the calculated props
  468.      */
  469.  
  470.     spv[ivalusrPR_RECORD_KEY].ulPropTag = PR_RECORD_KEY;
  471.     spv[ivalusrPR_RECORD_KEY].Value.bin.cb = sizeof(USR_ENTRYID);
  472.     spv[ivalusrPR_RECORD_KEY].Value.bin.lpb = (LPBYTE) lpEntryID;
  473.  
  474.     spv[ivalusrPR_DISPLAY_NAME_A].ulPropTag = PR_DISPLAY_NAME_A;
  475.     spv[ivalusrPR_DISPLAY_NAME_A].Value.lpszA = ((LPUSR_ENTRYID) lpEntryID)->abcrec.rgchDisplayName;
  476.  
  477.     /* Should always be the same as PR_DISPLAY_NAME */
  478.     spv[ivalusrPR_TRANSMITABLE_DISPLAY_NAME_A].ulPropTag = PR_TRANSMITABLE_DISPLAY_NAME_A;
  479.     spv[ivalusrPR_TRANSMITABLE_DISPLAY_NAME_A].Value.lpszA = ((LPUSR_ENTRYID) lpEntryID)->abcrec.rgchDisplayName;
  480.  
  481.     spv[ivalusrPR_EMAIL_ADDRESS_A].ulPropTag = PR_EMAIL_ADDRESS_A;
  482.     spv[ivalusrPR_EMAIL_ADDRESS_A].Value.lpszA = ((LPUSR_ENTRYID) lpEntryID)->abcrec.rgchEmailAddress;
  483.     lpszEMA = ((LPUSR_ENTRYID) lpEntryID)->abcrec.rgchEmailAddress;
  484.  
  485.     spv[ivalusrPR_ADDRTYPE_A].ulPropTag = PR_ADDRTYPE_A;
  486.     spv[ivalusrPR_ADDRTYPE_A].Value.lpszA = lpszEMT;
  487.  
  488.     /*
  489.      *  Build the search key...
  490.      */
  491.     /*  Search keys for mailable recipients that have email addresses are
  492.      *  defined as "EmailType':'EmailAddress\0".  We do the +2 for the ':' and
  493.      *  '\0'.
  494.      */
  495.     cbT = lstrlenA(lpszEMA) + lstrlenA(lpszEMT) + 2;
  496.  
  497.     sc = lpAllocBuff( cbT, (LPVOID *) &lpbT );
  498.     if (FAILED(sc))
  499.     {
  500.         hr = ResultFromScode(sc);
  501.         goto err;
  502.     }
  503.     lstrcpyA((LPSTR) lpbT, lpszEMT);
  504.     lstrcatA((LPSTR) lpbT, ":");
  505.     lstrcatA((LPSTR) lpbT, lpszEMA);
  506.     CharUpperBuff((LPTSTR) lpbT, (UINT) cbT);
  507.  
  508.     spv[ivalusrPR_SEARCH_KEY].ulPropTag = PR_SEARCH_KEY;
  509.     spv[ivalusrPR_SEARCH_KEY].Value.bin.cb = cbT;
  510.     spv[ivalusrPR_SEARCH_KEY].Value.bin.lpb = lpbT;
  511.  
  512.     /* properties used by the options property page */
  513.     spv[ivalusrPR_LISTBOX_VALUE].ulPropTag = PR_LISTBOX_VALUE;
  514.     spv[ivalusrPR_LISTBOX_VALUE].Value.l = 5;
  515.  
  516.     spv[ivalusrPR_CHECKBOX_1_VALUE].ulPropTag = PR_CHECKBOX_1_VALUE;
  517.     spv[ivalusrPR_CHECKBOX_1_VALUE].Value.b = TRUE;
  518.  
  519.     spv[ivalusrPR_CHECKBOX_2_VALUE].ulPropTag = PR_CHECKBOX_2_VALUE;
  520.     spv[ivalusrPR_CHECKBOX_2_VALUE].Value.b = FALSE;
  521.  
  522.     spv[ivalusrPR_CHECKBOX_3_VALUE].ulPropTag = PR_CHECKBOX_3_VALUE;
  523.     spv[ivalusrPR_CHECKBOX_3_VALUE].Value.b = TRUE;
  524.  
  525.     spv[ivalusrPR_DDLISTBOX_VALUE].ulPropTag = PR_DDLISTBOX_VALUE;
  526.     spv[ivalusrPR_DDLISTBOX_VALUE].Value.l = 10;
  527.  
  528.     spv[ivalusrPR_COMBOBOX_VALUE].ulPropTag = PR_COMBOBOX_VALUE;
  529.     spv[ivalusrPR_COMBOBOX_VALUE].Value.lpszA = "ComboBox item 10";
  530.  
  531.     /*
  532.      *  Note that we're using our entryID for our templateID.
  533.      *  This is a really simple way to implement templateIDs.
  534.      *  (See TID.C)
  535.      */
  536.     spv[ivalusrPR_TEMPLATEID].ulPropTag = PR_TEMPLATEID;
  537.     spv[ivalusrPR_TEMPLATEID].Value.bin.cb = sizeof(USR_ENTRYID);
  538.     spv[ivalusrPR_TEMPLATEID].Value.bin.lpb = (LPBYTE) lpEntryID;
  539.  
  540.     /*
  541.      *   Set the default properties
  542.      */
  543.     hr = lpPropData->lpVtbl->SetProps(
  544.         lpPropData,
  545.         cvalusrMax,
  546.         spv,
  547.         NULL);
  548.  
  549.     if (HR_FAILED(hr))
  550.     {
  551.         goto err;
  552.     }
  553.  
  554.     /*
  555.      *  Although this object is basically read only, we wanted to show
  556.      *  an example of how the check-boxes and other controls on the
  557.      *  "Options" pane work.  If we had set this object to be read only,
  558.      *  the values behind those controls would have been static.
  559.      */
  560.     (void)lpPropData->lpVtbl->HrSetObjAccess(lpPropData, IPROP_READWRITE);
  561.  
  562.     /*
  563.      *  Set the client access rights to the various properties.  Notice
  564.      *  that everything is READONLY except for the properties related to
  565.      *  the controls on the "Options" pane.
  566.      *
  567.      *  All properties are intially marked as CLEAN.
  568.      */
  569.     (void) lpPropData->lpVtbl->HrSetPropAccess(lpPropData,
  570.                                 (LPSPropTagArray) &tagaABUAccess,
  571.                                 rgulABUAccess);
  572.  
  573.     lpABUser->lpPropData = (LPMAPIPROP) lpPropData;
  574.  
  575.     InitializeCriticalSection(&lpABUser->cs);
  576.  
  577.     /*  We must AddRef the lpABPLogon object since we will be using it
  578.      */
  579.     lpABPLogon->lpVtbl->AddRef(lpABPLogon);
  580.  
  581.     *lppMAPIPropEntry = (LPVOID) lpABUser;
  582.     *lpulObjType = MAPI_MAILUSER;
  583.  
  584. out:
  585.     lpFreeBuff(lpbT);
  586.  
  587.     DebugTraceResult(HrNewSampUser, hr);
  588.     return hr;
  589.  
  590. err:
  591.     if (lpPropData)
  592.         lpPropData->lpVtbl->Release(lpPropData);
  593.  
  594.     lpFreeBuff(lpABUser);
  595.  
  596.     goto out;
  597.  
  598. }
  599.  
  600.  
  601. /*************************************************************************
  602.  *
  603.  *
  604.  -  ABU_QueryInterface
  605.  -
  606.  *  Allows QI'ing to only IUnknown, IMAPIProp, and IMailUser.
  607.  *
  608.  *  This method is reused in TID.C, OOTID.C, and ABOOSER.C.  Hence the
  609.  *  difference in checking of the 'this' pointer from other methods within
  610.  *  this object.
  611.  */
  612. STDMETHODIMP
  613. ABU_QueryInterface(LPABUSER lpABUser,
  614.     REFIID lpiid,
  615.     LPVOID FAR * lppNewObj)
  616. {
  617.  
  618.     HRESULT hr = hrSuccess;
  619.  
  620.     /*  Minimally check the lpABUser object
  621.      *  Can't do any more extensive checking that this because this method is reused
  622.      *  in OOUSER.C.
  623.      */
  624.  
  625.     if (IsBadReadPtr(lpABUser, offsetof(ABUSER, lpVtbl)+sizeof(ABU_Vtbl *)))
  626.     {
  627.         hr = ResultFromScode(E_INVALIDARG);
  628.         goto out;
  629.     }
  630.         
  631.     if (IsBadReadPtr(lpABUser->lpVtbl,
  632.                      offsetof(ABU_Vtbl, QueryInterface)+sizeof(ABU_QueryInterface_METHOD *)))
  633.     {
  634.         hr = ResultFromScode(E_INVALIDARG);
  635.         goto out;
  636.     }
  637.         
  638.     if (ABU_QueryInterface != lpABUser->lpVtbl->QueryInterface)
  639.     {
  640.         hr = ResultFromScode(E_INVALIDARG);
  641.         goto out;
  642.     }
  643.         
  644.  
  645.     /*  Validate other parameters */
  646.  
  647.     if (IsBadReadPtr(lpiid, (UINT) sizeof(IID)))
  648.     {
  649.         hr = ResultFromScode(E_INVALIDARG);
  650.         goto out;
  651.     }
  652.  
  653.     if (IsBadWritePtr(lppNewObj, sizeof(LPVOID)))
  654.     {
  655.         hr = ResultFromScode(E_INVALIDARG);
  656.         goto out;
  657.     }
  658.         
  659.  
  660.     /*  See if the requested interface is one of ours */
  661.  
  662.     if (memcmp(lpiid, &IID_IUnknown, sizeof(IID)) &&
  663.         memcmp(lpiid, &IID_IMAPIProp, sizeof(IID)) &&
  664.         memcmp(lpiid, &IID_IMailUser, sizeof(IID)))
  665.     {
  666.         *lppNewObj = NULL;      /* OLE requires zeroing [out] parameter */
  667.         hr = ResultFromScode(E_NOINTERFACE);
  668.         goto out;
  669.     }
  670.  
  671.     /*  Bump the usage count and return same object pointer. */
  672.  
  673.     EnterCriticalSection(&lpABUser->cs);
  674.     ++lpABUser->lcInit;
  675.     LeaveCriticalSection(&lpABUser->cs);
  676.     
  677.     *lppNewObj = lpABUser;
  678.  
  679. out:
  680.  
  681.     DebugTraceResult(ABU_QueryInterface, hr);
  682.     return hr;
  683. }
  684.  
  685.  
  686. /**************************************************
  687.  *
  688.  -  ABU_Release
  689.  -
  690.  *      Decrement lcInit.
  691.  *      When lcInit == 0, free up the lpABUser structure
  692.  *
  693.  */
  694. STDMETHODIMP_(ULONG)
  695. ABU_Release(LPABUSER lpABUser)
  696. {
  697.  
  698.     LONG lcInit;
  699.     /*
  700.      *  Check to see if it's big enough to hold this object
  701.      */
  702.     if (IsBadReadPtr(lpABUser, sizeof(ABUSER)))
  703.     {
  704.         /*
  705.          *  Not large enough
  706.          */
  707.         return 1;
  708.     }
  709.  
  710.     /*
  711.      *  Check to see that it's the correct vtbl
  712.      */
  713.     if (lpABUser->lpVtbl != &vtblABU)
  714.     {
  715.         /*
  716.          *  Not my vtbl
  717.          */
  718.         return 1;
  719.     }
  720.  
  721.     EnterCriticalSection(&lpABUser->cs);
  722.     lcInit = --lpABUser->lcInit;
  723.     LeaveCriticalSection(&lpABUser->cs);
  724.  
  725.     if (lcInit == 0)
  726.     {
  727.  
  728.         /*
  729.          *  Get rid of the lpPropData
  730.          */
  731.  
  732.         lpABUser->lpPropData->lpVtbl->Release(lpABUser->lpPropData);
  733.  
  734.         /*
  735.          *  Get rid of the tables used by the options property page
  736.          */
  737.  
  738.         if (lpABUser->lpTDatListBox)
  739.             lpABUser->lpTDatListBox->lpVtbl->Release(lpABUser->lpTDatListBox);
  740.  
  741.         if (lpABUser->lpTDatDDListBox)
  742.             lpABUser->lpTDatDDListBox->lpVtbl->Release(lpABUser->lpTDatDDListBox);
  743.  
  744.         if (lpABUser->lpTDatComboBox)
  745.             lpABUser->lpTDatComboBox->lpVtbl->Release(lpABUser->lpTDatComboBox);
  746.  
  747.         /*  
  748.          *  Release our reference to the ABLogon object.
  749.          */
  750.         if (lpABUser->lpABLogon)
  751.         {
  752.             lpABUser->lpABLogon->lpVtbl->Release(lpABUser->lpABLogon);
  753.             lpABUser->lpABLogon = NULL;
  754.         }
  755.  
  756.         /*
  757.          *  Destroy the critical section for this object
  758.          */
  759.  
  760.         DeleteCriticalSection(&lpABUser->cs);
  761.  
  762.         /*
  763.          *  Set the vtbl to NULL.  This way the client will find out
  764.          *  real fast if it's calling a method on a released object.  That is,
  765.          *  the client will crash.  Hopefully, this will happen during the
  766.          *  development stage of the client.
  767.          */
  768.  
  769.         lpABUser->lpVtbl = NULL;
  770.  
  771.         /*
  772.          *  Need to free the object
  773.          */
  774.  
  775.         lpABUser->lpFreeBuff( lpABUser );
  776.         return 0;
  777.     }
  778.  
  779.     return lcInit;
  780.  
  781. }
  782.  
  783. /*************************************************************************
  784.  *
  785.  -  ABU_OpenProperty
  786.  -
  787.  *
  788.  *  This is how we get the display table associated with this users
  789.  *  details screen.  This is also how we get the tables which are needed
  790.  *  to fill out the "Options" property pane.
  791.  */
  792. STDMETHODIMP
  793. ABU_OpenProperty(LPABUSER lpABUser,
  794.     ULONG ulPropTag,
  795.     LPCIID lpiid,
  796.     ULONG ulInterfaceOptions,
  797.     ULONG ulFlags,
  798.     LPUNKNOWN * lppUnk)
  799. {
  800.  
  801.     HRESULT hResult;
  802.  
  803.     /*
  804.      *  Check to see if it's big enough to hold this object
  805.      */
  806.     if (IsBadReadPtr(lpABUser, sizeof(ABUSER)))
  807.     {
  808.         /*
  809.          *  Not large enough
  810.          */
  811.         hResult = ResultFromScode(E_INVALIDARG);
  812.  
  813.         DebugTraceResult(ABU_OpenProperty, hResult);
  814.         return hResult;
  815.     }
  816.  
  817.     /*
  818.      *  Check to see that it's the correct vtbl
  819.      */
  820.     if (lpABUser->lpVtbl != &vtblABU)
  821.     {
  822.         /*
  823.          *  Not my vtbl
  824.          */
  825.         hResult = ResultFromScode(E_INVALIDARG);
  826.  
  827.         DebugTraceResult(ABU_OpenProperty, hResult);
  828.         return hResult;
  829.     }
  830.  
  831.     if (IsBadWritePtr(lppUnk, sizeof(LPUNKNOWN)))
  832.     {
  833.         /*
  834.          *  Got to be able to return an object
  835.          */
  836.         hResult = ResultFromScode(E_INVALIDARG);
  837.  
  838.         DebugTraceResult(ABU_OpenProperty, hResult);
  839.         return hResult;
  840.     }
  841.  
  842.     if (IsBadReadPtr(lpiid, (UINT) sizeof(IID)))
  843.     {
  844.         /*
  845.          *  An interface ID is required for this call.
  846.          */
  847.  
  848.         hResult = ResultFromScode(E_INVALIDARG);
  849.  
  850.         DebugTraceResult(ABU_OpenProperty, hResult);
  851.         return hResult;
  852.     }
  853.  
  854.     /*
  855.      *  Make sure we are getting a valid PropTag.
  856.      */
  857.     if (FBadPropTag(ulPropTag))
  858.     {
  859.         hResult = ResultFromScode(E_INVALIDARG);
  860.  
  861.         DebugTraceResult(ABU_OpenProperty, hResult);
  862.         return hResult;
  863.     }
  864.  
  865.     /*
  866.      *  check for unknown flags
  867.      */
  868.     if (ulFlags & ~(  MAPI_DEFERRED_ERRORS | STREAM_APPEND
  869.                     | MAPI_CREATE | MAPI_MODIFY))
  870.     {
  871.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  872.  
  873.         DebugTraceResult(ABU_OpenProperty, hResult);
  874.         return hResult;
  875.     }
  876.  
  877.     /*
  878.      *  STREAM_APPEND is only valid on a stream interface.
  879.      */
  880.     if (   (ulFlags & STREAM_APPEND)
  881.         && memcmp(lpiid, &IID_IStream, sizeof(IID)) )
  882.     {
  883.         hResult = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  884.  
  885.         DebugTraceResult(ABU_OpenProperty, hResult);
  886.         return hResult;
  887.     }
  888.         
  889.     if (ulInterfaceOptions & ~MAPI_UNICODE )
  890.     {
  891.         /*
  892.          *  Only the Unicode flag should be set for any of the objects that might
  893.          *  be returned from this object.
  894.          */
  895.         
  896.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  897.  
  898.         DebugTraceResult(ABU_OpenProperty, hResult);
  899.         return hResult;
  900.     }
  901.     
  902.     if ( ulInterfaceOptions & MAPI_UNICODE )
  903.     {
  904.         hResult = ResultFromScode(MAPI_E_BAD_CHARWIDTH);
  905.         DebugTraceResult(ABU_OpenProperty, hResult);
  906.         return hResult;
  907.         
  908.     }
  909.     
  910.     if (ulFlags & MAPI_CREATE)
  911.     {
  912.         hResult = ResultFromScode(E_ACCESSDENIED);
  913.         
  914.         DebugTraceResult(ABU_OpenProperty, hResult);
  915.         return hResult;
  916.     }
  917.     
  918.  
  919.     if (ulPropTag == PR_DETAILS_TABLE ||
  920.         ulPropTag == PR_LISTBOX_TABLE ||
  921.         ulPropTag == PR_DDLISTBOX_TABLE ||
  922.         ulPropTag == PR_COMBOBOX_TABLE)
  923.     {
  924.         /* Check to see if they're expecting a table interface */
  925.  
  926.         if (memcmp(lpiid, &IID_IMAPITable, sizeof(IID)))
  927.         {
  928.             hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  929.             return hResult;
  930.         }
  931.     }
  932.  
  933.  
  934.  
  935.     EnterCriticalSection(&lpABUser->cs);
  936.  
  937.  
  938.  
  939.     switch (ulPropTag)
  940.     {
  941.         case PR_DETAILS_TABLE:
  942.         {
  943.  
  944.             /* Looking for the display table*/
  945.             /* Create a display table */
  946.  
  947.             hResult = BuildDisplayTable(
  948.                 lpABUser->lpAllocBuff,
  949.                 lpABUser->lpAllocMore,
  950.                 lpABUser->lpFreeBuff,
  951.                 lpABUser->lpMalloc,
  952.                 lpABUser->hLibrary,
  953.                 sizeof(rgdtpage) / sizeof(DTPAGE),
  954.                 rgdtpage,
  955.                 0,
  956.                 (LPMAPITABLE *) lppUnk,
  957.                 NULL);
  958.  
  959.             break;
  960.         }
  961.  
  962.         case PR_LISTBOX_TABLE:
  963.         {
  964.             
  965.             /*
  966.              *  Looking for the table that fills the listbox
  967.              *  on the Options pane on this user's details
  968.              */
  969.  
  970.             /*
  971.              *  If we don't already have a Table Data Object, make one.
  972.              */
  973.             if (!lpABUser->lpTDatListBox)
  974.             {
  975.                 hResult = HrBuildListBoxTable(lpABUser);
  976.                 if (HR_FAILED(hResult))
  977.                     goto out;
  978.             }
  979.  
  980.             Assert(lpABUser->lpTDatListBox);
  981.  
  982.             /* Get a view from the table data object*/
  983.             hResult = lpABUser->lpTDatListBox->lpVtbl->HrGetView(
  984.                         lpABUser->lpTDatListBox,
  985.                         NULL,
  986.                         NULL,
  987.                         0,
  988.                         (LPMAPITABLE *) lppUnk);
  989.  
  990.             break;
  991.         }
  992.  
  993.         case PR_DDLISTBOX_TABLE:
  994.         {
  995.             /*
  996.              *  Locking for the table that fills the drop down listbox
  997.              *  on the Options pane on this user's details.
  998.              */
  999.  
  1000.             if (!lpABUser->lpTDatDDListBox)
  1001.             {
  1002.                 hResult = HrBuildDDListBoxTable(lpABUser);
  1003.                 if (HR_FAILED(hResult))
  1004.                     goto out;
  1005.             }
  1006.  
  1007.             Assert(lpABUser->lpTDatDDListBox);
  1008.  
  1009.             /* Get a view from the table data object */
  1010.             hResult = lpABUser->lpTDatDDListBox->lpVtbl->HrGetView(
  1011.                         lpABUser->lpTDatDDListBox,
  1012.                         NULL,
  1013.                         NULL,
  1014.                         0,
  1015.                         (LPMAPITABLE *) lppUnk);
  1016.  
  1017.  
  1018.             break;
  1019.         }
  1020.  
  1021.         case PR_COMBOBOX_TABLE:
  1022.         {
  1023.             /*
  1024.              *  Locking for the table that fills the combobox
  1025.              *  on the Options pane on this user's details.
  1026.              */
  1027.  
  1028.             if (!lpABUser->lpTDatComboBox)
  1029.             {
  1030.                 hResult = HrBuildComboBoxTable(lpABUser);
  1031.                 if (HR_FAILED(hResult))
  1032.                     goto out;
  1033.             }
  1034.  
  1035.             Assert(lpABUser->lpTDatComboBox);
  1036.  
  1037.             /* Get a view from the table data object */
  1038.             hResult =
  1039.                 lpABUser->lpTDatComboBox->lpVtbl->HrGetView(
  1040.                 lpABUser->lpTDatComboBox,
  1041.                 NULL,
  1042.                 NULL,
  1043.                 0,
  1044.                 (LPMAPITABLE *) lppUnk);
  1045.  
  1046.             break;
  1047.         }
  1048.  
  1049.         default:
  1050.         {
  1051.             hResult = ResultFromScode(MAPI_E_NO_SUPPORT);
  1052.  
  1053.             break;
  1054.         }
  1055.     }
  1056.  
  1057. out:
  1058.  
  1059.     LeaveCriticalSection(&lpABUser->cs);
  1060.     
  1061.     DebugTraceResult(ABU_OpenProperty, hResult);
  1062.     return hResult;
  1063.  
  1064. }
  1065.  
  1066. /**********************************************************************
  1067.  *
  1068.  *  Private functions
  1069.  */
  1070.  
  1071. /*
  1072.  *  Default column set for listbox table
  1073.  */
  1074.  
  1075. enum {  ivallbxPR_DISPLAY_NAME_A = 0,
  1076.         ivallbxPR_COMMENT_A,
  1077.         ivallbxPR_ENTRYID,
  1078.         ivallbxPR_DISPLAY_TYPE,
  1079.         ivallbxPR_LISTBOX_VALUE,
  1080.         ivallbxPR_INSTANCE_KEY,
  1081.         cvallbxMax };
  1082.  
  1083. const SizedSPropTagArray(cvallbxMax, tagaColSetListBox) =
  1084. {
  1085.     cvallbxMax,
  1086.     {
  1087.         PR_DISPLAY_NAME_A,
  1088.         PR_COMMENT_A,
  1089.         PR_ENTRYID,
  1090.         PR_DISPLAY_TYPE,
  1091.         PR_LISTBOX_VALUE,
  1092.         PR_INSTANCE_KEY
  1093.     }
  1094. };
  1095.  
  1096. typedef struct _options_entryid
  1097. {
  1098.     BYTE abFlags[4];
  1099.     MAPIUID muid;
  1100.     ULONG ulVersion;
  1101.     ULONG ulType;
  1102.     ULONG ulRowNumber;
  1103. } OPTIONS_ENTRYID, *LPOPTIONS_ENTRYID;
  1104.  
  1105. #define CBOPTIONS_ENTRYID sizeof(OPTIONS_ENTRYID)
  1106.  
  1107. OPTIONS_ENTRYID OptionsEntryID =
  1108. {
  1109.     {0, 0, 0, 0},
  1110.     MUIDABSAMPLE,
  1111.     SAMP_VERSION,
  1112.     SAMP_UNKNOWN,
  1113.     0
  1114. };
  1115.  
  1116. HRESULT
  1117. HrBuildListBoxTable(LPABUSER lpABUser)
  1118. {
  1119.     SCODE sc;
  1120.     HRESULT hResult;
  1121.     SPropValue rgsPropValue[cvallbxMax];
  1122.     SRow sRow;
  1123.     char szDisplay[MAX_FMT_DET_DN+2]; /* +2 for digits */
  1124.     char szComment[MAX_FMT_DET_COMMENT+2]; /* +2 for digits */
  1125.     char szFmtDisplay[MAX_FMT_DET_DN];
  1126.     char szFmtComment[MAX_FMT_DET_COMMENT];
  1127.     LPSTR pszFmtComment = (LPSTR) szFmtComment;
  1128.     LPSTR pszFmtDisplay = (LPSTR) szFmtDisplay;
  1129.  
  1130.     ULONG uliRow;
  1131.  
  1132.     /*
  1133.      *  Get string resources
  1134.      */
  1135.     sc = ScLoadString(  IDS_FMT_DET_DN,
  1136.                         MAX_FMT_DET_DN,
  1137.                         NULL,
  1138.                         lpABUser->hLibrary,
  1139.                         (LPSTR *) &pszFmtDisplay);
  1140.  
  1141.     if (FAILED(sc))
  1142.     {
  1143.         hResult = ResultFromScode(sc);
  1144.         goto out;
  1145.     }
  1146.  
  1147.     sc = ScLoadString(  IDS_FMT_DET_COMMENT,
  1148.                         MAX_FMT_DET_COMMENT,
  1149.                         NULL,
  1150.                         lpABUser->hLibrary,
  1151.                         (LPSTR *) &pszFmtComment);
  1152.     if (FAILED(sc))
  1153.     {
  1154.         hResult = ResultFromScode(sc);
  1155.         goto out;
  1156.     }
  1157.  
  1158.     /* Create a Table Data object */
  1159.     sc = CreateTable(
  1160.         (LPIID) &IID_IMAPITableData,
  1161.         lpABUser->lpAllocBuff,
  1162.         lpABUser->lpAllocMore,
  1163.         lpABUser->lpFreeBuff,
  1164.         lpABUser->lpMalloc,
  1165.         0,
  1166.         PR_DISPLAY_NAME_A,
  1167.         (LPSPropTagArray) &tagaColSetListBox,
  1168.         &(lpABUser->lpTDatListBox));
  1169.  
  1170.     if (FAILED(sc))
  1171.     {
  1172.         hResult = ResultFromScode(sc);
  1173.         goto out;
  1174.     }
  1175.  
  1176.     /* constants */
  1177.     sRow.cValues = cvallbxMax;
  1178.     sRow.lpProps = rgsPropValue;
  1179.  
  1180.     /*
  1181.      *  Although assignment of szDisplay and szComment happen here, their actual
  1182.      *  values happen below in the for loop.
  1183.      */
  1184.     rgsPropValue[ivallbxPR_DISPLAY_NAME_A].ulPropTag = PR_DISPLAY_NAME_A;
  1185.     rgsPropValue[ivallbxPR_DISPLAY_NAME_A].Value.lpszA = szDisplay;
  1186.  
  1187.     rgsPropValue[ivallbxPR_COMMENT_A].ulPropTag = PR_COMMENT_A;
  1188.     rgsPropValue[ivallbxPR_COMMENT_A].Value.lpszA = szComment;
  1189.  
  1190.  
  1191.     /*
  1192.      *  For this release of MAPI the following two properties are required
  1193.      *  for all listboxes exposed in any details dialog.  This requirement is
  1194.      *  scheduled to be removed before ship
  1195.      */
  1196.     rgsPropValue[ivallbxPR_ENTRYID].ulPropTag = PR_ENTRYID;
  1197.     rgsPropValue[ivallbxPR_ENTRYID].Value.bin.lpb = (LPBYTE) &OptionsEntryID;
  1198.     rgsPropValue[ivallbxPR_ENTRYID].Value.bin.cb = CBOPTIONS_ENTRYID;
  1199.  
  1200.     rgsPropValue[ivallbxPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
  1201.     rgsPropValue[ivallbxPR_DISPLAY_TYPE].Value.l = 0;  /*  There are no defines for this yet */
  1202.  
  1203.  
  1204.     rgsPropValue[ivallbxPR_LISTBOX_VALUE].ulPropTag = PR_LISTBOX_VALUE;
  1205.  
  1206.     rgsPropValue[ivallbxPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
  1207.     rgsPropValue[ivallbxPR_INSTANCE_KEY].Value.bin.cb = sizeof(ULONG);
  1208.  
  1209.     /* fill up the table */
  1210.     for (uliRow = 0; uliRow < MAX_LISTBOX_ROWS; uliRow++)
  1211.     {
  1212.         wsprintfA(szDisplay, szFmtDisplay, uliRow);
  1213.         wsprintfA(szComment, szFmtComment, uliRow);
  1214.  
  1215.         OptionsEntryID.ulRowNumber = uliRow;
  1216.         rgsPropValue[ivallbxPR_LISTBOX_VALUE].Value.l = uliRow;
  1217.  
  1218.         rgsPropValue[ivallbxPR_INSTANCE_KEY].Value.bin.lpb = (LPBYTE) &uliRow;
  1219.  
  1220.         hResult = lpABUser->lpTDatListBox->lpVtbl->HrModifyRow(
  1221.             lpABUser->lpTDatListBox,
  1222.             &sRow);
  1223.         if (HR_FAILED(hResult))
  1224.         {
  1225.             /*
  1226.              *  Mask errors here...
  1227.              *  We want to do this because it's probibly still a valid
  1228.              *  table data object that I can get views from.  Most likely
  1229.              *  just some of the rows will be missing...
  1230.              */
  1231.             hResult = hrSuccess;
  1232.             break;
  1233.         }
  1234.         /*
  1235.          *  get rid of any warnings
  1236.          */
  1237.         hResult = hrSuccess;
  1238.     }
  1239.  
  1240.  
  1241. out:
  1242.  
  1243.     DebugTraceResult(hrBuildListBoxTable, hResult);
  1244.     return hResult;
  1245. }
  1246.  
  1247. /*
  1248.  *  Default column set for the dropdown listbox table
  1249.  */
  1250.  
  1251. enum {  ivalddPR_DISPLAY_NAME_A = 0,
  1252.         ivalddPR_ENTRYID,
  1253.         ivalddPR_DISPLAY_TYPE,
  1254.         ivalddPR_DDLISTBOX_VALUE,
  1255.         ivalddPR_INSTANCE_KEY,
  1256.         cvalddMax };
  1257.  
  1258. const SizedSPropTagArray(cvalddMax, tagaColSetDDListBox) =
  1259. {
  1260.     cvalddMax,
  1261.     {
  1262.         PR_DISPLAY_NAME_A,
  1263.         PR_ENTRYID,
  1264.         PR_DISPLAY_TYPE,
  1265.         PR_DDLISTBOX_VALUE,
  1266.         PR_INSTANCE_KEY
  1267.     }
  1268. };
  1269.  
  1270. HRESULT
  1271. HrBuildDDListBoxTable(LPABUSER lpABUser)
  1272. {
  1273.     SCODE sc;
  1274.     HRESULT hResult;
  1275.     SPropValue rgsPropValue[cvalddMax];
  1276.     SRow sRow;
  1277.     char szFmtDisplay[MAX_FMT_DD_DN];
  1278.     char szDisplay[MAX_FMT_DD_DN+2]; /* +2 for digits */
  1279.     ULONG uliRow;
  1280.     LPSTR pszFmtDisplay = (LPSTR) szFmtDisplay;
  1281.  
  1282.     /*
  1283.      *  Get resource strings
  1284.      */
  1285.     sc = ScLoadString(  IDS_FMT_DD_DN,
  1286.                         MAX_FMT_DD_DN,
  1287.                         NULL,
  1288.                         lpABUser->hLibrary,
  1289.                         (LPSTR *)&pszFmtDisplay );
  1290.     if (FAILED(sc))
  1291.     {
  1292.         hResult = ResultFromScode(sc);
  1293.         goto out;
  1294.     }
  1295.  
  1296.     /* Create a Table Data object */
  1297.     sc = CreateTable(
  1298.         (LPIID) &IID_IMAPITableData,
  1299.         lpABUser->lpAllocBuff,
  1300.         lpABUser->lpAllocMore,
  1301.         lpABUser->lpFreeBuff,
  1302.         lpABUser->lpMalloc,
  1303.         0,
  1304.         PR_DISPLAY_NAME_A,
  1305.         (LPSPropTagArray) &tagaColSetDDListBox,
  1306.         &(lpABUser->lpTDatDDListBox));
  1307.  
  1308.     if (FAILED(sc))
  1309.     {
  1310.         hResult = ResultFromScode(sc);
  1311.         goto out;
  1312.     }
  1313.  
  1314.     /* constants */
  1315.     sRow.cValues = cvalddMax;
  1316.     sRow.lpProps = rgsPropValue;
  1317.  
  1318.  
  1319.     /*
  1320.      *  Although assignment of szDisplay happens here, its actual
  1321.      *  values happen below in the for loop.
  1322.      */
  1323.     rgsPropValue[ivalddPR_DISPLAY_NAME_A].ulPropTag = PR_DISPLAY_NAME_A;
  1324.     rgsPropValue[ivalddPR_DISPLAY_NAME_A].Value.lpszA = szDisplay;
  1325.  
  1326.     /*
  1327.      *  For this release of MAPI the following two properties are required
  1328.      *  for all listboxes exposed in any details dialog.  This requirement is
  1329.      *  scheduled to be removed before ship
  1330.      */
  1331.     rgsPropValue[ivalddPR_ENTRYID].ulPropTag = PR_ENTRYID;
  1332.     rgsPropValue[ivalddPR_ENTRYID].Value.bin.lpb = (LPBYTE) &OptionsEntryID;
  1333.     rgsPropValue[ivalddPR_ENTRYID].Value.bin.cb = CBOPTIONS_ENTRYID;
  1334.  
  1335.     rgsPropValue[ivalddPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
  1336.     rgsPropValue[ivalddPR_DISPLAY_TYPE].Value.l = 0;
  1337.     
  1338.  
  1339.     rgsPropValue[ivalddPR_DDLISTBOX_VALUE].ulPropTag = PR_DDLISTBOX_VALUE;
  1340.  
  1341.     rgsPropValue[ivalddPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
  1342.     rgsPropValue[ivalddPR_INSTANCE_KEY].Value.bin.cb = sizeof(ULONG);
  1343.  
  1344.     /* fill up the table */
  1345.     for (uliRow = 0; uliRow < 25; uliRow++)
  1346.     {
  1347.         wsprintfA(szDisplay, szFmtDisplay, uliRow);
  1348.  
  1349.         OptionsEntryID.ulRowNumber = uliRow;
  1350.         rgsPropValue[ivalddPR_DDLISTBOX_VALUE].Value.l = uliRow;
  1351.         
  1352.         rgsPropValue[ivalddPR_INSTANCE_KEY].Value.bin.lpb = (LPBYTE) &uliRow;
  1353.  
  1354.         hResult = lpABUser->lpTDatDDListBox->lpVtbl->HrModifyRow(
  1355.             lpABUser->lpTDatDDListBox,
  1356.             &sRow);
  1357.         if (HR_FAILED(hResult))
  1358.         {
  1359.             /*
  1360.              *  Mask errors here...
  1361.              *  We want to do this because it's probibly still a valid
  1362.              *  table data object that I can get views from.  Most likely
  1363.              *  just some of the rows will be missing...
  1364.              */
  1365.  
  1366.             hResult = hrSuccess;
  1367.             break;
  1368.         }
  1369.         /*
  1370.          *  get rid of any warnings
  1371.          */
  1372.         hResult = hrSuccess;
  1373.     }
  1374.  
  1375. out:
  1376.  
  1377.     DebugTraceResult(HrBuildDDListBoxTable, hResult);
  1378.     return hResult;
  1379. }
  1380.  
  1381. /*
  1382.  *  Default column set for the combobox table
  1383.  */
  1384. enum { ivalcbPR_DISPLAY_NAME_A = 0,
  1385.         ivalcbPR_ENTRYID,
  1386.         ivalcbPR_DISPLAY_TYPE,
  1387.         ivalcbPR_COMBOBOX_VALUE,
  1388.         ivalcbPR_INSTANCE_KEY,
  1389.         cvalcbMax };
  1390.  
  1391. const SizedSPropTagArray(cvalcbMax, tagaColSetComboBox) =
  1392. {
  1393.     cvalcbMax,
  1394.     {
  1395.         PR_DISPLAY_NAME_A,
  1396.         PR_ENTRYID,
  1397.         PR_DISPLAY_TYPE,
  1398.         PR_COMBOBOX_VALUE,
  1399.         PR_INSTANCE_KEY
  1400.     }
  1401. };
  1402.  
  1403. HRESULT
  1404. HrBuildComboBoxTable(LPABUSER lpABUser)
  1405. {
  1406.     SCODE sc;
  1407.     HRESULT hResult;
  1408.     SPropValue rgsPropValue[cvalcbMax];
  1409.     SRow sRow;
  1410.     char szFmtDisplay[MAX_FMT_COMBO_DN];
  1411.     char szDisplay[MAX_FMT_COMBO_DN + 2]; /* +2 for digits */
  1412.     ULONG uliRow;
  1413.     LPSTR pszFmtDisplay = (LPSTR) szFmtDisplay;
  1414.  
  1415.     /*
  1416.      *  Get resource strings
  1417.      */
  1418.     sc = ScLoadString(  IDS_FMT_COMBO_DN,
  1419.                         MAX_FMT_COMBO_DN,
  1420.                         NULL,
  1421.                         lpABUser->hLibrary,
  1422.                         (LPSTR *) &pszFmtDisplay );
  1423.     if (FAILED(sc))
  1424.     {
  1425.         hResult = ResultFromScode(sc);
  1426.         goto out;
  1427.     }
  1428.  
  1429.     /* Create a table data object */
  1430.     sc = CreateTable(
  1431.         (LPIID) &IID_IMAPITableData,
  1432.         lpABUser->lpAllocBuff,
  1433.         lpABUser->lpAllocMore,
  1434.         lpABUser->lpFreeBuff,
  1435.         lpABUser->lpMalloc,
  1436.         0,
  1437.         PR_DISPLAY_NAME_A,
  1438.         (LPSPropTagArray) &tagaColSetComboBox,
  1439.         &(lpABUser->lpTDatComboBox));
  1440.  
  1441.     if (FAILED(sc))
  1442.     {
  1443.         hResult = ResultFromScode(sc);
  1444.         goto out;
  1445.     }
  1446.  
  1447.     /* constants */
  1448.     sRow.cValues = cvalcbMax;
  1449.     sRow.lpProps = rgsPropValue;
  1450.  
  1451.     /*
  1452.      *  Although assignment of szDisplay happens here, its actual
  1453.      *  values happen below in the for loop.
  1454.      */
  1455.     rgsPropValue[ivalcbPR_DISPLAY_NAME_A].ulPropTag = PR_DISPLAY_NAME_A;
  1456.     rgsPropValue[ivalcbPR_DISPLAY_NAME_A].Value.lpszA = szDisplay;
  1457.  
  1458.  
  1459.     /*
  1460.      *  For this release of MAPI the following two properties are required
  1461.      *  for all listboxes exposed in any details dialog.  This requirement is
  1462.      *  scheduled to be removed before ship
  1463.      */
  1464.     rgsPropValue[ivalcbPR_ENTRYID].ulPropTag = PR_ENTRYID;
  1465.     rgsPropValue[ivalcbPR_ENTRYID].Value.bin.lpb = (LPBYTE) &OptionsEntryID;
  1466.     rgsPropValue[ivalcbPR_ENTRYID].Value.bin.cb = CBOPTIONS_ENTRYID;
  1467.  
  1468.     rgsPropValue[ivalcbPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
  1469.     rgsPropValue[ivalcbPR_DISPLAY_TYPE].Value.l = 0;
  1470.  
  1471.     rgsPropValue[ivalcbPR_COMBOBOX_VALUE].ulPropTag = PR_COMBOBOX_VALUE;
  1472.     rgsPropValue[ivalcbPR_COMBOBOX_VALUE].Value.lpszA = szDisplay;
  1473.  
  1474.     rgsPropValue[ivalcbPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
  1475.     rgsPropValue[ivalcbPR_INSTANCE_KEY].Value.bin.cb = sizeof(ULONG);
  1476.  
  1477.  
  1478.     /* fill up the table */
  1479.     for (uliRow = 0; uliRow < 25; uliRow++)
  1480.     {
  1481.         wsprintfA(szDisplay, szFmtDisplay, uliRow);
  1482.  
  1483.         OptionsEntryID.ulRowNumber = uliRow;
  1484.  
  1485.         rgsPropValue[ivalcbPR_INSTANCE_KEY].Value.bin.lpb = (LPBYTE) &uliRow;
  1486.  
  1487.         hResult = lpABUser->lpTDatComboBox->lpVtbl->HrModifyRow(
  1488.             lpABUser->lpTDatComboBox,
  1489.             &sRow);
  1490.         if (HR_FAILED(hResult))
  1491.         {
  1492.             /*
  1493.              *  Mask errors here...
  1494.              *  We want to do this because it's probibly still a valid
  1495.              *  table data object that I can get views from.  Most likely
  1496.              *  just some of the rows will be missing...
  1497.              */
  1498.  
  1499.             hResult = hrSuccess;
  1500.             break;
  1501.         }
  1502.  
  1503.         /*
  1504.          *  get rid of any warnings
  1505.          */
  1506.         hResult = hrSuccess;
  1507.     }
  1508.  
  1509. out:
  1510.     DebugTraceResult(HrBuildComboBoxTable, hResult);
  1511.     return hResult;
  1512. }
  1513.