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