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

  1. /***********************************************************************
  2.  *
  3.  *  ABCTBL2.C
  4.  *
  5.  *  Contents Table - Part 2.
  6.  *
  7.  *
  8.  *  The following routines are implemented in this file.
  9.  *
  10.  *
  11.  *      IVTABC_SeekRow
  12.  *      IVTABC_SeekRowApprox
  13.  *      IVTABC_GetRowCount
  14.  *      IVTABC_QueryPosition
  15.  *      IVTABC_FindRow
  16.  *      IVTABC_Restrict
  17.  *      IVTABC_QueryRows
  18.  *
  19.  *
  20.  *
  21.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  22.  *
  23.  ***********************************************************************/
  24.  
  25. #include "abp.h"
  26. #include "abctbl.h"
  27. #include "sampabp.rh"
  28.  
  29. /*************************************************************************
  30.  *
  31.  -  IVTABC_SeekRow
  32.  -
  33.  *
  34.  *  Tries to seek an appropriate number of rows.
  35.  *
  36.  *
  37.  */
  38. STDMETHODIMP 
  39. IVTABC_SeekRow(LPIVTABC lpIVTAbc,
  40.     BOOKMARK bkOrigin,
  41.     LONG lRowCount,
  42.     LONG * lplRowsSought)
  43. {
  44.     LONG lNewPos;
  45.     LONG lMoved;
  46.     LONG lDelta;
  47.     LONG lLast;
  48.     HRESULT hResult = hrSuccess;
  49.  
  50.     /*
  51.      *  Validate parameters
  52.      */
  53.  
  54.     /*
  55.      *  Check to see if it's large enough to hold this object
  56.      */
  57.     if (IsBadReadPtr(lpIVTAbc, sizeof(IVTABC)))
  58.     {
  59.         /*
  60.          *  Not large enough
  61.          */
  62.         hResult = ResultFromScode(E_INVALIDARG);
  63.  
  64.         DebugTraceResult(IVTABC_SeekRow, hResult);
  65.         return hResult;
  66.     }
  67.  
  68.     /*
  69.      *  Check to see that it's the correct vtbl
  70.      */
  71.     if (lpIVTAbc->lpVtbl != &vtblIVTABC)
  72.     {
  73.         /*
  74.          *  Not my vtbl
  75.          */
  76.         hResult = ResultFromScode(E_INVALIDARG);
  77.  
  78.         DebugTraceResult(IVTABC_SeekRow, hResult);
  79.         return hResult;
  80.     }
  81.  
  82.     /*
  83.      *  Check the out parameter for writability (if requested)
  84.      */
  85.     if (lplRowsSought &&
  86.         IsBadWritePtr(lplRowsSought, sizeof(LONG)))
  87.     {
  88.         hResult = ResultFromScode(E_INVALIDARG);
  89.  
  90.         DebugTraceResult(IVTABC_SeekRow, hResult);
  91.         return hResult;
  92.     }
  93.  
  94.  
  95.     EnterCriticalSection(&lpIVTAbc->cs);
  96.  
  97.  
  98.  
  99.     if (bkOrigin == BOOKMARK_BEGINNING)
  100.     {
  101.         lNewPos = 0;
  102.  
  103.     }
  104.     else if (bkOrigin == BOOKMARK_CURRENT)
  105.     {
  106.         lNewPos = lpIVTAbc->ulPosition;
  107.  
  108.     }
  109.     else if (bkOrigin == BOOKMARK_END)
  110.     {
  111.         lNewPos = lpIVTAbc->ulMaxPos;
  112.  
  113.     }
  114.     else
  115.     {
  116.         ULONG ulBK = (ULONG) bkOrigin - 3;
  117.         LPABCBK lpABCBK = NULL;
  118.  
  119.         /*
  120.          *  See if it's out of range
  121.          */
  122.         if (ulBK < 0 || ulBK >= MAX_BOOKMARKS)
  123.         {
  124.             /*
  125.              *  bad book mark, it's an error, so...
  126.              */
  127.             hResult = ResultFromScode(E_INVALIDARG);
  128.  
  129.             goto out;
  130.         }
  131.  
  132.         if (!(lpABCBK = lpIVTAbc->rglpABCBK[ulBK]))
  133.         {
  134.             /*
  135.              *  bookmark has not been allocated
  136.              */
  137.             hResult = ResultFromScode(MAPI_E_INVALID_BOOKMARK);
  138.  
  139.             goto out;
  140.         }
  141.  
  142.         /* Not validating existing bookmark  */
  143.         lNewPos = lpABCBK->ulPosition;
  144.     }
  145.  
  146.     /*
  147.      *  Figure out what endpoint to use and what direction to go to
  148.      *  get there.
  149.      */
  150.     if (lRowCount < 0)
  151.     {
  152.         lLast = 0;
  153.         lDelta = -1;
  154.     }
  155.     else
  156.     {
  157.         lLast = lpIVTAbc->ulMaxPos;
  158.         lDelta = 1;
  159.     }
  160.  
  161.     /*
  162.      *  While there's rows to seek ...
  163.      */
  164.     lMoved = 0;
  165.     while (lNewPos != lLast &&
  166.         lMoved != lRowCount)
  167.     {
  168.         lNewPos += lDelta;
  169.  
  170.         /*
  171.          *  Unrestricted list is easy: just seek.  Also, if the next
  172.          *  'row' is the end of the table, just go there; don't want
  173.          *  to check it against any restriction.
  174.          */
  175.         if (!lpIVTAbc->lpszPartialName ||
  176.             lNewPos == (LONG) lpIVTAbc->ulMaxPos)
  177.         {
  178.             lMoved += lDelta;
  179.         }
  180.  
  181.         /*
  182.          *  Otherwise, deal with the restricted list:  only count
  183.          *  the row if it's in the restriction.
  184.          */
  185.         else
  186.         {
  187.             if (!FChecked(lpIVTAbc, (ULONG) lNewPos))
  188.             {
  189.                 hResult = HrValidateEntry(lpIVTAbc, (ULONG) lNewPos);
  190.  
  191.                 if (HR_FAILED(hResult))
  192.                 {
  193.                     goto out;
  194.                 }
  195.             }
  196.  
  197.             if (FMatched(lpIVTAbc, (ULONG) lNewPos))
  198.             {
  199.                 lMoved += lDelta;
  200.             }
  201.         }
  202.     }
  203.  
  204.     if (lplRowsSought)
  205.         *lplRowsSought = lMoved;
  206.  
  207.     lpIVTAbc->ulPosition = lNewPos;
  208.  
  209. out:
  210.     LeaveCriticalSection(&lpIVTAbc->cs);
  211.  
  212.     DebugTraceResult(IVTABC_SeekRow, hResult);
  213.     return hResult;
  214.  
  215. }
  216.  
  217. /*************************************************************************
  218.  *
  219.  -  IVTABC_SeekRowApprox
  220.  -
  221.  *  Tries to set the position of the table according to the approximate
  222.  *  position passed in.
  223.  *
  224.  *
  225.  */
  226. STDMETHODIMP 
  227. IVTABC_SeekRowApprox(LPIVTABC lpIVTAbc,
  228.     ULONG ulNumerator,
  229.     ULONG ulDenominator)
  230. {
  231.     HRESULT hResult = hrSuccess;
  232.     ULONG iByte;
  233.     BYTE bCount;
  234.     ULONG ulPos = 0;
  235.     ULONG ulCount = 0;
  236.  
  237.     /*
  238.      *  Validate parameters
  239.      */
  240.  
  241.     /*
  242.      *  Check to see if it's large enough to hold this object
  243.      */
  244.     if (IsBadReadPtr(lpIVTAbc, sizeof(IVTABC)))
  245.     {
  246.         /*
  247.          *  Not large enough
  248.          */
  249.         hResult = ResultFromScode(E_INVALIDARG);
  250.  
  251.         DebugTraceResult(IVTABC_SeekRowApprox, hResult);
  252.         return hResult;
  253.     }
  254.  
  255.     /*
  256.      *  Check to see that it's the correct vtbl
  257.      */
  258.     if (lpIVTAbc->lpVtbl != &vtblIVTABC)
  259.     {
  260.         /*
  261.          *  Not my vtbl
  262.          */
  263.         hResult = ResultFromScode(E_INVALIDARG);
  264.  
  265.         DebugTraceResult(IVTABC_SeekRowApprox, hResult);
  266.         return hResult;
  267.     }
  268.  
  269.     /*
  270.      *  0 denominator is not allowed
  271.      */
  272.     if (!ulDenominator)
  273.     {
  274.         hResult = ResultFromScode(E_INVALIDARG);
  275.  
  276.         DebugTraceResult(IVTABC_SeekRowApprox, hResult);
  277.         return hResult;
  278.     }
  279.  
  280.  
  281.     EnterCriticalSection(&lpIVTAbc->cs);
  282.  
  283.  
  284.     if (ulNumerator >= ulDenominator)
  285.     {
  286.         /*  We're at the end of the list */
  287.         lpIVTAbc->ulPosition = lpIVTAbc->ulMaxPos;
  288.  
  289.         hResult = hrSuccess;
  290.         goto out;
  291.     }
  292.  
  293.     /*
  294.      *  Since I'm using muldiv() which takes ints/longs, I should shift right
  295.      *  so that I don't incorrectly call it.
  296.      *  I'm really just checking to see if the sign bit is set...
  297.      */
  298.  
  299.     if (((long)ulNumerator < 0) || ((long)ulDenominator < 0))
  300.     {
  301.         ulNumerator >>= 1;
  302.         ulDenominator >>= 1;
  303.     }
  304.  
  305.     if (!lpIVTAbc->lpszPartialName)
  306.     {
  307.         /*
  308.          *  The NON-Restriction method
  309.          */
  310.  
  311.         lpIVTAbc->ulPosition = MULDIV(lpIVTAbc->ulMaxPos, ulNumerator,
  312.             ulDenominator);
  313.  
  314.         hResult = hrSuccess;
  315.         goto out;
  316.     }
  317.  
  318.     /*
  319.      *  Restriction method
  320.      */
  321.  
  322.     /*  Figure out % of which corresponds with numerator. */
  323.     ulCount = MULDIV(lpIVTAbc->ulRstrDenom, ulNumerator, ulDenominator);
  324.  
  325.     /*  Count bits in rgMatched until I match numerator */
  326.  
  327.     for (iByte = 0; iByte < (lpIVTAbc->ulMaxPos / 8); iByte++)
  328.     {
  329.         CBitsB(lpIVTAbc->rgMatched[iByte], bCount); /* <-- MACRO  */
  330.         ulPos += (ULONG) bCount;
  331.  
  332.         if (ulPos >= ulCount)
  333.         {
  334.             ulPos -= bCount;    /* Go back a byte */
  335.             break;
  336.         }
  337.     }
  338.  
  339.     /*  My current position is there. */
  340.     lpIVTAbc->ulPosition = iByte * 8;
  341.  
  342.  
  343. out:
  344.     LeaveCriticalSection(&lpIVTAbc->cs);
  345.  
  346.     DebugTraceResult(IVTABC_SeekRowApprox, hResult);
  347.     return hResult;
  348.  
  349. }
  350.  
  351. /*************************************************************************
  352.  *
  353.  -  IVTABC_GetRowCount
  354.  -
  355.  *
  356.  *  If there's a restriction applied, I don't necessarily know how many
  357.  *  rows there are...
  358.  */
  359.  
  360. STDMETHODIMP 
  361. IVTABC_GetRowCount(LPIVTABC lpIVTAbc,
  362.     ULONG ulFlags,
  363.     ULONG * lpulCount)
  364. {
  365.     HRESULT hResult;
  366.  
  367.     /*
  368.      *  Validate parameters
  369.      */
  370.  
  371.     /*
  372.      *  Check to see if it's large enough to hold this object
  373.      */
  374.     if (IsBadReadPtr(lpIVTAbc, sizeof(IVTABC)))
  375.     {
  376.         /*
  377.          *  Not large enough
  378.          */
  379.         hResult = ResultFromScode(E_INVALIDARG);
  380.  
  381.         DebugTraceResult(IVTABC_GetRowCount, hResult);
  382.         return hResult;
  383.     }
  384.  
  385.     /*
  386.      *  Check to see that it's the correct vtbl
  387.      */
  388.     if (lpIVTAbc->lpVtbl != &vtblIVTABC)
  389.     {
  390.         /*
  391.          *  Not my vtbl
  392.          */
  393.         hResult = ResultFromScode(E_INVALIDARG);
  394.  
  395.         DebugTraceResult(IVTABC_GetRowCount, hResult);
  396.         return hResult;
  397.     }
  398.  
  399.     /*
  400.      *  Check the out parameters for writability
  401.      */
  402.     if (IsBadWritePtr(lpulCount, sizeof(ULONG)))
  403.     {
  404.         hResult = ResultFromScode(E_INVALIDARG);
  405.  
  406.         DebugTraceResult(IVTABC_GetRowCount, hResult);
  407.         return hResult;
  408.     }
  409.  
  410.     if (ulFlags & ~TBL_NOWAIT)
  411.     {
  412.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  413.  
  414.         DebugTraceResult(IVTABC_GetRowCount, hResult);
  415.         return hResult;
  416.     }
  417.  
  418.  
  419.     EnterCriticalSection(&lpIVTAbc->cs);
  420.  
  421.     /*
  422.      *  If there's no restriction, you can actually calculate this..
  423.      */
  424.     if (!lpIVTAbc->lpszPartialName)
  425.     {
  426.  
  427.         /*
  428.          *  Number of actual rows
  429.          */
  430.         *lpulCount = lpIVTAbc->ulMaxPos;
  431.         hResult = hrSuccess;
  432.         goto out;
  433.     }
  434.  
  435.     /*
  436.      *  There's no way that I can tell how many actual entries there
  437.      *  are without counting them.  That takes way too long, so we give
  438.      *  the client our best guess.
  439.      */
  440.  
  441.     *lpulCount = lpIVTAbc->ulRstrDenom;
  442.  
  443.     /*
  444.      *  Then we warn the client that this count may not be accurate
  445.      */
  446.     
  447.     hResult = ResultFromScode(MAPI_W_APPROX_COUNT);
  448.  
  449. out:
  450.     LeaveCriticalSection(&lpIVTAbc->cs);
  451.  
  452.     DebugTraceResult(IVTABC_GetRowCount, hResult);
  453.     return hResult;
  454. }
  455.  
  456. /*************************************************************************
  457.  *
  458.  -  IVTABC_QueryPosition
  459.  -
  460.  *  Figures out the current fractional position
  461.  *
  462.  *
  463.  *
  464.  */
  465. STDMETHODIMP 
  466. IVTABC_QueryPosition(LPIVTABC lpIVTAbc,
  467.     ULONG * lpulRow,
  468.     ULONG * lpulNumerator,
  469.     ULONG * lpulDenominator)
  470. {
  471.     HRESULT hResult = hrSuccess;
  472.  
  473.     /*
  474.      *  Validate parameters
  475.      */
  476.  
  477.     /*
  478.      *  Check to see if it's large enough to hold this object
  479.      */
  480.     if (IsBadReadPtr(lpIVTAbc, sizeof(IVTABC)))
  481.     {
  482.         /*
  483.          *  Not large enough
  484.          */
  485.         hResult = ResultFromScode(E_INVALIDARG);
  486.  
  487.         DebugTraceResult(IVTABC_QueryPosition, hResult);
  488.         return hResult;
  489.     }
  490.  
  491.     /*
  492.      *  Check to see that it's the correct vtbl
  493.      */
  494.     if (lpIVTAbc->lpVtbl != &vtblIVTABC)
  495.     {
  496.         /*
  497.          *  Not my vtbl
  498.          */
  499.         hResult = ResultFromScode(E_INVALIDARG);
  500.  
  501.         DebugTraceResult(IVTABC_QueryPosition, hResult);
  502.         return hResult;
  503.     }
  504.  
  505.     /*
  506.      *  Check the out parameters for writability
  507.      */
  508.     if (IsBadWritePtr(lpulRow, sizeof(ULONG))
  509.         || IsBadWritePtr(lpulNumerator, sizeof(ULONG))
  510.         || IsBadWritePtr(lpulDenominator, sizeof(ULONG)))
  511.     {
  512.         hResult = ResultFromScode(E_INVALIDARG);
  513.  
  514.         DebugTraceResult(IVTABC_QueryPosition, hResult);
  515.         return hResult;
  516.     }
  517.  
  518.  
  519.     EnterCriticalSection(&lpIVTAbc->cs);
  520.  
  521.  
  522.     /*  ...I don't have a restriction  */
  523.     if (!lpIVTAbc->lpszPartialName)
  524.     {
  525.         *lpulRow = lpIVTAbc->ulPosition;
  526.  
  527.         *lpulNumerator = lpIVTAbc->ulPosition;
  528.         *lpulDenominator = lpIVTAbc->ulMaxPos;
  529.     }
  530.     else
  531.     {
  532.         BYTE bCount = 0;
  533.         BYTE bFrag;
  534.         ULONG iByte;
  535.  
  536.         /*
  537.          *  Zero out fraction
  538.          */
  539.         *lpulNumerator = 0;
  540.  
  541.         /*
  542.          *  Set denominator that we've been keeping track of.
  543.          */
  544.         *lpulDenominator = (lpIVTAbc->ulRstrDenom ? lpIVTAbc->ulRstrDenom : 1);
  545.  
  546.         /*
  547.          *  Handle corner case - we're at the beginning of the list...
  548.          */
  549.         if (lpIVTAbc->ulPosition == 0)
  550.         {
  551.             *lpulRow = 0;
  552.             goto out;
  553.         }
  554.  
  555.         /*
  556.          *  Calculate Numerator
  557.          *  We use the rgMatched bit array and count the bits up to
  558.          *  our current position (lpIVTAbc->ulPosition).
  559.          *
  560.          */
  561.         for (iByte = 0; iByte < (lpIVTAbc->ulPosition / 8); iByte++)
  562.         {
  563.             CBitsB(lpIVTAbc->rgMatched[iByte], bCount); /* <-- MACRO  */
  564.             *lpulNumerator += (ULONG) bCount;
  565.         }
  566.         /*  Count the fragment  */
  567.         bFrag = lpIVTAbc->rgMatched[iByte];
  568.         bFrag = bFrag >> (8 - (lpIVTAbc->ulPosition % 8));
  569.  
  570.         CBitsB(bFrag, bCount);
  571.         *lpulNumerator += (ULONG) bCount;
  572.  
  573.         /*
  574.          *  Good guess here...
  575.          */
  576.         *lpulRow = *lpulNumerator;
  577.  
  578.     }
  579.  
  580. out:
  581.  
  582.     LeaveCriticalSection(&lpIVTAbc->cs);
  583.  
  584.     DebugTraceResult(IVTABC_QueryPosition, hResult);
  585.     return hResult;
  586. }
  587.  
  588. /*************************************************************************
  589.  *
  590.  -  IVTABC_FindRow
  591.  -
  592.  *
  593.  *  Prefix searches to find a row
  594.  *
  595.  *
  596.  */
  597. STDMETHODIMP 
  598. IVTABC_FindRow(LPIVTABC lpIVTAbc,
  599.     LPSRestriction lpRestriction,
  600.     BOOKMARK bkOrigin,
  601.     ULONG ulFlags)
  602. {
  603.     HRESULT hResult = hrSuccess;
  604.  
  605.     ULONG cbRead;
  606.     ABCREC abcrec;
  607.     LONG lpos;
  608.     ULONG fFound = FALSE;
  609.     LPSTR szPrefix;
  610.     int nCmpResult;
  611.  
  612.     ULONG ulCurMin;
  613.     ULONG ulCurMac;
  614.     ULONG ulPosT;
  615.  
  616.     /*
  617.      *  Validate parameters
  618.      */
  619.  
  620.     /*
  621.      *  Check to see if it's large enough to hold this object
  622.      */
  623.     if (IsBadReadPtr(lpIVTAbc, sizeof(IVTABC)))
  624.     {
  625.         /*
  626.          *  Not large enough
  627.          */
  628.         hResult = ResultFromScode(E_INVALIDARG);
  629.  
  630.         DebugTraceResult(IVTABC_FindRow, hResult);
  631.         return hResult;
  632.     }
  633.  
  634.     /*
  635.      *  Check to see that it's the correct vtbl
  636.      */
  637.     if (lpIVTAbc->lpVtbl != &vtblIVTABC)
  638.     {
  639.         /*
  640.          *  Not my vtbl
  641.          */
  642.         hResult = ResultFromScode(E_INVALIDARG);
  643.  
  644.         DebugTraceResult(IVTABC_FindRow, hResult);
  645.         return hResult;
  646.     }
  647.  
  648.     /*
  649.      *  Check flags
  650.      */
  651.     if (ulFlags & ~DIR_BACKWARD)
  652.     {
  653.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  654.  
  655.         DebugTraceResult(IVTABC_FindRow, hResult);
  656.         return hResult;
  657.     }
  658.  
  659.     /*
  660.      *  I don't go backwards, yet.
  661.      */
  662.     if (ulFlags & DIR_BACKWARD)
  663.     {
  664.         hResult = ResultFromScode(MAPI_E_NO_SUPPORT);
  665.  
  666.         DebugTraceResult(IVTABC_FindRow, hResult);
  667.         return hResult;
  668.     }
  669.  
  670.  
  671.     EnterCriticalSection(&lpIVTAbc->cs);
  672.  
  673.     /*
  674.      *  Open the file
  675.      */
  676.     hResult = HrOpenFile(lpIVTAbc);
  677.     if (HR_FAILED(hResult))
  678.     {
  679.         goto out;
  680.     }
  681.  
  682.     /*
  683.      *  initialize
  684.      */
  685.     ulCurMin = lpIVTAbc->ulPosition;
  686.     ulCurMac = lpIVTAbc->ulMaxPos;
  687.  
  688.     /*
  689.      *  I handle two type of restrictions: 
  690.      *      prefix searching on Display Names
  691.      *      Finding a row based on it's instance key
  692.      */
  693.  
  694.     /*
  695.      *  The prefix search on display name restriction looks like:
  696.      *
  697.      *  +-----------------
  698.      *  | RES_PROPERTY
  699.      *  +-----------------
  700.      *  | RELOP_GE
  701.      *  +-----------------
  702.      *  | PR_DISPLAY_NAME
  703.      *  +-----------------
  704.      *  | LPSPropVal   -----+
  705.      *  +-----------------  |
  706.      *                      |   +-------------------------
  707.      *                      +-->| PR_DISPLAY_NAME
  708.      *                          +-------------------------
  709.      *                          | 0 <-- for alignment (don't care)
  710.      *                          +-------------------------
  711.      *                          | lpszA <-- prefix for display name
  712.      *                          +-------------------------
  713.      *
  714.      *
  715.      *
  716.      *              -OR-
  717.      *
  718.      *  Find a row based on it's instance key
  719.      *
  720.      *  +-----------------
  721.      *  | RES_PROPERTY
  722.      *  +-----------------
  723.      *  | RELOP_EQ
  724.      *  +-----------------
  725.      *  | PR_INSTANCE_KEY
  726.      *  +-----------------
  727.      *  | LPSPropVal   -----+
  728.      *  +-----------------  |
  729.      *                      |   +-------------------------
  730.      *                      +-->| PR_INSTANCE_KEY
  731.      *                          +-------------------------
  732.      *                          |     | cbInstanceKey
  733.      *                          + bin +-------------------
  734.      *                          |     | lpbInstanceKey
  735.      *                          +-------------------------
  736.      *
  737.      *
  738.      *  If it doesn't look like one of these, return MAPI_E_TOO_COMPLEX.
  739.      */
  740.  
  741.     /*
  742.      *  Both restrictions require this one
  743.      */
  744.     if (lpRestriction->rt != RES_PROPERTY)
  745.     {
  746.         hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
  747.  
  748.         goto out;
  749.     }
  750.  
  751.  
  752.     /*
  753.      *  Look for Instance Key first - it's easiest to handle
  754.      */
  755.     if (lpRestriction->res.resProperty.relop == RELOP_EQ)
  756.     {
  757.         LPABCRecInstance lpABCRecInstance;
  758.         
  759.         if (lpRestriction->res.resProperty.ulPropTag != PR_INSTANCE_KEY)
  760.         {
  761.             /*
  762.              *  Clearly something we don't recognize
  763.              */
  764.             hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
  765.  
  766.             goto out;
  767.         }
  768.  
  769.         /*
  770.          *  Crack the bin part of this restriction and
  771.          *  see if we can still find our way back to this
  772.          *  record - quickly...
  773.          */
  774.         lpABCRecInstance = (LPABCRecInstance) lpRestriction->res.resProperty.lpProp->Value.bin.lpb;
  775.  
  776.         /*
  777.          *  First check to see that we're browsing the same file
  778.          */
  779.         if (lstrcmp(lpABCRecInstance->rgchzFileName, lpIVTAbc->lpszFileName))
  780.         {
  781.             /*
  782.              *  Nope, different names, return not found and leave our position alone...
  783.              */
  784.             hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  785.             goto out;
  786.         }
  787.  
  788.         /*
  789.          *  Ok, so we think we're browsing the same file.  Has it been modified since the
  790.          *  last time we looked?
  791.          */
  792.         if (memcmp(&(lpABCRecInstance->filetime), &(lpIVTAbc->filetime), sizeof (FILETIME)))
  793.         {
  794.             /*
  795.              *  Nope, they're different, so no guarantees here...
  796.              */
  797.             hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  798.             goto out;
  799.         }
  800.  
  801.         /*
  802.          *  Now, I feel pretty confident about this instance key.  Just set my current position
  803.          *  and go for it.
  804.          */
  805.         lpIVTAbc->ulPosition = lpABCRecInstance->ulRecordPosition;
  806.  
  807.         /* Done */
  808.         goto out;
  809.  
  810.     }
  811.             
  812.     /*
  813.      *  Now we're looking for prefix searching on display name
  814.      */
  815.     if (lpRestriction->res.resProperty.relop != RELOP_GE)
  816.     {
  817.         hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
  818.  
  819.         goto out;
  820.     }
  821.  
  822.     if (lpRestriction->res.resProperty.ulPropTag != PR_DISPLAY_NAME_A)
  823.     {
  824.         hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
  825.  
  826.         goto out;
  827.     }
  828.  
  829.     szPrefix = lpRestriction->res.resProperty.lpProp->Value.lpszA;
  830.  
  831.     if (bkOrigin == BOOKMARK_BEGINNING)
  832.     {
  833.         ulCurMin = 0;
  834.  
  835.     }
  836.     else if (bkOrigin == BOOKMARK_END)
  837.     {
  838.         ulCurMin = lpIVTAbc->ulMaxPos;
  839.  
  840.     }
  841.     else if (bkOrigin != BOOKMARK_CURRENT)
  842.     {
  843.         ULONG ulBK = (ULONG) bkOrigin - 3;
  844.         LPABCBK lpABCBK = NULL;
  845.  
  846.         /*
  847.          *  See if it's out of range
  848.          */
  849.         if (ulBK < 0 || ulBK >= MAX_BOOKMARKS)
  850.         {
  851.             /*
  852.              *  bad book mark, it's an error, so...
  853.              */
  854.             hResult = ResultFromScode(E_INVALIDARG);
  855.  
  856.             goto out;
  857.         }
  858.  
  859.         if (!(lpABCBK = lpIVTAbc->rglpABCBK[ulBK]))
  860.         {
  861.             /*
  862.              *  bookmark has not been allocated
  863.              */
  864.             hResult = ResultFromScode(MAPI_E_INVALID_BOOKMARK);
  865.  
  866.             goto out;
  867.         }
  868.  
  869.         /*  Not validating existing bookmark  */
  870.         ulCurMin = lpABCBK->ulPosition;
  871.     }
  872.  
  873.     while (ulCurMin < ulCurMac)
  874.     {
  875.         /*
  876.          *  Look for a row which matches the table restriction (if any).
  877.          */
  878.         ulPosT = (ulCurMin + ulCurMac) / 2;
  879.  
  880.         lpos = (long)((long)ulPosT * (long)sizeof(ABCREC));
  881.  
  882.         SetFilePointer(lpIVTAbc->hFile, lpos, NULL, FILE_BEGIN);
  883.  
  884.         /*  Read in the record at that location  */
  885.         if (!ReadFile(lpIVTAbc->hFile, (LPVOID) &abcrec,
  886.                 sizeof(ABCREC), &cbRead, NULL))
  887.         {
  888.             hResult = ResultFromScode(MAPI_E_DISK_ERROR);
  889.             SetErrorIDS(lpIVTAbc, hResult, IDS_SAB_NO_READ);
  890.  
  891.             goto out;
  892.         }
  893.  
  894.         /*
  895.          *  I want case insensitive comparisons here...
  896.          */
  897.         nCmpResult = lstrcmpi(szPrefix, abcrec.rgchDisplayName);
  898.  
  899.         if (nCmpResult > 0)
  900.         {
  901.             ulCurMin = ulPosT + 1;
  902.         }
  903.         else
  904.         {
  905.             ulCurMac = ulPosT;
  906.             if (!lpIVTAbc->lpszPartialName ||
  907.                 FNameMatch(lpIVTAbc, abcrec.rgchDisplayName))
  908.             {
  909.                 fFound = TRUE;
  910.             }
  911.         }
  912.     }
  913.  
  914.     /*
  915.      *  If I didn't find a row, return MAPI_E_NOT_FOUND.
  916.      */
  917.     if (!fFound)
  918.     {
  919.         hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  920.  
  921.         goto out;
  922.     }
  923.  
  924.     /*
  925.      *  Otherwise, set the current position to the row found.
  926.      */
  927.     lpIVTAbc->ulPosition = ulCurMac;
  928.  
  929. out:
  930.     LeaveCriticalSection(&lpIVTAbc->cs);
  931.  
  932.     DebugTraceResult(IVTABC_FindRow, hResult);
  933.     return hResult;
  934. }
  935.  
  936. /*************************************************************************
  937.  *
  938.  -  IVTABC_Restrict
  939.  -
  940.  *
  941.  *      Should just support ANR type restrictions...
  942.  */
  943. STDMETHODIMP 
  944. IVTABC_Restrict(LPIVTABC lpIVTAbc,
  945.     LPSRestriction lpRestriction,
  946.     ULONG ulFlags)
  947. {
  948.     LPSTR szT = NULL;
  949.     LPSTR lpszTNew = NULL;
  950.     ULONG cbTB = 0;
  951.     BYTE bFilter = 0;
  952.     SCODE scode;
  953.     HRESULT hResult = hrSuccess;
  954.  
  955.     /*
  956.      *  Validate parameters
  957.      */
  958.  
  959.     /*
  960.      *  Check to see if it's large enough to hold this object
  961.      */
  962.     if (IsBadReadPtr(lpIVTAbc, sizeof(IVTABC)))
  963.     {
  964.         /*
  965.          *  Not large enough
  966.          */
  967.         hResult = ResultFromScode(E_INVALIDARG);
  968.  
  969.         goto out;
  970.     }
  971.  
  972.     /*
  973.      *  Check to see that it's the correct vtbl
  974.      */
  975.     if (lpIVTAbc->lpVtbl != &vtblIVTABC)
  976.     {
  977.         /*
  978.          *  Not my vtbl
  979.          */
  980.         hResult = ResultFromScode(E_INVALIDARG);
  981.  
  982.         goto out;
  983.     }
  984.  
  985.     /*
  986.      *  Check flags
  987.      */
  988.     if (ulFlags & ~(TBL_NOWAIT|TBL_BATCH))
  989.     {
  990.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  991.  
  992.         goto out;
  993.     }
  994.  
  995.     /*
  996.      *  I only handle ANR type restrictions
  997.      */
  998.  
  999.     /*
  1000.      *  Check to see if they're resetting the restrictions
  1001.      */
  1002.     if (!lpRestriction)
  1003.     {
  1004.         EnterCriticalSection(&lpIVTAbc->cs);
  1005.         
  1006.         if (lpIVTAbc->lpszPartialName)
  1007.             (*(lpIVTAbc->lpFreeBuff)) (lpIVTAbc->lpszPartialName);
  1008.         lpIVTAbc->lpszPartialName = NULL;
  1009.  
  1010.         FreeANRBitmaps(lpIVTAbc);
  1011.  
  1012.         LeaveCriticalSection(&lpIVTAbc->cs);
  1013.         
  1014.         return hrSuccess;
  1015.     }
  1016.  
  1017.     /*
  1018.      *  The restriction must look like:
  1019.      *
  1020.      *
  1021.      *  +--------------
  1022.      *  | RES_PROPERTY
  1023.      *  +--------------
  1024.      *  | RELOP_EQ
  1025.      *  +--------------
  1026.      *  | PR_ANR
  1027.      *  +--------------
  1028.      *  | LPSPropVal ---+
  1029.      *  +-------------- |
  1030.      *                  |   +-------------------------
  1031.      *                  +-->| PR_ANR
  1032.      *                      +-------------------------
  1033.      *                      | 0 <-- for alignment (don't care)
  1034.      *                      +-------------------------
  1035.      *                      | lpszA <-- string to ANR on
  1036.      *                      +-------------------------
  1037.      *
  1038.      *
  1039.      *
  1040.      *  If it doesn't look like this, return MAPI_E_TOO_COMPLEX.
  1041.      *
  1042.      */
  1043.  
  1044.     if (lpRestriction->rt != RES_PROPERTY)
  1045.     {
  1046.         hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
  1047.  
  1048.         goto out;
  1049.     }
  1050.  
  1051.     if (lpRestriction->res.resProperty.relop != RELOP_EQ)
  1052.     {
  1053.         hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
  1054.  
  1055.         goto out;
  1056.     }
  1057.  
  1058.     if (lpRestriction->res.resProperty.ulPropTag != PR_ANR)
  1059.     {
  1060.         hResult = ResultFromScode(MAPI_E_TOO_COMPLEX);
  1061.  
  1062.         goto out;
  1063.     }
  1064.  
  1065.     /*
  1066.      *  NULL string is not defined - it's a bad restriction
  1067.      */
  1068.     if (!lpRestriction->res.resProperty.lpProp->Value.lpszA)
  1069.     {
  1070.         hResult = ResultFromScode(E_INVALIDARG);
  1071.         
  1072.         goto out;
  1073.     }
  1074.  
  1075.  
  1076.     szT = lpRestriction->res.resProperty.lpProp->Value.lpszA;
  1077.  
  1078.     /*
  1079.      *  Skip over leading spaces
  1080.      */
  1081.  
  1082.     while (*szT == ' ')
  1083.         szT++;
  1084.  
  1085.     /*
  1086.      *  Empty string is not defined - it's a bad restriction
  1087.      */
  1088.     if (*szT == '\0')
  1089.     {
  1090.         hResult = ResultFromScode(E_INVALIDARG);
  1091.         goto out;
  1092.     }
  1093.  
  1094.  
  1095.     /*
  1096.      *  Copy the string for the partial name
  1097.      */
  1098.  
  1099.     scode = lpIVTAbc->lpAllocBuff(lstrlenA(szT) + 1, (LPVOID *) &lpszTNew);
  1100.     if (FAILED(scode))
  1101.     {
  1102.         /*
  1103.          *  Memory error
  1104.          */
  1105.  
  1106.         hResult = ResultFromScode(scode);
  1107.         goto out;
  1108.     }
  1109.     lstrcpyA(lpszTNew, szT);
  1110.  
  1111.  
  1112.     EnterCriticalSection(&lpIVTAbc->cs);
  1113.  
  1114.  
  1115.     /*
  1116.      *  Clear up any old restriction
  1117.      */
  1118.  
  1119.     if (lpIVTAbc->lpszPartialName)
  1120.         lpIVTAbc->lpFreeBuff(lpIVTAbc->lpszPartialName);
  1121.     
  1122.     lpIVTAbc->lpszPartialName = lpszTNew;
  1123.  
  1124.     FreeANRBitmaps(lpIVTAbc);
  1125.  
  1126.  
  1127.     /*
  1128.      *  Allocate enough bits for the checked&matched arrays
  1129.      */
  1130.     cbTB = (lpIVTAbc->ulMaxPos) / 8 + 1;    /* Number of bytes in both arrays */
  1131.  
  1132.     lpIVTAbc->rgChecked = lpIVTAbc->lpMalloc->lpVtbl->Alloc(
  1133.         lpIVTAbc->lpMalloc,
  1134.         cbTB);
  1135.  
  1136.     if (lpIVTAbc->rgChecked == NULL)
  1137.     {
  1138.         lpIVTAbc->lpFreeBuff(lpIVTAbc->lpszPartialName);
  1139.         lpIVTAbc->lpszPartialName = NULL;
  1140.  
  1141.         hResult = ResultFromScode(scode);
  1142.  
  1143.         LeaveCriticalSection(&lpIVTAbc->cs);
  1144.         goto out;
  1145.     }
  1146.  
  1147.     lpIVTAbc->rgMatched = lpIVTAbc->lpMalloc->lpVtbl->Alloc(
  1148.         lpIVTAbc->lpMalloc,
  1149.         cbTB);
  1150.  
  1151.     if (lpIVTAbc->rgMatched == NULL)
  1152.     {
  1153.         (*(lpIVTAbc->lpFreeBuff)) (lpIVTAbc->lpszPartialName);
  1154.         lpIVTAbc->lpszPartialName = NULL;
  1155.  
  1156.         lpIVTAbc->lpMalloc->lpVtbl->Free(lpIVTAbc->lpMalloc, lpIVTAbc->rgChecked);
  1157.         lpIVTAbc->rgChecked = NULL;
  1158.  
  1159.         hResult = ResultFromScode(scode);
  1160.  
  1161.         LeaveCriticalSection(&lpIVTAbc->cs);
  1162.         goto out;
  1163.     }
  1164.  
  1165.     /*
  1166.      *  Initialize the checked array with 0's
  1167.      */
  1168.  
  1169.     FillMemory(lpIVTAbc->rgChecked, (UINT) cbTB, 0x00);
  1170.  
  1171.     /*
  1172.      *  Initialize the matched array with 1's
  1173.      *  [we assume that if you haven't checked it, it matches]
  1174.      */
  1175.  
  1176.     FillMemory(lpIVTAbc->rgMatched, (UINT) cbTB, 0xFF);
  1177.  
  1178.     /*
  1179.      *  Fill in the end bits so we don't have to worry about them
  1180.      *  later
  1181.      */
  1182.     bFilter = (0xFF >> (lpIVTAbc->ulMaxPos % 8));
  1183.  
  1184.     /*  Checked end bits should be 1 */
  1185.     lpIVTAbc->rgChecked[cbTB - 1] = bFilter;
  1186.  
  1187.     /*  Matched end bits should be 0 */
  1188.     lpIVTAbc->rgMatched[cbTB - 1] = ~bFilter;
  1189.  
  1190.     /*
  1191.      *  Set the currenly known total number of rows
  1192.      *  that match the restriction.
  1193.      */
  1194.  
  1195.     lpIVTAbc->ulRstrDenom = lpIVTAbc->ulMaxPos;
  1196.  
  1197.     LeaveCriticalSection(&lpIVTAbc->cs);
  1198.  
  1199. out:
  1200.  
  1201.     DebugTraceResult(IVTABC_Restrict, hResult);
  1202.     return hResult;
  1203.  
  1204. }
  1205.  
  1206.  
  1207.  
  1208. /*************************************************************************
  1209.  *
  1210.  -  IVTABC_QueryRows
  1211.  -
  1212.  *  Attempts to retrieve ulRowCount rows from the .SAB file.  Even in the
  1213.  *  restricted case.
  1214.  *
  1215.  *
  1216.  */
  1217. STDMETHODIMP 
  1218. IVTABC_QueryRows(LPIVTABC lpIVTAbc,
  1219.     LONG lRowCount,
  1220.     ULONG ulFlags,
  1221.     LPSRowSet * lppRows)
  1222. {
  1223.     SCODE scode;
  1224.     HRESULT hResult = hrSuccess;
  1225.     LPSRowSet lpRowSet = NULL;
  1226.     LPSPropValue lpRow = NULL;
  1227.     int cbSizeOfRow;
  1228.     int cRows, iRow;
  1229.     int cCols;
  1230.     DWORD cbRead;
  1231.     ABCREC abcrec;
  1232.     ULONG ulOrigPosition;
  1233.  
  1234.     /*
  1235.      *  Validate parameters
  1236.      */
  1237.  
  1238.     /*
  1239.      *  Check to see if it's large enough to hold this object
  1240.      */
  1241.     if (IsBadReadPtr(lpIVTAbc, sizeof(IVTABC)))
  1242.     {
  1243.         /*
  1244.          *  Not large enough
  1245.          */
  1246.         hResult = ResultFromScode(E_INVALIDARG);
  1247.  
  1248.         DebugTraceResult(IVTABC_QueryRows, hResult);
  1249.         return hResult;
  1250.     }
  1251.  
  1252.     /*
  1253.      *  Check to see that it's the correct vtbl
  1254.      */
  1255.     if (lpIVTAbc->lpVtbl != &vtblIVTABC)
  1256.     {
  1257.         /*
  1258.          *  Not my vtbl
  1259.          */
  1260.         hResult = ResultFromScode(E_INVALIDARG);
  1261.  
  1262.         DebugTraceResult(IVTABC_QueryRows, hResult);
  1263.         return hResult;
  1264.     }
  1265.  
  1266.     /*
  1267.      *  Check the out parameter for writability
  1268.      */
  1269.     if (IsBadWritePtr(lppRows, sizeof(LPSRowSet)))
  1270.     {
  1271.         hResult = ResultFromScode(E_INVALIDARG);
  1272.  
  1273.         DebugTraceResult(IVTABC_QueryRows, hResult);
  1274.         return hResult;
  1275.     }
  1276.  
  1277.     /*
  1278.      *  Never valid to ask for 0 rows
  1279.      */
  1280.     if (!lRowCount)
  1281.     {
  1282.         hResult = ResultFromScode(E_INVALIDARG);
  1283.  
  1284.         DebugTraceResult(IVTABC_QueryRows, hResult);
  1285.         return hResult;
  1286.     }
  1287.  
  1288.     /*  //$ MM2 Hack!  Won't Read backwards for TR2 */
  1289.     if (lRowCount < 0)
  1290.     {
  1291.         hResult = ResultFromScode(E_INVALIDARG);
  1292.  
  1293.         DebugTraceResult(IVTABC_QueryRows, hResult);
  1294.         return hResult;
  1295.     }
  1296.  
  1297.     /*
  1298.      *  Check the flags
  1299.      */
  1300.     if (ulFlags & ~TBL_NOADVANCE)
  1301.     {
  1302.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  1303.  
  1304.         DebugTraceResult(IVTABC_QueryRows, hResult);
  1305.         return hResult;
  1306.     }
  1307.  
  1308.  
  1309.     EnterCriticalSection(&lpIVTAbc->cs);
  1310.  
  1311.     /*
  1312.      *  Open the file
  1313.      */
  1314.     hResult = HrOpenFile(lpIVTAbc);
  1315.     if (HR_FAILED(hResult))
  1316.     {
  1317.         goto out;
  1318.     }
  1319.  
  1320.     ulOrigPosition = lpIVTAbc->ulPosition;
  1321.  
  1322.     /*
  1323.      *  Calculate # of rows that will be read.
  1324.      */
  1325.     cRows = (int)lpIVTAbc->ulMaxPos - (int)lpIVTAbc->ulPosition;
  1326.     cRows = (cRows < (int)lRowCount ? cRows : (int)lRowCount);
  1327.  
  1328.     /*
  1329.      *  Allocate array for SRowSet
  1330.      */
  1331.  
  1332.     scode = lpIVTAbc->lpAllocBuff(sizeof(ULONG) + cRows * sizeof(SRow),
  1333.                                         (LPVOID *) &lpRowSet);
  1334.     if (FAILED(scode))
  1335.     {
  1336.         hResult = ResultFromScode(scode);
  1337.  
  1338.         goto out;
  1339.     }
  1340.  
  1341.     /*
  1342.      *  Initialize - so we can clean up later if we have to...
  1343.      */
  1344.     lpRowSet->cRows = cRows;
  1345.  
  1346.     for (iRow = 0; iRow < cRows; iRow++)
  1347.         lpRowSet->aRow[iRow].lpProps = NULL;
  1348.  
  1349.  
  1350.  
  1351.     /*
  1352.      *  Seek to correct position in file
  1353.      */
  1354.     (void) SetFilePointer(lpIVTAbc->hFile, lpIVTAbc->ulPosition * sizeof(ABCREC),
  1355.                         NULL, FILE_BEGIN);
  1356.  
  1357.     /*
  1358.      *  Read each row from the file
  1359.      */
  1360.     for (iRow = 0; iRow < cRows; iRow++)
  1361.     {
  1362.  
  1363.         /*  The only properties available are:
  1364.          *
  1365.          *  PR_DISPLAY_NAME, PR_ENTRYID, PR_ADDRTYPE, PR_EMAIL_ADDRESS,
  1366.          *  PR_OBJECT_TYPE, PR_DISPLAY_TYPE
  1367.          */
  1368.  
  1369.         /*
  1370.          *  Handle restricted lists
  1371.          */
  1372.         if (lpIVTAbc->lpszPartialName)
  1373.         {
  1374.             ULONG ulPos = lpIVTAbc->ulPosition;
  1375.  
  1376. next:
  1377.             if (ulPos == lpIVTAbc->ulMaxPos)
  1378.             {
  1379.                 break;
  1380.             }
  1381.  
  1382.             if (!FChecked(lpIVTAbc, ulPos))
  1383.             {
  1384.                 hResult = HrValidateEntry(lpIVTAbc, ulPos);
  1385.                 if (HR_FAILED(hResult))
  1386.                 {
  1387.                     goto err;
  1388.                 }
  1389.             }
  1390.  
  1391.             if (!FMatched(lpIVTAbc, ulPos))
  1392.             {
  1393.                 ulPos++;
  1394.                 goto next;
  1395.             }
  1396.  
  1397.             lpIVTAbc->ulPosition = ulPos;
  1398.             (void) SetFilePointer(lpIVTAbc->hFile, lpIVTAbc->ulPosition * sizeof(ABCREC),
  1399.                                     NULL, FILE_BEGIN);
  1400.  
  1401.         }
  1402.  
  1403.         lpIVTAbc->ulPosition++;
  1404.  
  1405.         /*
  1406.          *  Read in the record from the file
  1407.          */
  1408.         if (!ReadFile(lpIVTAbc->hFile, (LPVOID) &abcrec,
  1409.                 sizeof(ABCREC), &cbRead, NULL))
  1410.         {
  1411.             hResult = ResultFromScode(MAPI_E_DISK_ERROR);
  1412.             SetErrorIDS(lpIVTAbc, hResult, IDS_SAB_NO_READ);
  1413.  
  1414.             goto err;
  1415.         }
  1416.         /*  Second check  */
  1417.         if ((UINT) cbRead != sizeof(ABCREC))
  1418.         {
  1419.             /*
  1420.              *  Should never get here.
  1421.              */
  1422.             hResult = ResultFromScode(MAPI_E_DISK_ERROR);
  1423.             SetErrorIDS(lpIVTAbc, hResult, IDS_SAB_NO_READ);
  1424.  
  1425.             goto err;
  1426.         }
  1427.  
  1428.         /*  Allocate memory to start a row.
  1429.          */
  1430.         cbSizeOfRow = sizeof(ULONG) +
  1431.             (int)lpIVTAbc->lpPTAColSet->cValues * sizeof(SPropValue);
  1432.  
  1433.         scode = lpIVTAbc->lpAllocBuff(cbSizeOfRow, (LPVOID *) &lpRow);
  1434.         if (FAILED(scode))
  1435.         {
  1436.             hResult = ResultFromScode(scode);
  1437.  
  1438.             goto err;
  1439.         }
  1440.  
  1441.         /*
  1442.          *  Get all the data
  1443.          */
  1444.         for (cCols = 0; cCols < (int)lpIVTAbc->lpPTAColSet->cValues; cCols++)
  1445.         {
  1446.             switch (lpIVTAbc->lpPTAColSet->aulPropTag[cCols])
  1447.             {
  1448.             case PR_DISPLAY_NAME_A:
  1449.                 {
  1450.  
  1451.                     lpRow[cCols].ulPropTag = PR_DISPLAY_NAME_A;
  1452.                     scode = lpIVTAbc->lpAllocMore (lstrlenA(abcrec.rgchDisplayName) + 1,
  1453.                                                 lpRow,
  1454.                                                 (LPVOID *) &(lpRow[cCols].Value.lpszA));
  1455.  
  1456.                     if (FAILED(scode))
  1457.                     {
  1458.                         lpRow[cCols].ulPropTag = PROP_TAG(PT_ERROR,
  1459.                             PROP_ID(PR_DISPLAY_NAME_A));
  1460.                         lpRow[cCols].Value.err = scode;
  1461.                     }
  1462.                     else
  1463.                     {
  1464.  
  1465.                         lstrcpyA(lpRow[cCols].Value.lpszA,
  1466.                             abcrec.rgchDisplayName);
  1467.                     }
  1468.  
  1469.                 }
  1470.                 break;
  1471.  
  1472.             case PR_EMAIL_ADDRESS_A:
  1473.                 {
  1474.  
  1475.                     lpRow[cCols].ulPropTag = PR_EMAIL_ADDRESS_A;
  1476.                     scode = lpIVTAbc->lpAllocMore (
  1477.                                 lstrlenA(abcrec.rgchEmailAddress) + 1,
  1478.                                 lpRow, (LPVOID *) &(lpRow[cCols].Value.lpszA));
  1479.  
  1480.                     if (FAILED(scode))
  1481.                     {
  1482.                         lpRow[cCols].ulPropTag = PROP_TAG(PT_ERROR,
  1483.                             PROP_ID(PR_EMAIL_ADDRESS_A));
  1484.                         lpRow[cCols].Value.err = scode;
  1485.                     }
  1486.                     else
  1487.                     {
  1488.  
  1489.                         lstrcpyA(lpRow[cCols].Value.lpszA,
  1490.                             abcrec.rgchEmailAddress);
  1491.                     }
  1492.  
  1493.                 }
  1494.                 break;
  1495.  
  1496.             case PR_ADDRTYPE:
  1497.                 {
  1498.                     /*
  1499.                      *  AddrType is always "MSPEER" for the SAB
  1500.                      */
  1501.  
  1502.                     lpRow[cCols].ulPropTag = PR_ADDRTYPE_A;
  1503.                     scode = lpIVTAbc->lpAllocMore (lstrlenA(lpszEMT) + 1,
  1504.                                 lpRow, (LPVOID *) &(lpRow[cCols].Value.lpszA));
  1505.  
  1506.                     if (FAILED(scode))
  1507.                     {
  1508.                         lpRow[cCols].ulPropTag = PROP_TAG(PT_ERROR,
  1509.                             PROP_ID(PR_ADDRTYPE_A));
  1510.                         lpRow[cCols].Value.err = scode;
  1511.                     }
  1512.                     else
  1513.                     {
  1514.  
  1515.                         lstrcpyA(lpRow[cCols].Value.lpszA, lpszEMT);
  1516.                     }
  1517.  
  1518.                 }
  1519.                 break;
  1520.  
  1521.             case PR_ENTRYID:
  1522.                 {
  1523.                     /*
  1524.                      *  Fixed sized entryid.  Basically just the .SAB file record
  1525.                      */
  1526.                     LPUSR_ENTRYID lpUsrEid;
  1527.  
  1528.                     lpRow[cCols].ulPropTag = PR_ENTRYID;
  1529.                     scode = lpIVTAbc->lpAllocMore (sizeof(USR_ENTRYID), lpRow,
  1530.                                 (LPVOID *) &(lpRow[cCols].Value.bin.lpb));
  1531.  
  1532.                     if (FAILED(scode))
  1533.                     {
  1534.                         lpRow[cCols].ulPropTag = PROP_TAG(PT_ERROR,
  1535.                             PROP_ID(PR_ENTRYID));
  1536.                         lpRow[cCols].Value.err = scode;
  1537.                     }
  1538.                     else
  1539.                     {
  1540.                         lpUsrEid = (LPUSR_ENTRYID) lpRow[cCols].Value.bin.lpb;
  1541.  
  1542.                         ZeroMemory(lpUsrEid, sizeof(USR_ENTRYID));
  1543.  
  1544.                         /*  Size of entryid */
  1545.                         lpRow[cCols].Value.bin.cb = sizeof(USR_ENTRYID);
  1546.  
  1547.                         lpUsrEid->abFlags[0] = 0;   /*  long-term, recipient */
  1548.                         lpUsrEid->abFlags[1] = 0;
  1549.                         lpUsrEid->abFlags[2] = 0;
  1550.                         lpUsrEid->abFlags[3] = 0;
  1551.                         lpUsrEid->muid = muidABSample;
  1552.                         lpUsrEid->ulVersion = SAMP_VERSION;
  1553.                         lpUsrEid->ulType = SAMP_USER;
  1554.                         lpUsrEid->abcrec = abcrec;
  1555.                     }
  1556.  
  1557.                 }
  1558.                 break;
  1559.  
  1560.             case PR_OBJECT_TYPE:
  1561.                 {
  1562.                     /*
  1563.                      *  MailUser
  1564.                      */
  1565.  
  1566.                     lpRow[cCols].ulPropTag = PR_OBJECT_TYPE;
  1567.                     lpRow[cCols].Value.ul = MAPI_MAILUSER;
  1568.                 }
  1569.                 break;
  1570.  
  1571.             case PR_DISPLAY_TYPE:
  1572.                 {
  1573.                     /*
  1574.                      *  MailUser
  1575.                      */
  1576.  
  1577.                     lpRow[cCols].ulPropTag = PR_DISPLAY_TYPE;
  1578.                     lpRow[cCols].Value.ul = DT_MAILUSER;
  1579.  
  1580.                 }
  1581.                 break;
  1582.  
  1583.             case PR_INSTANCE_KEY:
  1584.                 {
  1585.                     LPABCRecInstance lpABCRecInstance;
  1586.                     UINT cbRecInstance;
  1587.                     /*
  1588.                      *  Instance keys are made up of:
  1589.                      *      ulRecordPosition - current position in the file
  1590.                      *      filetime         - current date and time stamp of file
  1591.                      *      lpszFileName     - current file that we're browsing
  1592.                      */
  1593.                     lpRow[cCols].ulPropTag = PR_INSTANCE_KEY;
  1594.                     
  1595.                     cbRecInstance = sizeof(ABCRecInstance)+lstrlen(lpIVTAbc->lpszFileName)+1;
  1596.                     scode = lpIVTAbc->lpAllocMore(cbRecInstance,
  1597.                                                 lpRow,
  1598.                                                 (LPVOID) &(lpRow[cCols].Value.bin.lpb));
  1599.  
  1600.                     if (FAILED(scode))
  1601.                     {
  1602.                         lpRow[cCols].ulPropTag = PROP_TAG(PT_ERROR,
  1603.                             PROP_ID(PR_INSTANCE_KEY));
  1604.                         lpRow[cCols].Value.err = scode;
  1605.                     }
  1606.                     else
  1607.                     {
  1608.                         lpABCRecInstance = (LPABCRecInstance) lpRow[cCols].Value.bin.lpb;
  1609.  
  1610.                         ZeroMemory(lpABCRecInstance, cbRecInstance);
  1611.  
  1612.                         lpRow[cCols].Value.bin.cb = (ULONG) cbRecInstance;
  1613.  
  1614.                         lpABCRecInstance->ulRecordPosition = lpIVTAbc->ulPosition;
  1615.                         lpABCRecInstance->filetime = lpIVTAbc->filetime;
  1616.                         lstrcpy(lpABCRecInstance->rgchzFileName, lpIVTAbc->lpszFileName);
  1617.  
  1618.                     }
  1619.                 }
  1620.                 break;                      
  1621.                         
  1622.  
  1623.             default:
  1624.                 {
  1625.  
  1626.                     lpRow[cCols].ulPropTag = PROP_TAG(PT_ERROR,
  1627.                         PROP_ID(lpIVTAbc->lpPTAColSet->aulPropTag[cCols]));
  1628.                     lpRow[cCols].Value.err = MAPI_E_NOT_FOUND;
  1629.                 }
  1630.                 break;
  1631.             }
  1632.         }
  1633.  
  1634.         /*  # of columns  */
  1635.         lpRowSet->aRow[iRow].cValues = lpIVTAbc->lpPTAColSet->cValues;
  1636.  
  1637.         /*  Actual row of data */
  1638.         lpRowSet->aRow[iRow].lpProps = lpRow;
  1639.  
  1640.         lpRow = NULL;
  1641.  
  1642.     }
  1643.  
  1644.     /*
  1645.      *  it's always iRow.
  1646.      */
  1647.     lpRowSet->cRows = iRow;
  1648.  
  1649.     /*
  1650.      *  Handle Seeked position stuff
  1651.      */
  1652.     if (ulFlags & TBL_NOADVANCE)
  1653.     {
  1654.         /*
  1655.          *  Set it back to it's original position
  1656.          */
  1657.         lpIVTAbc->ulPosition = ulOrigPosition;
  1658.     }
  1659.  
  1660.  
  1661.     *lppRows = lpRowSet;
  1662.  
  1663. out:
  1664.     LeaveCriticalSection(&lpIVTAbc->cs);
  1665.  
  1666.     DebugTraceResult(IVTABC_QueryRows, hResult);
  1667.     return hResult;
  1668.  
  1669. err:
  1670.     /*
  1671.      *  Clean up memory...
  1672.      */
  1673.  
  1674.     /*  Free the row  */
  1675.     lpIVTAbc->lpFreeBuff(lpRow);
  1676.  
  1677.     /*  Clean up the rest of the rows  */
  1678.     FreeProws(lpRowSet);
  1679.  
  1680.     *lppRows = NULL;
  1681.  
  1682.     goto out;
  1683.  
  1684. }
  1685.  
  1686.