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

Windows编程

开发平台:

Visual C++

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