Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1738 lines
41 KiB

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