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

Windows编程

开发平台:

Visual C++

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