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.

848 lines
24 KiB

  1. /*************************************************************************
  2. * @doc SHROOM EXTERNAL API *
  3. * *
  4. * WWIMP.CPP *
  5. * *
  6. * Copyright (C) Microsoft Corporation 1997 *
  7. * All Rights reserved. *
  8. * *
  9. * This file contains CITWordWheelLocal, the local implementation *
  10. * of IITWordWheel *
  11. * *
  12. **************************************************************************
  13. * *
  14. * Written By : Erin Foxford *
  15. * Current Owner: erinfox *
  16. * *
  17. *
  18. * TODO TODO TODO: Replace the blind use of critical sections with a
  19. * better way of ensuring thread-safeness while preserving performance.
  20. * But for now, in the interest of coding time, we just make sure the
  21. * code is thread-safe.
  22. *
  23. **************************************************************************/
  24. #include <mvopsys.h>
  25. #ifdef _DEBUG
  26. static char s_aszModule[] = __FILE__; /* For error report */
  27. #endif
  28. #include <atlinc.h> // includes for ATL.
  29. // MediaView (InfoTech) includes
  30. #include <groups.h>
  31. #include <wwheel.h>
  32. #include "itcat.h" // catalog
  33. #include "itcc.h" // needed for STDPROP_SORTKEY def.
  34. #include "ITPropl.h" // property list
  35. #include "itrs.h" // result set
  36. #include "itquery.h" // query and index
  37. #include <ccfiles.h>
  38. #include "ITDB.h"
  39. #include "DBImp.h"
  40. #include "itww.h"
  41. #include "WWImp.h"
  42. #include "itgroup.h"
  43. /********************************************************************
  44. * @method STDMETHODIMP | IITWordWheel | Open |
  45. * Opens a word wheel
  46. * @parm IITDatabase* | lpITDB | Pointer to database object
  47. * @parm LPCWSTR | lpszMoniker | Name of word wheel
  48. * @parm DWORD | dwFlags | One or more of the following values:
  49. * @flag ITWW_OPEN_CONNECT | If the wordwheel resides on a remote machine,
  50. * connect to the machine during this call to retrieve initialization data. Otherwise
  51. * the connection is delayed until the first API call which requires this data.
  52. *
  53. * @rvalue E_INVALIDARG | IITDatabase* or lpszMoniker was NULL
  54. * @rvalue E_ALREADYOPEN | Word wheel is already open
  55. * @rvalue E_GETLASTERROR | An I/O or transport operation failed. Call the Win32
  56. * GetLastError function to retrieve the error code.
  57. * @rvalue STG_E_* | Any of the IStorage errors that could while opening a storage
  58. * @rvalue S_OK | The word wheel was successfully opened
  59. *
  60. ********************************************************************/
  61. STDMETHODIMP CITWordWheelLocal::Open(IITDatabase* lpITDB, LPCWSTR lpszMoniker, DWORD dwFlags)
  62. {
  63. HRESULT hr;
  64. LPWSTR szStorageName;
  65. if (NULL == lpITDB || NULL == lpszMoniker)
  66. return E_POINTER;
  67. // TODO: Report error or close word wheel if it's already open ?
  68. if (m_hWheel || m_pSubStorage)
  69. return E_ALREADYOPEN;
  70. m_cs.Lock();
  71. // Open substorage and pass to word wheel
  72. szStorageName = new WCHAR [CCH_MAX_OBJ_NAME + CCH_MAX_OBJ_STORAGE + 1];
  73. WSTRCPY (szStorageName, SZ_WW_STORAGE);
  74. if (WSTRLEN (lpszMoniker) <= CCH_MAX_OBJ_NAME)
  75. WSTRCAT (szStorageName, lpszMoniker);
  76. else
  77. {
  78. MEMCPY (szStorageName, lpszMoniker, CCH_MAX_OBJ_NAME * sizeof (WCHAR));
  79. szStorageName [CCH_MAX_OBJ_NAME + CCH_MAX_OBJ_STORAGE] = (WCHAR)'\0';
  80. }
  81. if (SUCCEEDED(hr = lpITDB->GetObjectPersistence(szStorageName,
  82. IITDB_OBJINST_NULL,
  83. (LPVOID *) &m_pSubStorage, FALSE)))
  84. {
  85. // Open word wheel
  86. m_hWheel = WordWheelOpen(lpITDB, m_pSubStorage, &hr);
  87. }
  88. delete szStorageName;
  89. if (m_hWheel == NULL || FAILED(hr))
  90. {
  91. exit0:
  92. if (m_pSubStorage != NULL)
  93. {
  94. m_pSubStorage->Release();
  95. m_pSubStorage = NULL;
  96. }
  97. m_cs.Unlock();
  98. return hr;
  99. }
  100. // NOTE:
  101. // If the client wants to load a group into the word wheel for filtering,
  102. // s/he must first call the "Open" method of ITWordWheel, then create
  103. // a group (these two steps may be interchanged), then call the "SetGroup"
  104. // method of ITWordWheel.
  105. // Store count
  106. m_cEntries = m_cMaxEntries = WordWheelLength(m_hWheel, &hr);
  107. // Open catalog object - we only need one instance
  108. hr = CoCreateInstance(CLSID_IITCatalogLocal, NULL, CLSCTX_INPROC_SERVER, IID_IITCatalog,
  109. (VOID **) &m_pCatalog);
  110. if (FAILED(hr))
  111. goto exit0;
  112. // If we can't open the catalog hat's OK because we can run
  113. // without it.
  114. if (FAILED(m_pCatalog->Open(lpITDB)))
  115. {
  116. m_pCatalog->Release();
  117. m_pCatalog = NULL;
  118. }
  119. m_cs.Unlock();
  120. return S_OK;
  121. }
  122. /********************************************************************
  123. * @method STDMETHODIMP | IITWordWheel | Close |
  124. * Closes a word wheel
  125. *
  126. * @rvalue S_OK | The word wheel was successfully closed
  127. *
  128. ********************************************************************/
  129. STDMETHODIMP CITWordWheelLocal::Close(void)
  130. {
  131. m_cs.Lock();
  132. if (m_hWheel)
  133. {
  134. WordWheelClose(m_hWheel);
  135. m_hWheel = NULL;
  136. }
  137. else
  138. return E_NOTINIT;
  139. if (m_pSubStorage)
  140. {
  141. m_pSubStorage->Release();
  142. m_pSubStorage = NULL;
  143. }
  144. if (m_pCatalog)
  145. {
  146. m_pCatalog->Close();
  147. m_pCatalog->Release();
  148. m_pCatalog = NULL;
  149. }
  150. if (m_hScratchBuffer)
  151. {
  152. _GLOBALFREE(m_hScratchBuffer);
  153. m_hScratchBuffer = NULL;
  154. }
  155. m_cbScratchBuffer = 0;
  156. if (m_pIITGroup != NULL)
  157. {
  158. m_pIITGroup->Release();
  159. m_pIITGroup = NULL;
  160. }
  161. m_cs.Unlock();
  162. return S_OK;
  163. }
  164. /********************************************************************
  165. * @method STDMETHODIMP | IITWordWheel | GetLocaleInfo |
  166. * Gets locale info that the word wheel was built with.
  167. * @parm DWORD* | pdwCodePageID | On exit, pointer to code page ID.
  168. * @parm LCID* | plcid | On exit, pointer to locale ID.
  169. *
  170. * @rvalue S_OK | The locale info was successfully retrieved.
  171. *
  172. ********************************************************************/
  173. STDMETHODIMP CITWordWheelLocal::GetLocaleInfo(DWORD *pdwCodePageID, LCID *plcid)
  174. {
  175. HRESULT hr = S_OK;
  176. PWHEEL pwheel = NULL;
  177. if (pdwCodePageID == NULL || plcid == NULL)
  178. return (SetErrReturn(E_POINTER));
  179. if (m_hWheel == NULL)
  180. return (E_NOTOPEN);
  181. m_cs.Lock();
  182. // validate the parameters and lock down the structure
  183. if ((pwheel = (PWHEEL)_GLOBALLOCK(m_hWheel)) != NULL &&
  184. PWHEEL_OK(pwheel))
  185. {
  186. BTREE_PARAMS btp;
  187. GetBtreeParams(pwheel->pInfo->hbt, &btp);
  188. *pdwCodePageID = btp.dwCodePageID;
  189. *plcid = btp.lcid;
  190. }
  191. else
  192. hr = E_UNEXPECTED;
  193. if (pwheel != NULL)
  194. _GLOBALUNLOCK(m_hWheel);
  195. m_cs.Unlock();
  196. return (hr);
  197. }
  198. /********************************************************************
  199. * @method STDMETHODIMP | IITWordWheel | GetSorterInstance |
  200. * Get the ID of the sorter instance being used by the
  201. * word wheel
  202. *
  203. * @parm DWORD* | pdwObjInstance | Pointer to sorter instance ID
  204. *
  205. * @rvalue E_NOTOPEN | The word wheel has not been opened
  206. * @rvalue E_POINTER | pdwObjInstance was an invalid pointer
  207. * @rvalue S_OK | The sorter instance ID was successfully obtained
  208. *
  209. ********************************************************************/
  210. STDMETHODIMP CITWordWheelLocal::GetSorterInstance(DWORD *pdwObjInstance)
  211. {
  212. HRESULT hr = S_OK;
  213. PWHEEL pwheel = NULL;
  214. if (m_hWheel == NULL)
  215. return (E_NOTOPEN);
  216. if (pdwObjInstance == NULL)
  217. return (E_POINTER);
  218. m_cs.Lock();
  219. // validate the parameters and lock down the structure
  220. if ((pwheel = (PWHEEL)_GLOBALLOCK(m_hWheel)) != NULL &&
  221. PWHEEL_OK(pwheel))
  222. {
  223. BTREE_PARAMS btp;
  224. GetBtreeParams(pwheel->pInfo->hbt, &btp);
  225. *pdwObjInstance =
  226. (btp.rgchFormat[0] == KT_EXTSORT ? btp.dwExtSortInstID :
  227. IITDB_OBJINST_NULL);
  228. }
  229. else
  230. hr = E_UNEXPECTED;
  231. if (pwheel != NULL)
  232. _GLOBALUNLOCK(m_hWheel);
  233. m_cs.Unlock();
  234. return (hr);
  235. }
  236. /********************************************************************
  237. * @method STDMETHODIMP | IITWordWheel | Count |
  238. * Returns number of entries in word wheel through pcEntries
  239. *
  240. * @parm LONG* | pcEntries | Number of entries in word wheel
  241. *
  242. * @rvalue E_NOTOPEN | The word wheel has not been opened
  243. * @rvalue E_POINTER | pcEntries was an invalid pointer
  244. * @rvalue S_OK | The count was successfully returned
  245. *
  246. ********************************************************************/
  247. STDMETHODIMP CITWordWheelLocal::Count(LONG *pcEntries)
  248. {
  249. if (NULL == m_hWheel)
  250. return E_NOTOPEN;
  251. if (NULL == pcEntries)
  252. return E_POINTER;
  253. *pcEntries = m_cEntries;
  254. return S_OK;
  255. }
  256. /********************************************************************
  257. * @method STDMETHODIMP | IITWordWheel | Lookup |
  258. * Looks up an entry and returns contents in a buffer
  259. *
  260. * @parm LONG | lEntry | Entry to look up
  261. * @parm LPVOID | lpvKeyBuf | Buffer to return entry
  262. * @parm DWORD | cbKeyBuf | Buffer size in number of bytes
  263. *
  264. * @rvalue E_OUTOFRANGE | Entry number is out of range
  265. * @rvalue S_OK | The word wheel entry was successfully returned
  266. *
  267. ********************************************************************/
  268. STDMETHODIMP CITWordWheelLocal::Lookup(LONG lEntry, LPVOID lpvKeyBuf, DWORD cbKeyBuf)
  269. {
  270. if (NULL == m_hWheel)
  271. return E_NOTOPEN;
  272. if (NULL == lpvKeyBuf)
  273. return E_POINTER;
  274. m_cs.Lock();
  275. HRESULT hr = WordWheelLookup(m_hWheel, lEntry, lpvKeyBuf, cbKeyBuf);
  276. m_cs.Unlock();
  277. return hr;
  278. }
  279. /********************************************************************
  280. * @method STDMETHODIMP | IITWordWheel | Lookup |
  281. * Looks up an entry and returns contents as a result set
  282. *
  283. * @parm LONG | lEntry | Entry to look up
  284. * @parm IITResultList* | lpITResult | Pointer to result set to fill
  285. * @parm LONG | cEntries | Number of entries to fill result set
  286. *
  287. * @rvalue E_INVALIDARG | Invalid argument was passed (cEntries <lt>= 0 or lpITResult
  288. * is NULL)
  289. * @rvalue E_OUTOFRANGE | The entry does not exist in the word wheel
  290. * @rvalue S_OK | The word wheel entry was successfully returned
  291. *
  292. ********************************************************************/
  293. STDMETHODIMP CITWordWheelLocal::Lookup(LONG lEntry, IITResultSet* lpITResult, LONG cEntries)
  294. {
  295. PWHEEL pWheel = NULL; // pointer to locked-down structure
  296. PWHEELINFO pInfo = NULL;
  297. BYTE Key[ITWW_CBKEY_MAX];
  298. BYTE DataBuffer[8];
  299. DWORD dwOffset; // Offset into data file
  300. DWORD cbRead;
  301. LPBYTE pPropBuffer = NULL;
  302. LARGE_INTEGER dlibMove; // For seeking
  303. ULARGE_INTEGER libNewPos;
  304. IITSortKey *pITSortKey = NULL;
  305. LONG iRow;
  306. LONG iColumn;
  307. LONG iEntry; // Loop index
  308. LONG lMaxEntry;
  309. HRESULT hr;
  310. if (NULL == m_hWheel)
  311. return E_NOTOPEN;
  312. if (NULL == lpITResult)
  313. return E_POINTER;
  314. m_cs.Lock();
  315. // validate the parameters and lock down the structure
  316. if ((pWheel = (PWHEEL)_GLOBALLOCK(m_hWheel))==NULL ||
  317. !PWHEEL_OK(pWheel))
  318. {
  319. hr = E_INVALIDSTATE;
  320. warning_abort;
  321. }
  322. pInfo = pWheel->pInfo;
  323. // if result set is empty, add columns based on header
  324. lpITResult->GetColumnCount(iColumn);
  325. if (0 == iColumn)
  326. {
  327. lpITResult->Add(STDPROP_SORTKEY, (LPWSTR) NULL, PRIORITY_NORMAL);
  328. if (pInfo->pKeyHdr)
  329. lpITResult->Add(pInfo->pKeyHdr);
  330. }
  331. // Check for a btree key type that the word wheel supports and set
  332. // pITSortKey.
  333. if (FAILED(hr = CheckWordWheelKeyType(pInfo->hbt, &pITSortKey)))
  334. assert_abort;
  335. lMaxEntry = lEntry + cEntries;
  336. for (iEntry = lEntry; iEntry < lMaxEntry ; iEntry++)
  337. {
  338. DWORD cbKeyData = 0L; // Amount of data in key property
  339. // exceeded entries in word wheel
  340. if (iEntry >= m_cEntries)
  341. break;
  342. // If there's a filter, let's get the proper entry in the WW.
  343. if (!m_pIITGroup)
  344. lEntry = iEntry;
  345. else
  346. {
  347. hr = m_pIITGroup->FindTopicNum((DWORD)iEntry, (DWORD*)(&lEntry));
  348. if (FAILED(hr))
  349. goto cleanup;
  350. else if (S_FALSE == hr) // not found
  351. break;
  352. }
  353. // lookup the entry in the map file
  354. hr = RcKeyFromIndexHbt(pInfo->hbt, pInfo->hmapbt,
  355. (KEY)Key, ITWW_CBKEY_MAX, lEntry);
  356. if (FAILED(hr))
  357. goto cleanup;
  358. // lookup data associated w/ key
  359. hr = RcLookupByKey(pInfo->hbt, (KEY)Key, NULL, DataBuffer);
  360. if (FAILED(hr))
  361. goto cleanup;
  362. dwOffset = *(LPDWORD) &DataBuffer[4];
  363. // get data from data file
  364. // seek to get offset into data file where key
  365. // properties reside
  366. dlibMove.QuadPart = dwOffset;
  367. hr = (pInfo->hf)->Seek(dlibMove, STREAM_SEEK_SET, &libNewPos);
  368. if (FAILED(hr))
  369. goto cleanup;
  370. // read in amount of key data
  371. hr = (pInfo->hf)->Read(&cbKeyData, sizeof(DWORD), &cbRead);
  372. if (FAILED(hr))
  373. goto cleanup;
  374. // get current last row so we can set the data there
  375. lpITResult->GetRowCount(iRow);
  376. // Set key. Note that GetColumnFromPropID might return error
  377. // if caller didn't specify STDPROP_SORTKEY.
  378. if (SUCCEEDED(hr = lpITResult->GetColumnFromPropID(STDPROP_SORTKEY, iColumn)))
  379. lpITResult->Set(iRow, iColumn, (LPVOID) Key,
  380. CbKeyWordWheel((LPVOID) Key, pITSortKey));
  381. if (cbKeyData)
  382. {
  383. // read the data
  384. hr = ReallocBufferHmem
  385. (&m_hScratchBuffer, &m_cbScratchBuffer, cbKeyData);
  386. if (FAILED(hr))
  387. goto cleanup;
  388. if(NULL == (pPropBuffer = (BYTE *)_GLOBALLOCK(m_hScratchBuffer)))
  389. {
  390. hr = E_OUTOFMEMORY;
  391. goto cleanup;
  392. }
  393. hr = (pInfo->hf)->Read(pPropBuffer, cbKeyData, &cbRead);
  394. // Even if Set(iRow...) fails, set other properties, if there are any
  395. // TODO: This function may need optimization
  396. lpITResult->Set(iRow, pInfo->pKeyHdr, pPropBuffer);
  397. _GLOBALUNLOCK(m_hScratchBuffer);
  398. }
  399. }
  400. cleanup:
  401. if (NULL != pWheel)
  402. _GLOBALUNLOCK(m_hWheel);
  403. if (pITSortKey != NULL)
  404. pITSortKey->Release();
  405. m_cs.Unlock();
  406. return hr;
  407. }
  408. /********************************************************************
  409. * @method STDMETHODIMP | IITWordWheel | Lookup |
  410. * Returns word wheel entry closest to given prefix
  411. *
  412. * @parm LPCVOID | lpcvPrefix | Prefix to look up
  413. * @parm BOOL | fExactMatch | TRUE if prefix must have exact match; FALSE otherwise
  414. * @parm LONG* | plEntry | Entry into word wheel with closest match
  415. *
  416. * @rvalue E_NOTEXIST | The prefix doesn't exist; returned when fExactMatch is set
  417. * to TRUE and there is no match.
  418. * @rvalue E_POINTER | Either lpcvPrefix or pcEntries was an invalid pointer
  419. * @rvalue S_OK | The entry was successfully returned
  420. *
  421. ********************************************************************/
  422. STDMETHODIMP CITWordWheelLocal::Lookup(LPCVOID lpcvPrefix, BOOL fExactMatch,
  423. LONG *plEntry)
  424. {
  425. HRESULT hr;
  426. if (NULL == m_hWheel)
  427. return E_NOTOPEN;
  428. if (NULL == lpcvPrefix || NULL == plEntry)
  429. return E_POINTER;
  430. m_cs.Lock();
  431. *plEntry = WordWheelPrefix(m_hWheel, lpcvPrefix, fExactMatch, &hr);
  432. m_cs.Unlock();
  433. return hr;
  434. }
  435. /********************************************************************
  436. * @method STDMETHODIMP | IITWordWheel | GetDataCount |
  437. * Returns number of occurrences associated with given word wheel entry
  438. *
  439. * @parm LONG | lEntry | Entry into word wheel
  440. * @parm DWORD* | pdwCount | Number of occurrences
  441. *
  442. * @rvalue E_NOTEXIST | Entry number is not in the valid range
  443. * @rvalue S_OK | The entry was successfully returned
  444. *
  445. ********************************************************************/
  446. STDMETHODIMP CITWordWheelLocal::GetDataCount(LONG lEntry, DWORD *pdwCount)
  447. {
  448. HRESULT hr = S_OK;
  449. BYTE Key[ITWW_CBKEY_MAX];
  450. BYTE DataBuffer[8];
  451. if (NULL == m_hWheel)
  452. return E_NOTOPEN;
  453. if (NULL == pdwCount)
  454. return E_POINTER;
  455. m_cs.Lock();
  456. PWHEEL pWheel = (PWHEEL)_GLOBALLOCK(m_hWheel);
  457. PWHEELINFO pInfo = pWheel->pInfo;
  458. if (pWheel->pIITGroup)
  459. {
  460. hr = (pWheel->pIITGroup)->FindTopicNum((DWORD)lEntry, (DWORD*)(&lEntry));
  461. if (FAILED(hr))
  462. goto cleanup;
  463. }
  464. // lookup the entry in the map file
  465. hr = RcKeyFromIndexHbt(pInfo->hbt, pInfo->hmapbt,
  466. (KEY)Key, ITWW_CBKEY_MAX, lEntry);
  467. if (FAILED(hr))
  468. goto cleanup;
  469. // lookup some data (count) associated w/ key
  470. hr = RcLookupByKey(pInfo->hbt, (KEY)Key, NULL, DataBuffer);
  471. if (FAILED(hr))
  472. goto cleanup;
  473. *pdwCount = *(LPDWORD) DataBuffer;
  474. cleanup:
  475. if (NULL != pWheel)
  476. _GLOBALUNLOCK(m_hWheel);
  477. m_cs.Unlock();
  478. return hr;
  479. }
  480. /********************************************************************
  481. * @method STDMETHODIMP | IITWordWheel | GetData |
  482. * Fills given result set with rows corresponding to user data
  483. *
  484. * @parm LONG | lEntry | Entry
  485. * @parm IITResultSet* | lpITResult | Pointer to result set object to fill
  486. *
  487. * @rvalue E_INVALIDARG | Result set pointer cannot be NULL
  488. * @rvalue E_NOTEXIST | Entry number is not in the valid range
  489. * @rvalue E_OUTOFMEMORY | Memory allocation failed
  490. * @rvalue S_OK | The entry was successfully returned
  491. *
  492. ********************************************************************/
  493. STDMETHODIMP CITWordWheelLocal::GetData(LONG lEntry, IITResultSet* lpITResult)
  494. {
  495. BYTE Key[ITWW_CBKEY_MAX];
  496. BYTE DataBuffer[8];
  497. DWORD dwCount; // Number of occurrences
  498. DWORD dwOffset; // Offset into data file
  499. LARGE_INTEGER dlibMove; // For seeking
  500. ULARGE_INTEGER libNewPos;
  501. DWORD cbPropSize;
  502. LPBYTE pPropBuffer = NULL;
  503. DWORD cbRead;
  504. LONG iColumn;
  505. DWORD iRow; // Loop index
  506. HRESULT hr = S_OK;
  507. if (NULL == m_hWheel)
  508. return E_NOTOPEN;
  509. if (NULL == lpITResult)
  510. return E_POINTER;
  511. m_cs.Lock();
  512. PWHEEL pWheel = (PWHEEL)_GLOBALLOCK(m_hWheel);
  513. PWHEELINFO pInfo = pWheel->pInfo;
  514. // if result set is empty, add columns based on header
  515. // also add columns passed on catalog header
  516. lpITResult->GetColumnCount(iColumn);
  517. if (0 == iColumn)
  518. {
  519. lpITResult->Add(pInfo->pOccHdr);
  520. if (m_pCatalog)
  521. m_pCatalog->GetColumns(lpITResult);
  522. }
  523. if (pWheel->pIITGroup)
  524. {
  525. hr = (pWheel->pIITGroup)->FindTopicNum((DWORD)lEntry, (DWORD*)(&lEntry));
  526. if (FAILED(hr))
  527. goto cleanup;
  528. }
  529. // lookup the entry in the map file
  530. hr = RcKeyFromIndexHbt(pInfo->hbt, pInfo->hmapbt,
  531. (KEY)Key, ITWW_CBKEY_MAX, lEntry);
  532. if (FAILED(hr))
  533. goto cleanup;
  534. // lookup some data (count and offset into data file) associated w/ key
  535. hr = RcLookupByKey(pInfo->hbt, (KEY)Key, NULL, DataBuffer);
  536. if (FAILED(hr))
  537. goto cleanup;
  538. dwCount = *(LPDWORD) DataBuffer;
  539. dwOffset = *(LPDWORD) &DataBuffer[4];
  540. // get data from data file
  541. // seek to get offset into data file where key
  542. // properties reside and find out how much to skip
  543. dlibMove.QuadPart = dwOffset;
  544. hr = (pInfo->hf)->Seek(dlibMove, STREAM_SEEK_SET, &libNewPos);
  545. if (FAILED(hr))
  546. goto cleanup;
  547. DWORD dwDataOffset;
  548. hr = (pInfo->hf)->Read(&dwDataOffset, sizeof(DWORD), &cbRead);
  549. if (FAILED(hr))
  550. goto cleanup;
  551. // Seek to where data properties start
  552. dlibMove.QuadPart = dwDataOffset;
  553. hr = (pInfo->hf)->Seek(dlibMove, STREAM_SEEK_CUR, &libNewPos);
  554. if (FAILED(hr))
  555. goto cleanup;
  556. // Loop over all properties - get size, then read in property info into
  557. // memory block
  558. for (iRow = 0; iRow < dwCount; iRow++)
  559. {
  560. hr = (pInfo->hf)->Read(&cbPropSize, sizeof(DWORD), &cbRead);
  561. if (FAILED(hr))
  562. goto cleanup;
  563. hr = ReallocBufferHmem
  564. (&m_hScratchBuffer, &m_cbScratchBuffer, cbPropSize);
  565. if (FAILED(hr))
  566. goto cleanup;
  567. if(NULL == (pPropBuffer = (BYTE *)_GLOBALLOCK(m_hScratchBuffer)))
  568. {
  569. hr = E_OUTOFMEMORY;
  570. goto cleanup;
  571. }
  572. hr = (pInfo->hf)->Read(pPropBuffer, cbPropSize, &cbRead);
  573. if(SUCCEEDED(hr))
  574. // pass header and data to append to result set
  575. // TODO: This function may need optimization
  576. hr = lpITResult->Append(pInfo->pOccHdr, pPropBuffer);
  577. _GLOBALUNLOCK(m_hScratchBuffer);
  578. if (FAILED(hr))
  579. goto cleanup;
  580. }
  581. // Then fill result set w/ any properties that might be in catalog
  582. if (m_pCatalog)
  583. hr = m_pCatalog->Lookup(lpITResult);
  584. // if (S_FALSE == hr)
  585. hr = S_OK; // don't report S_FALSE
  586. cleanup:
  587. if (NULL != pWheel)
  588. _GLOBALUNLOCK(m_hWheel);
  589. m_cs.Unlock();
  590. return hr;
  591. }
  592. /********************************************************************
  593. * @method STDMETHODIMP | IITWordWheel | GetDataColumns |
  594. * Adds columns to given result set for all data properties
  595. *
  596. * @parm IITResultSet* | pRS | Pointer to result set
  597. *
  598. * @rvalue S_OK | The columns were successfully added
  599. *
  600. ********************************************************************/
  601. STDMETHODIMP CITWordWheelLocal::GetDataColumns(IITResultSet* pRS)
  602. {
  603. PWHEEL pWheel = (PWHEEL)_GLOBALLOCK(m_hWheel);
  604. PWHEELINFO pInfo = pWheel->pInfo;
  605. if (pRS == NULL)
  606. return E_POINTER;
  607. pRS->Add(pInfo->pOccHdr);
  608. if (NULL != pWheel)
  609. _GLOBALUNLOCK(m_hWheel);
  610. return S_OK;
  611. }
  612. /********************************************************************
  613. * @method STDMETHODIMP | IITWordWheel | SetGroup |
  614. * Associates a group with a word wheel, used for filtering.
  615. *
  616. * @parm IITGroup* | pIITGroup | pointer to a pre-loaded group interface
  617. *
  618. * @rvalue S_OK | interface pointer not NULL--successfully assigned
  619. * @rvalue E_INVALIDARG | received a NULL pointer for the interface
  620. * @rvalue E_NOTOPEN | the word wheel was not found to be open
  621. * @rvalue E_OUTOFMEMORY | unable to lock the wordwheel's memory
  622. * @rvalue E_BADFILTERSIZE | the filter group and wordwheel have different sizes
  623. *
  624. * @comm This method does not verify that the group behind the
  625. * interface has been loaded, or that the group is not empty.
  626. * If the client assigns the group interface pointer any random
  627. * positive value other than zero, without properly instantiating
  628. * the group object, this method returns S_OK.
  629. ********************************************************************/
  630. STDMETHODIMP CITWordWheelLocal::SetGroup(IITGroup* pIITGroup)
  631. {
  632. if (NULL == m_hWheel)
  633. return E_NOTOPEN;
  634. m_cs.Lock();
  635. PWHEEL pWheel;
  636. if (NULL == (pWheel = (PWHEEL)_GLOBALLOCK(m_hWheel)))
  637. {
  638. m_cs.Unlock();
  639. return E_OUTOFMEMORY;
  640. }
  641. // NULL is a valid argument--client is attempting to free the group
  642. if (pIITGroup)
  643. {
  644. // We need to access the group's maxItemAllGroup and lcItem fields.
  645. // We can make two function calls, or locally store the output of a single call.
  646. _LPGROUP localImage = (_LPGROUP)(pIITGroup->GetLocalImageOfGroup());
  647. if ((DWORD)(m_cMaxEntries) != localImage->maxItemAllGroup)
  648. {
  649. _GLOBALUNLOCK(m_hWheel);
  650. m_cs.Unlock();
  651. return E_BADFILTERSIZE;
  652. }
  653. pWheel->lNumEntries = m_cEntries = (LONG)(localImage->lcItem);
  654. }
  655. else
  656. {
  657. pWheel->lNumEntries = m_cEntries = m_cMaxEntries;
  658. }
  659. if (pIITGroup)
  660. pIITGroup->AddRef();
  661. if (m_pIITGroup != NULL)
  662. m_pIITGroup->Release();
  663. pWheel->pIITGroup = m_pIITGroup = pIITGroup;
  664. _GLOBALUNLOCK(m_hWheel);
  665. m_cs.Unlock();
  666. return S_OK;
  667. }
  668. /********************************************************************
  669. * @method STDMETHODIMP | IITWordWheel | GetGroup |
  670. * Retrieves the group associated with the word wheel.
  671. *
  672. * @parm IITGroup** | ppIITGroup | (out) Pointer to the group interface.
  673. *
  674. * @rvalue S_OK | private member variable m_pIITGroup != NULL
  675. * @rvalue E_NOTINIT | private member variable m_pIITGroup == NULL
  676. * @rvalue E_BADPARAM | ppIITGroup was NULL
  677. ********************************************************************/
  678. STDMETHODIMP CITWordWheelLocal::GetGroup(IITGroup** ppiitGroup)
  679. {
  680. if (NULL == ppiitGroup)
  681. return E_POINTER;
  682. if (m_pIITGroup == NULL)
  683. return E_NOTINIT;
  684. (*ppiitGroup = m_pIITGroup)->AddRef();
  685. return S_OK;
  686. }